Project
Loading...
Searching...
No Matches
test_ASoA.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#include <cstdio>
13#include "Framework/ASoA.h"
18#include "gandiva/tree_expr_builder.h"
19#include "arrow/status.h"
20#include "gandiva/filter.h"
21#include <catch_amalgamated.hpp>
22#include <arrow/util/key_value_metadata.h>
23
24using namespace o2::framework;
25using namespace arrow;
26using namespace o2::soa;
27
28namespace o2::aod
29{
30namespace test
31{
36DECLARE_SOA_DYNAMIC_COLUMN(Sum, sum, [](int x, int y) { return x + y; });
37DECLARE_SOA_EXPRESSION_COLUMN(ESum, esum, int, test::x + test::y);
38} // namespace test
39
40DECLARE_SOA_TABLE(Points, "TEST", "POINTS", test::X, test::Y);
41DECLARE_SOA_TABLE(Points3Ds, "TEST", "PTS3D", o2::soa::Index<>, test::X, test::Y, test::Z);
42
43DECLARE_SOA_TABLE_VERSIONED(Points3DMk1s, "TEST", "PTS3D", 1, o2::soa::Index<>, o2::soa::Marker<1>, test::X, test::Y, test::Z);
44DECLARE_SOA_TABLE_VERSIONED(Points3DMk2s, "TEST", "PTS3D", 2, o2::soa::Index<>, o2::soa::Marker<2>, test::X, test::Y, test::Z);
45DECLARE_SOA_TABLE_VERSIONED(Points3DMk3s, "TEST", "PTS3D", 3, o2::soa::Index<>, o2::soa::Marker<3>, test::X, test::Y, test::Z);
46
47namespace test
48{
49DECLARE_SOA_COLUMN_FULL(SomeBool, someBool, bool, "someBool");
50DECLARE_SOA_COLUMN_FULL(Color, color, int32_t, "color");
51} // namespace test
52
53DECLARE_SOA_TABLE(Infos, "TEST", "INFOS", test::Color, test::SomeBool);
54
55namespace test
56{
59DECLARE_SOA_INDEX_COLUMN_FULL(PointA, pointA, int, Points, "_A");
60DECLARE_SOA_INDEX_COLUMN_FULL(PointB, pointB, int, Points, "_B");
61DECLARE_SOA_COLUMN_FULL(Thickness, thickness, int, "thickness");
62} // namespace test
63
64DECLARE_SOA_TABLE(Segments, "TEST", "SEGMENTS", test::N, test::PointAId, test::PointBId, test::InfoId);
65DECLARE_SOA_TABLE(SegmentsExtras, "TEST", "SEGMENTSPLUS", test::Thickness);
66
67namespace test
68{
69DECLARE_SOA_COLUMN(L1, l1, std::vector<float>);
70DECLARE_SOA_COLUMN(L2, l2, std::vector<int>);
71} // namespace test
72
73DECLARE_SOA_TABLE(Lists, "TEST", "LISTS", o2::soa::Index<>, test::L1, test::L2);
74} // namespace o2::aod
75
76TEST_CASE("TestMarkers")
77{
78 TableBuilder b1;
79 auto pwriter = b1.cursor<o2::aod::Points3Ds>();
80 for (auto i = 0; i < 20; ++i) {
81 pwriter(0, -1 * i, (int)(i / 2), 2 * i);
82 }
83 auto t1 = b1.finalize();
84
85 auto pt = o2::aod::Points3Ds{t1};
86 auto pt1 = o2::aod::Points3DMk1s{t1};
87 auto pt2 = o2::aod::Points3DMk2s{t1};
88 auto pt3 = o2::aod::Points3DMk3s{t1};
89 REQUIRE(pt1.begin().mark() == (size_t)1);
90 REQUIRE(pt2.begin().mark() == (size_t)2);
91 REQUIRE(pt3.begin().mark() == (size_t)3);
92}
93
94TEST_CASE("TestTableIteration")
95{
96 TableBuilder builder;
97 auto rowWriter = builder.persist<int32_t, int32_t>({"fX", "fY"});
98 rowWriter(0, 0, 0);
99 rowWriter(0, 0, 1);
100 rowWriter(0, 0, 2);
101 rowWriter(0, 0, 3);
102 rowWriter(0, 1, 4);
103 rowWriter(0, 1, 5);
104 rowWriter(0, 1, 6);
105 rowWriter(0, 1, 7);
106 auto table = builder.finalize();
107
108 auto i = ColumnIterator<int32_t>(table->column(0).get());
109 int64_t pos = 0;
110 uint64_t offset = 0;
111 i.mCurrentPos = &pos;
112 i.mGlobalOffset = &offset;
113 REQUIRE(*i == 0);
114 pos++;
115 REQUIRE(*i == 0);
116 pos++;
117 REQUIRE(*i == 0);
118 pos++;
119 REQUIRE(*i == 0);
120 pos++;
121 REQUIRE(*i == 1);
122 pos++;
123 REQUIRE(*i == 1);
124 pos++;
125 REQUIRE(*i == 1);
126 pos++;
127 REQUIRE(*i == 1);
128
129 arrow::ChunkedArray* chunks[2] = {
130 table->column(0).get(),
131 table->column(1).get()};
132 o2::aod::Points::iterator tests(chunks, {table->num_rows(), 0});
133 REQUIRE(tests.x() == 0);
134 REQUIRE(tests.y() == 0);
135 ++tests;
136 REQUIRE(tests.x() == 0);
137 REQUIRE(tests.y() == 1);
138 using Test = InPlaceTable<"T/0"_h, o2::aod::test::X, o2::aod::test::Y>;
139 Test tests2{table};
140 size_t value = 0;
141 auto b = tests2.begin();
142 auto e = tests2.end();
143 REQUIRE(b != e);
144 ++b;
145 ++b;
146 ++b;
147 ++b;
148 ++b;
149 ++b;
150 ++b;
151 ++b;
152 REQUIRE(b == e);
153
154 b = tests2.begin();
155 REQUIRE(b != e);
156 REQUIRE(((b + 1) == (b + 1)));
157 REQUIRE(((b + 7) != b));
158 REQUIRE(((b + 7) != e));
159 REQUIRE(((b + 8) == e));
160
161 for (auto& t : tests2) {
162 REQUIRE(t.x() == value / 4);
163 REQUIRE((size_t)t.y() == value);
164 REQUIRE(value < 8);
165 value++;
166 }
167
168 for (auto t1 = tests2.begin(); t1 != tests2.end(); ++t1) {
169 for (auto t2 = t1 + 1; t2 != tests2.end(); ++t2) {
170 }
171 }
172}
173
174TEST_CASE("TestDynamicColumns")
175{
176 TableBuilder builder;
177 auto rowWriter = builder.persist<int32_t, int32_t>({"fX", "fY"});
178 rowWriter(0, 0, 0);
179 rowWriter(0, 0, 1);
180 rowWriter(0, 0, 2);
181 rowWriter(0, 0, 3);
182 rowWriter(0, 1, 4);
183 rowWriter(0, 1, 5);
184 rowWriter(0, 1, 6);
185 rowWriter(0, 1, 7);
186 auto table = builder.finalize();
187
188 using Test1 = InPlaceTable<"A"_h, o2::aod::test::X, o2::aod::test::Y, o2::aod::test::Sum<o2::aod::test::X, o2::aod::test::Y>>;
189
190 Test1 tests1{table};
191 for (auto& test : tests1) {
192 REQUIRE(test.sum() == (test.x() + test.y()));
193 }
194
195 using Test2 = InPlaceTable<"B"_h, o2::aod::test::X, o2::aod::test::Y, o2::aod::test::Sum<o2::aod::test::Y, o2::aod::test::Y>>;
196
197 Test2 tests2{table};
198 for (auto& test : tests2) {
199 CHECK(test.sum() == (test.y() + test.y()));
200 }
201}
202
203TEST_CASE("TestColumnIterators")
204{
205 TableBuilder builder;
206 auto rowWriter = builder.persist<int32_t, int32_t>({"fX", "fY"});
207 rowWriter(0, 0, 0);
208 rowWriter(0, 0, 1);
209 rowWriter(0, 0, 2);
210 rowWriter(0, 0, 3);
211 rowWriter(0, 1, 4);
212 rowWriter(0, 1, 5);
213 rowWriter(0, 1, 6);
214 rowWriter(0, 1, 7);
215 auto table = builder.finalize();
216
217 int64_t index1 = 0;
218 int64_t index2 = 0;
219 ColumnIterator<int32_t> foo{table->column(1).get()};
220 foo.mCurrentPos = &index1;
221 auto bar{foo};
222 bar.mCurrentPos = &index2;
223 REQUIRE(foo.mCurrent == bar.mCurrent);
224 REQUIRE(foo.mLast == bar.mLast);
225 REQUIRE(foo.mColumn == bar.mColumn);
226 REQUIRE(foo.mFirstIndex == bar.mFirstIndex);
227 REQUIRE(foo.mCurrentChunk == bar.mCurrentChunk);
228
229 auto foobar = std::move(foo);
230 REQUIRE(foobar.mCurrent == bar.mCurrent);
231 REQUIRE(foobar.mLast == bar.mLast);
232 REQUIRE(foobar.mColumn == bar.mColumn);
233 REQUIRE(foobar.mFirstIndex == bar.mFirstIndex);
234 REQUIRE(foobar.mCurrentChunk == bar.mCurrentChunk);
235}
236
237TEST_CASE("TestJoinedTables")
238{
239 TableBuilder builderX;
240 auto rowWriterX = builderX.persist<int32_t>({"fX"});
241 rowWriterX(0, 0);
242 rowWriterX(0, 1);
243 rowWriterX(0, 2);
244 rowWriterX(0, 3);
245 rowWriterX(0, 4);
246 rowWriterX(0, 5);
247 rowWriterX(0, 6);
248 rowWriterX(0, 7);
249 auto tableX = builderX.finalize();
250
251 TableBuilder builderY;
252 auto rowWriterY = builderY.persist<int32_t>({"fY"});
253 rowWriterY(0, 7);
254 rowWriterY(0, 6);
255 rowWriterY(0, 5);
256 rowWriterY(0, 4);
257 rowWriterY(0, 3);
258 rowWriterY(0, 2);
259 rowWriterY(0, 1);
260 rowWriterY(0, 0);
261 auto tableY = builderY.finalize();
262
263 TableBuilder builderZ;
264 auto rowWriterZ = builderZ.persist<int32_t>({"fZ"});
265 rowWriterZ(0, 8);
266 rowWriterZ(0, 8);
267 rowWriterZ(0, 8);
268 rowWriterZ(0, 8);
269 rowWriterZ(0, 8);
270 rowWriterZ(0, 8);
271 rowWriterZ(0, 8);
272 rowWriterZ(0, 8);
273 auto tableZ = builderZ.finalize();
274
275 TableBuilder builderW;
276 auto rowWriterW = builderW.persist<int32_t>({"fW"});
277 rowWriterW(0, 8);
278 rowWriterW(0, 8);
279 rowWriterW(0, 8);
280 auto tableW = builderW.finalize();
281
282 using TestX = InPlaceTable<"A0"_h, o2::aod::test::X>;
283 using TestY = InPlaceTable<"A1"_h, o2::aod::test::Y>;
284 using TestZ = InPlaceTable<"A2"_h, o2::aod::test::Z>;
285 using TestW = InPlaceTable<"A3"_h, o2::aod::test::W>;
286 using Test = Join<TestX, TestY>;
287
288 REQUIRE(Test::contains<TestX>());
289 REQUIRE(Test::contains<TestY>());
290 REQUIRE(!Test::contains<TestZ>());
291
292 Test tests{{tableX, tableY}};
293
294 REQUIRE(tests.contains<TestX>());
295 REQUIRE(tests.contains<TestY>());
296 REQUIRE(!tests.contains<TestZ>());
297
298 for (auto& test : tests) {
299 REQUIRE(7 == test.x() + test.y());
300 }
301
302 auto tests2 = join(TestX{tableX}, TestY{tableY});
303 static_assert(std::same_as<Test::self_t, decltype(tests2)>, "Joined tables should have the same type, regardless how we construct them");
304 for (auto& test : tests2) {
305 REQUIRE(7 == test.x() + test.y());
306 }
307
308 auto tests3 = join(TestX{tableX}, TestY{tableY}, TestZ{tableZ});
309
310 for (auto& test : tests3) {
311 REQUIRE(15 == test.x() + test.y() + test.z());
312 }
313 using TestMoreThanTwo = Join<TestX, TestY, TestZ>;
314 TestMoreThanTwo tests4{{tableX, tableY, tableZ}};
315 for (auto& test : tests4) {
316 REQUIRE(15 == test.x() + test.y() + test.z());
317 }
318
319 try {
320 auto testF = join(TestZ{tableZ}, TestW{tableW});
321 } catch (RuntimeErrorRef ref) {
322 REQUIRE(std::string{error_from_ref(ref).what} == "Tables TEST and TEST have different sizes (8 vs 3) and cannot be joined!");
323 }
324}
325
326TEST_CASE("TestConcatTables")
327{
328 TableBuilder builderA;
329 auto rowWriterA = builderA.persist<int32_t, int32_t>({"fX", "fY"});
330 rowWriterA(0, 0, 0);
331 rowWriterA(0, 1, 0);
332 rowWriterA(0, 2, 0);
333 rowWriterA(0, 3, 0);
334 rowWriterA(0, 4, 0);
335 rowWriterA(0, 5, 0);
336 rowWriterA(0, 6, 0);
337 rowWriterA(0, 7, 0);
338 auto tableA = builderA.finalize();
339 REQUIRE(tableA->num_rows() == 8);
340
341 TableBuilder builderB;
342 auto rowWriterB = builderB.persist<int32_t>({"fX"});
343 rowWriterB(0, 8);
344 rowWriterB(0, 9);
345 rowWriterB(0, 10);
346 rowWriterB(0, 11);
347 rowWriterB(0, 12);
348 rowWriterB(0, 13);
349 rowWriterB(0, 14);
350 rowWriterB(0, 15);
351 auto tableB = builderB.finalize();
352
353 TableBuilder builderC;
354 auto rowWriterC = builderC.persist<int32_t>({"fZ"});
355 rowWriterC(0, 8);
356 rowWriterC(0, 9);
357 rowWriterC(0, 10);
358 rowWriterC(0, 11);
359 rowWriterC(0, 12);
360 rowWriterC(0, 13);
361 rowWriterC(0, 14);
362 rowWriterC(0, 15);
363 auto tableC = builderC.finalize();
364
365 TableBuilder builderD;
366 auto rowWriterD = builderD.persist<int32_t, int32_t>({"fX", "fZ"});
367 rowWriterD(0, 16, 8);
368 rowWriterD(0, 17, 9);
369 rowWriterD(0, 18, 10);
370 rowWriterD(0, 19, 11);
371 rowWriterD(0, 20, 12);
372 rowWriterD(0, 21, 13);
373 rowWriterD(0, 22, 14);
374 rowWriterD(0, 23, 15);
375 auto tableD = builderD.finalize();
376
377 using TestA = InPlaceTable<0, o2::soa::Index<>, o2::aod::test::X, o2::aod::test::Y>; // o2::aod::TestA;
378 using TestB = InPlaceTable<0, o2::soa::Index<>, o2::aod::test::X>; // o2::aod::TestB;
379 using TestC = InPlaceTable<0, o2::aod::test::Z>; // o2::aod::TestC;
380 using TestD = InPlaceTable<0, o2::aod::test::X, o2::aod::test::Z>; // o2::aod::TestD;
381 using ConcatTest = Concat<TestA, TestB>;
382 using JoinedTest = Join<TestA, TestC>;
383 using NestedJoinTest = Join<JoinedTest, TestD>;
384 using NestedConcatTest = Concat<Join<TestA, TestB>, TestD>;
385
386 static_assert(std::same_as<NestedJoinTest::columns_t, o2::framework::pack<o2::soa::Index<>, o2::aod::test::Y, o2::aod::test::X, o2::aod::test::Z>>, "Bad nested join");
387
388 static_assert(std::same_as<ConcatTest::columns_t, o2::framework::pack<o2::soa::Index<>, o2::aod::test::X>>, "Bad intersection of columns");
389 ConcatTest tests{{tableA, tableB}};
390 REQUIRE(16 == tests.size());
391 for (auto& test : tests) {
392 REQUIRE(test.index() == test.x());
393 }
394
395 static_assert(std::same_as<NestedConcatTest::columns_t, o2::framework::pack<o2::aod::test::X>>, "Bad nested concat");
396
397 // Hardcode a selection for the first 5 odd numbers
398 using FilteredTest = Filtered<TestA>;
399 using namespace o2::framework;
400 expressions::Filter testf = (o2::aod::test::x == 1) || (o2::aod::test::x == 3);
401 gandiva::Selection selection;
402 auto status = gandiva::SelectionVector::MakeInt64(tests.size(), arrow::default_memory_pool(), &selection);
403 REQUIRE(status.ok());
404
405 auto fptr = tableA->schema()->GetFieldByName("fX");
406 REQUIRE(fptr != nullptr);
407 REQUIRE(fptr->name() == "fX");
408 REQUIRE(fptr->type()->id() == arrow::Type::INT32);
409
410 auto node_x = gandiva::TreeExprBuilder::MakeField(fptr);
411 auto literal_1 = gandiva::TreeExprBuilder::MakeLiteral(static_cast<int32_t>(1));
412 auto literal_3 = gandiva::TreeExprBuilder::MakeLiteral(static_cast<int32_t>(3));
413 auto equals_to_1 = gandiva::TreeExprBuilder::MakeFunction("equal", {node_x, literal_1}, arrow::boolean());
414 auto equals_to_3 = gandiva::TreeExprBuilder::MakeFunction("equal", {node_x, literal_3}, arrow::boolean());
415 auto node_or = gandiva::TreeExprBuilder::MakeOr({equals_to_1, equals_to_3});
416 auto condition = gandiva::TreeExprBuilder::MakeCondition(node_or);
417 REQUIRE(condition->ToString() == "bool equal((int32) fX, (const int32) 1) || bool equal((int32) fX, (const int32) 3)");
418 std::shared_ptr<gandiva::Filter> filter;
419 status = gandiva::Filter::Make(tableA->schema(), condition, &filter);
420 REQUIRE(status.ToString() == "OK");
421
422 arrow::TableBatchReader reader(*tableA);
423 std::shared_ptr<RecordBatch> batch;
424 auto s = reader.ReadNext(&batch);
425 REQUIRE(s.ok());
426 REQUIRE(batch != nullptr);
427 REQUIRE(batch->num_rows() == 8);
428 auto st = filter->Evaluate(*batch, selection);
429 REQUIRE(st.ToString() == "OK");
430
431 gandiva::Selection selection_f = expressions::createSelection(tableA, testf);
432
433 TestA testA{tableA};
434 FilteredTest filtered{{testA.asArrowTableRef()}, selection_f};
435 REQUIRE(2 == filtered.size());
436
437 auto i = 0;
438 REQUIRE(filtered.begin() != filtered.end());
439 for (auto& f : filtered) {
440 REQUIRE(i * 2 + 1 == f.x());
441 REQUIRE(i * 2 + 1 == f.index());
442 i++;
443 }
444 REQUIRE(i == 2);
445
446 // Hardcode a selection for the first 5 odd numbers
447 using FilteredConcatTest = Filtered<ConcatTest::table_t>;
448 using namespace o2::framework;
449 gandiva::Selection selectionConcat;
450 status = gandiva::SelectionVector::MakeInt64(tests.size(), arrow::default_memory_pool(), &selectionConcat);
451 REQUIRE(status.ok() == true);
452 selectionConcat->SetIndex(0, 0);
453 selectionConcat->SetIndex(1, 5);
454 selectionConcat->SetIndex(2, 10);
455 selectionConcat->SetNumSlots(3);
456 ConcatTest concatTest{tableA, tableB};
457 FilteredConcatTest concatTestTable{{concatTest.asArrowTableRef()}, selectionConcat};
458 REQUIRE(3 == concatTestTable.size());
459
460 i = 0;
461 auto b = concatTestTable.begin();
462 auto e = concatTestTable.end();
463
464 REQUIRE(b.mRowIndex == 0);
465 REQUIRE(b.getSelectionRow() == 0);
466 REQUIRE(e.index == 3);
467
468 REQUIRE(concatTestTable.begin() != concatTestTable.end());
469 for (auto& f : concatTestTable) {
470 REQUIRE(i * 5 == f.x());
471 REQUIRE(i * 5 == f.index());
472 REQUIRE(i == f.filteredIndex());
473 i++;
474 }
475 REQUIRE(i == 3);
476
477 // Test with a Joined table
478 using FilteredJoinTest = Filtered<JoinedTest::table_t>;
479 gandiva::Selection selectionJoin;
480 status = gandiva::SelectionVector::MakeInt64(tests.size(), arrow::default_memory_pool(), &selectionJoin);
481 REQUIRE(status.ok() == true);
482 selectionJoin->SetIndex(0, 0);
483 selectionJoin->SetIndex(1, 2);
484 selectionJoin->SetIndex(2, 4);
485 selectionJoin->SetNumSlots(3);
486 JoinedTest testJoin{{tableA, tableC}};
487 FilteredJoinTest filteredJoin{{testJoin.asArrowTableRef()}, selectionJoin};
488
489 i = 0;
490 REQUIRE(filteredJoin.begin() != filteredJoin.end());
491 for (auto& f : filteredJoin) {
492 REQUIRE(i * 2 == f.x());
493 REQUIRE(i * 2 == f.index());
494 i++;
495 }
496 REQUIRE(i == 3);
497}
498
499TEST_CASE("TestDereference")
500{
501 TableBuilder builderA;
502 auto pointsWriter = builderA.cursor<o2::aod::Points>();
503 pointsWriter(0, 0, 0);
504 pointsWriter(0, 3, 4);
505 auto pointsT = builderA.finalize();
506 o2::aod::Points points{pointsT};
507 REQUIRE(pointsT->num_rows() == 2);
508
509 TableBuilder builderA2;
510 auto infoWriter = builderA2.cursor<o2::aod::Infos>();
511 infoWriter(0, 0, true);
512 infoWriter(0, 1, false);
513 infoWriter(0, 4, true);
514 auto infosT = builderA2.finalize();
515 o2::aod::Infos infos{infosT};
516 REQUIRE(infos.begin().someBool() == true);
517 REQUIRE((infos.begin() + 1).someBool() == false);
518 REQUIRE((infos.begin() + 2).someBool() == true);
519 REQUIRE((infos.begin() + 2).color() == 4);
520 REQUIRE(infosT->num_rows() == 3);
521
522 TableBuilder builderB;
523 auto segmentsWriter = builderB.cursor<o2::aod::Segments>();
524 segmentsWriter(0, 10, 0, 1, 2);
525 auto segmentsT = builderB.finalize();
526 o2::aod::Segments segments{segmentsT};
527 REQUIRE(segmentsT->num_rows() == 1);
528
529 TableBuilder builderC;
530 auto segmentsExtraWriter = builderC.cursor<o2::aod::SegmentsExtras>();
531 segmentsExtraWriter(0, 1);
532 auto segmentsExtraT = builderC.finalize();
533 o2::aod::SegmentsExtras segmentsExtras{segmentsExtraT};
534 REQUIRE(segmentsExtraT->num_rows() == 1);
535
536 REQUIRE(segments.begin().pointAId() == 0);
537 REQUIRE(segments.begin().pointBId() == 1);
538 static_assert(std::same_as<decltype(segments.begin().pointA()), o2::aod::Points::iterator>);
539 auto i = segments.begin();
540 using namespace o2::framework;
541 i.bindExternalIndices(&points, &infos);
542 REQUIRE(i.n() == 10);
543 REQUIRE(i.info().color() == 4);
544 REQUIRE(i.info().someBool() == true);
545 REQUIRE(i.pointA().x() == 0);
546 REQUIRE(i.pointA().y() == 0);
547 REQUIRE(i.pointB().x() == 3);
548 REQUIRE(i.pointB().y() == 4);
549
550 segments.bindExternalIndices(&points, &infos);
551 auto j = segments.begin();
552 REQUIRE(j.n() == 10);
553 REQUIRE(j.info().color() == 4);
554 REQUIRE(j.info().someBool() == true);
555 REQUIRE(j.pointA().x() == 0);
556 REQUIRE(j.pointA().y() == 0);
557 REQUIRE(j.pointB().x() == 3);
558 REQUIRE(j.pointB().y() == 4);
559
560 auto joined = join(segments, segmentsExtras);
561 joined.bindExternalIndices(&points, &infos);
562 auto se = joined.begin();
563 REQUIRE(se.n() == 10);
564 REQUIRE(se.info().color() == 4);
565 REQUIRE(se.pointA().x() == 0);
566 REQUIRE(se.pointA().y() == 0);
567 REQUIRE(se.pointB().x() == 3);
568 REQUIRE(se.pointB().y() == 4);
569 REQUIRE(se.thickness() == 1);
570}
571
572TEST_CASE("TestSchemaCreation")
573{
574 auto schema = std::make_shared<arrow::Schema>(createFieldsFromColumns(o2::aod::Points::persistent_columns_t{}));
575 REQUIRE(schema->num_fields() == 2);
576 REQUIRE(schema->field(0)->name() == "fX");
577 REQUIRE(schema->field(1)->name() == "fY");
578}
579
580TEST_CASE("TestFilteredOperators")
581{
582 TableBuilder builderA;
583 auto rowWriterA = builderA.persist<int32_t, int32_t>({"fX", "fY"});
584 rowWriterA(0, 0, 8);
585 rowWriterA(0, 1, 9);
586 rowWriterA(0, 2, 10);
587 rowWriterA(0, 3, 11);
588 rowWriterA(0, 4, 12);
589 rowWriterA(0, 5, 13);
590 rowWriterA(0, 6, 14);
591 rowWriterA(0, 7, 15);
592 auto tableA = builderA.finalize();
593 REQUIRE(tableA->num_rows() == 8);
594
595 using TestA = InPlaceTable<0, o2::soa::Index<>, o2::aod::test::X, o2::aod::test::Y>; // o2::soa::Table<OriginEnc{"AOD"}, o2::soa::Index<>, o2::aod::test::X, o2::aod::test::Y>;
596 using FilteredTest = Filtered<TestA>;
597 using namespace o2::framework;
598
599 expressions::Filter f1 = o2::aod::test::x < 4;
600 expressions::Filter f2 = o2::aod::test::y > 13;
601
602 TestA testA{tableA};
603 auto s1 = expressions::createSelection(testA.asArrowTable(), f1);
604 FilteredTest filtered1{{testA.asArrowTableRef()}, s1};
605 REQUIRE(4 == filtered1.size());
606 REQUIRE(filtered1.begin() != filtered1.end());
607
608 auto s2 = expressions::createSelection(testA.asArrowTable(), f2);
609 FilteredTest filtered2{{testA.asArrowTableRef()}, s2};
610 REQUIRE(2 == filtered2.size());
611 REQUIRE(filtered2.begin() != filtered2.end());
612
613 FilteredTest filteredUnion = filtered1 + filtered2;
614 REQUIRE(6 == filteredUnion.size());
615
616 std::vector<std::tuple<int32_t, int32_t>> expectedUnion{{0, 8}, {1, 9}, {2, 10}, {3, 11}, {6, 14}, {7, 15}};
617 auto i = 0;
618 for (auto& f : filteredUnion) {
619 REQUIRE(std::get<0>(expectedUnion[i]) == f.x());
620 REQUIRE(std::get<1>(expectedUnion[i]) == f.y());
621 REQUIRE(std::get<0>(expectedUnion[i]) == f.index());
622 i++;
623 }
624 REQUIRE(i == 6);
625
626 FilteredTest filteredIntersection = filtered1 * filtered2;
627 REQUIRE(0 == filteredIntersection.size());
628
629 REQUIRE(filteredIntersection.size() == 0);
630
631 expressions::Filter f3 = o2::aod::test::x < 3;
632 auto s3 = expressions::createSelection(testA.asArrowTable(), f3);
633 FilteredTest filtered3{{testA.asArrowTableRef()}, s3};
634 REQUIRE(3 == filtered3.size());
635 REQUIRE(filtered3.begin() != filtered3.end());
636
637 FilteredTest unionIntersection = (filtered1 + filtered2) * filtered3;
638 REQUIRE(3 == unionIntersection.size());
639
640 i = 0;
641 for (auto& f : unionIntersection) {
642 REQUIRE(i == f.x());
643 REQUIRE(i + 8 == f.y());
644 REQUIRE(i == f.index());
645 i++;
646 }
647 REQUIRE(i == 3);
648}
649
650TEST_CASE("TestNestedFiltering")
651{
652 TableBuilder builderA;
653 auto rowWriterA = builderA.persist<int32_t, int32_t>({"fX", "fY"});
654 rowWriterA(0, 0, 8);
655 rowWriterA(0, 1, 9);
656 rowWriterA(0, 2, 10);
657 rowWriterA(0, 3, 11);
658 rowWriterA(0, 4, 12);
659 rowWriterA(0, 5, 13);
660 rowWriterA(0, 6, 14);
661 rowWriterA(0, 7, 15);
662 auto tableA = builderA.finalize();
663 REQUIRE(tableA->num_rows() == 8);
664
665 using TestA = InPlaceTable<0, o2::soa::Index<>, o2::aod::test::X, o2::aod::test::Y>;
666 using FilteredTest = Filtered<TestA>;
667 using NestedFilteredTest = Filtered<Filtered<TestA>>;
668 using TripleNestedFilteredTest = Filtered<Filtered<Filtered<TestA>>>;
669 using namespace o2::framework;
670
671 expressions::Filter f1 = o2::aod::test::x < 4;
672 expressions::Filter f2 = o2::aod::test::y > 9;
673 expressions::Filter f3 = o2::aod::test::x < 3;
674
675 TestA testA{tableA};
676 auto s1 = expressions::createSelection(testA.asArrowTable(), f1);
677 FilteredTest filtered{{testA.asArrowTableRef()}, s1};
678 REQUIRE(4 == filtered.size());
679 REQUIRE(filtered.begin() != filtered.end());
680
681 auto s2 = expressions::createSelection(filtered.asArrowTable(), f2);
682 NestedFilteredTest nestedFiltered{{filtered}, s2};
683 REQUIRE(2 == nestedFiltered.size());
684 auto i = 0;
685 for (auto& f : nestedFiltered) {
686 REQUIRE(i + 2 == f.x());
687 REQUIRE(i + 10 == f.y());
688 REQUIRE(i + 2 == f.index());
689 i++;
690 }
691 REQUIRE(i == 2);
692
693 auto s3 = expressions::createSelection(nestedFiltered.asArrowTable(), f3);
694 TripleNestedFilteredTest tripleFiltered{{nestedFiltered}, s3};
695 REQUIRE(1 == tripleFiltered.size());
696 i = 0;
697 for (auto& f : tripleFiltered) {
698 REQUIRE(i + 2 == f.x());
699 REQUIRE(i + 10 == f.y());
700 REQUIRE(i + 2 == f.index());
701 i++;
702 }
703 REQUIRE(i == 1);
704}
705
706TEST_CASE("TestEmptyTables")
707{
708 TableBuilder bPoints;
709 [[maybe_unused]] auto pwriter = bPoints.cursor<o2::aod::Points>();
710 auto pempty = bPoints.finalize();
711
712 TableBuilder bInfos;
713 [[maybe_unused]] auto iwriter = bInfos.cursor<o2::aod::Infos>();
714 auto iempty = bInfos.finalize();
715
716 o2::aod::Points p{pempty};
717 o2::aod::Infos i{iempty};
718
720 PI pi{{pempty, iempty}};
721 REQUIRE(pi.size() == 0);
722 auto spawned = Extend<o2::aod::Points, o2::aod::test::ESum>(p);
723 REQUIRE(spawned.size() == 0);
724}
725
726namespace o2::aod
727{
728DECLARE_SOA_TABLE(Origints, "TEST", "ORIG", o2::soa::Index<>, test::X, test::SomeBool);
729namespace test
730{
731DECLARE_SOA_INDEX_COLUMN(Origint, origint);
732DECLARE_SOA_INDEX_COLUMN_FULL(AltOrigint, altOrigint, int, Origints, "_alt");
734} // namespace test
735
736DECLARE_SOA_TABLE(References, "TEST", "REFS", o2::soa::Index<>, test::OrigintId);
737DECLARE_SOA_TABLE(OtherReferences, "TEST", "OREFS", o2::soa::Index<>, test::AltOrigintId);
738DECLARE_SOA_TABLE(ManyReferences, "TEST", "MREFS", o2::soa::Index<>, test::OrigintIds);
739} // namespace o2::aod
740
741TEST_CASE("TestIndexToFiltered")
742{
744 auto writer = b.cursor<o2::aod::Origints>();
745 for (auto i = 0; i < 20; ++i) {
746 writer(0, i, i % 3 == 0);
747 }
748 auto origins = b.finalize();
749 o2::aod::Origints o{origins};
750
752 auto writer_z = z.cursor<o2::aod::ManyReferences>();
753 std::vector<int> ids;
754 for (auto i = 0; i < 5; ++i) {
755 ids.clear();
756 for (auto j = 0; j < 20; ++j) {
757 ids.push_back(j);
758 }
759 writer_z(0, ids);
760 }
761 auto mrefs = z.finalize();
762 o2::aod::ManyReferences m{mrefs};
763
765 auto writer_w = w.cursor<o2::aod::References>();
766 for (auto i = 0; i < 5 * 20; ++i) {
767 writer_w(0, i % 20);
768 }
769 auto refs = w.finalize();
770 o2::aod::References r{refs};
771 expressions::Filter flt = o2::aod::test::someBool == true;
773 auto selection = expressions::createSelection(o.asArrowTable(), flt);
774 Flt f{{o.asArrowTableRef()}, selection};
775 r.bindExternalIndices(&f);
776 auto it = r.begin();
777 it.moveByIndex(23);
778 REQUIRE(it.origint_as<Flt>().globalIndex() == 3);
779 it++;
780 REQUIRE(it.origint_as<Flt>().globalIndex() == 4);
781 it++;
782 REQUIRE(it.origint_as<Flt>().globalIndex() == 5);
783
784 m.bindExternalIndices(&f);
785 for (auto const& row : m) {
786 auto os = row.origints_as<Flt>();
787 auto fos = row.filtered_origints_as<Flt>();
788 REQUIRE(os.size() == 20);
789 REQUIRE(fos.size() == 6);
790 }
791}
792namespace o2::aod
793{
794namespace test
795{
796DECLARE_SOA_INDEX_COLUMN_FULL(SinglePoint, singlePoint, int32_t, Points3Ds, "");
797DECLARE_SOA_ARRAY_INDEX_COLUMN(Points3D, pointGroup);
798DECLARE_SOA_SLICE_INDEX_COLUMN(Points3D, pointSlice);
799DECLARE_SOA_SELF_INDEX_COLUMN(OtherPoint, otherPoint);
802} // namespace test
803
804DECLARE_SOA_TABLE(PointsRef, "TEST", "PTSREF", test::Points3DIdSlice, test::Points3DIds);
805DECLARE_SOA_TABLE(PointsRefF, "TEST", "PTSREFF", test::SinglePointId, test::Points3DIdSlice, test::Points3DIds);
806DECLARE_SOA_TABLE(PointsSelfIndex, "TEST", "PTSSLF", o2::soa::Index<>, test::X, test::Y, test::Z, test::OtherPointId,
807 test::PointSeqIdSlice, test::PointSetIds);
808} // namespace o2::aod
809
810TEST_CASE("TestAdvancedIndices")
811{
812 TableBuilder b1;
813 auto pwriter = b1.persist<int, int, int>({"fX", "fY", "fZ"});
814 for (auto i = 0; i < 20; ++i) {
815 pwriter(0, -1 * i, (int)(i / 2), 2 * i);
816 }
817 auto tpts1 = b1.finalize();
818
819 TableBuilder b2;
820 auto prwriter = b2.cursor<o2::aod::PointsRef>();
821 auto a = std::array{0, 1};
822 auto aa = std::vector{2, 3, 4};
823 prwriter(0, &a[0], aa);
824 a = {4, 10};
825 aa = {12, 2, 19};
826 prwriter(0, &a[0], aa);
827 auto t2 = b2.finalize();
828
829 auto pt = o2::aod::Points3Ds{tpts1};
830 auto prt = o2::aod::PointsRef{t2};
831 prt.bindExternalIndices(&pt);
832
833 auto it = prt.begin();
834 auto s1 = it.pointSlice();
835 auto g1 = it.pointGroup();
836 auto bb = std::same_as<decltype(s1), o2::aod::Points3Ds>;
837 REQUIRE(bb);
838 REQUIRE(s1.size() == 2);
839 aa = {2, 3, 4};
840 for (int i = 0; i < 3; ++i) {
841 REQUIRE(g1[i].globalIndex() == aa[i]);
842 }
843
844 // Check the X coordinate of the points in the pointGroup
845 // for the first point.
846 for (auto& p : it.pointGroup_as<o2::aod::Points3Ds>()) {
847 REQUIRE(p.x() == -1 * p.globalIndex());
848 }
849
850 ++it;
851 auto s2 = it.pointSlice();
852 auto g2 = it.pointGroup();
853 REQUIRE(s2.size() == 7);
854 aa = {12, 2, 19};
855 for (int i = 0; i < 3; ++i) {
856 REQUIRE(g2[i].globalIndex() == aa[i]);
857 }
858
860 expressions::Filter fltx = (o2::aod::test::x <= -6);
861 Flt f{{tpts1}, expressions::createSelection(tpts1, fltx)};
862 prt.bindExternalIndices(&f);
863
864 auto it2 = prt.begin();
865 auto s1f = it2.pointSlice_as<Flt>();
866 auto g1f = it2.pointGroup_as<Flt>();
867 REQUIRE(s1f.size() == 2);
868 aa = {2, 3, 4};
869 for (int i = 0; i < 3; ++i) {
870 REQUIRE(g1f[i].globalIndex() == aa[i]);
871 }
872
873 ++it2;
874 auto s2f = it2.pointSlice_as<Flt>();
875 auto g2f = it2.pointGroup_as<Flt>();
876 REQUIRE(s2f.size() == 7);
877 aa = {12, 2, 19};
878 for (int i = 0; i < 3; ++i) {
879 REQUIRE(g2f[i].globalIndex() == aa[i]);
880 }
881
882 TableBuilder b3;
883 auto pswriter = b3.cursor<o2::aod::PointsSelfIndex>();
884 int references[] = {19, 2, 0, 13, 4, 6, 5, 5, 11, 9, 3, 8, 16, 14, 1, 18, 12, 18, 2, 7};
885 int slice[2] = {-1, -1};
886 std::vector<int> pset;
887 std::array<int, 4> withSlices = {3, 6, 13, 19};
888 std::array<std::pair<int, int>, 4> bounds = {std::pair{1, 5}, std::pair{3, 3}, std::pair{11, 11}, std::pair{10, 18}};
889 std::array<int, 4> withSets = {0, 1, 13, 14};
890 unsigned const int sizes[] = {3, 1, 5, 4};
891 unsigned int c1 = 0;
892 unsigned int c2 = 0;
893 for (auto i = 0; i < 20; ++i) {
894 pset.clear();
895 slice[0] = -1;
896 slice[1] = -1;
897 if (c1 < withSlices.size() && i == withSlices[c1]) {
898 slice[0] = bounds[c1].first;
899 slice[1] = bounds[c1].second;
900 ++c1;
901 }
902 if (c2 < withSets.size() && i == withSets[c2]) {
903 for (auto z = 0U; z < sizes[c2]; ++z) {
904 pset.push_back(i + 1 + z);
905 }
906 ++c2;
907 }
908 pswriter(0, -1 * i, 0.5 * i, 2 * i, references[i], slice, pset);
909 }
910 auto t3 = b3.finalize();
911 auto pst = o2::aod::PointsSelfIndex{t3};
912 pst.bindInternalIndicesTo(&pst);
913 auto i = 0;
914 c1 = 0;
915 c2 = 0;
916 for (auto& p : pst) {
917 auto op = p.otherPoint_as<o2::aod::PointsSelfIndex>();
918 auto bbb = std::same_as<decltype(op), o2::aod::PointsSelfIndex::iterator>;
919 REQUIRE(bbb);
920 REQUIRE(op.globalIndex() == references[i]);
921
922 auto ops = p.pointSeq_as<o2::aod::PointsSelfIndex>();
923 auto bbbs = std::same_as<decltype(ops), o2::aod::PointsSelfIndex>;
924 REQUIRE(bbbs);
925
926 if (i == withSlices[c1]) {
927 auto lit = ops.begin();
928 REQUIRE(ops.size() == bounds[c1].second - bounds[c1].first + 1);
929 REQUIRE(lit.globalIndex() == bounds[c1].first);
930 lit.moveByIndex(ops.size() - 1);
931 REQUIRE(lit.globalIndex() == bounds[c1].second);
932 ++c1;
933 } else {
934 REQUIRE(ops.size() == 0);
935 }
936
937 auto opss = p.pointSet_as<o2::aod::PointsSelfIndex>();
938 auto bbba = std::same_as<decltype(opss), std::vector<o2::aod::PointsSelfIndex::iterator>>;
939 REQUIRE(bbba);
940
941 auto opss_ids = p.pointSetIds();
942 if (c2 < withSets.size() && i == withSets[c2]) {
943 REQUIRE(opss.size() == sizes[c2]);
944 REQUIRE(opss.begin()->globalIndex() == i + 1);
945 REQUIRE(opss.back().globalIndex() == i + sizes[c2]);
946 int c3 = 0;
947 for (auto const& id : opss_ids) {
948 REQUIRE(id == i + 1 + c3);
949 ++c3;
950 }
951 ++c2;
952 } else {
953 REQUIRE(opss.size() == 0);
954 }
955 ++i;
956 }
957}
958
959namespace o2::aod
960{
961DECLARE_SOA_TABLE(PointsSelfRef, "TEST", "PTSSR", test::OtherPointId, test::PointSeqIdSlice, test::PointSetIds);
962} // namespace o2::aod
963
964TEST_CASE("TestSelfIndexRecursion")
965{
966 TableBuilder b3;
967 auto pswriter = b3.cursor<o2::aod::PointsSelfIndex>();
968 int references[] = {19, 2, 0, 13, 4, 6, 5, 5, 11, 9, 3, 8, 16, 14, 1, 18, 12, 18, 2, 7};
969 int slice[2] = {-1, -1};
970 std::vector<int> pset;
971 std::array<int, 4> withSlices = {3, 6, 13, 19};
972 std::array<std::pair<int, int>, 4> bounds = {std::pair{1, 5}, std::pair{3, 3}, std::pair{11, 11}, std::pair{10, 18}};
973 std::array<int, 4> withSets = {0, 1, 13, 14};
974 unsigned const int sizes[] = {3, 1, 5, 4};
975 unsigned int c1 = 0;
976 unsigned int c2 = 0;
977 for (auto i = 0; i < 20; ++i) {
978 pset.clear();
979 slice[0] = -1;
980 slice[1] = -1;
981 if (c1 < withSlices.size() && i == withSlices[c1]) {
982 slice[0] = bounds[c1].first;
983 slice[1] = bounds[c1].second;
984 ++c1;
985 }
986 if (c2 < withSets.size() && i == withSets[c2]) {
987 for (auto z = 0U; z < sizes[c2]; ++z) {
988 pset.push_back(i + 1 + z);
989 }
990 ++c2;
991 }
992 pswriter(0, -1 * i, 0.5 * i, 2 * i, references[i], slice, pset);
993 }
994 auto t3 = b3.finalize();
995 auto pst = o2::aod::PointsSelfIndex{t3};
996 pst.bindInternalIndicesTo(&pst);
997
998 // FIXME: only 4 levels of recursive self-index dereference are tested
999 for (auto& p : pst) {
1000 auto ops = p.pointSeq_as<o2::aod::PointsSelfIndex>();
1001 for (auto& pp : ops) {
1002 auto bpp = std::same_as<std::decay_t<decltype(pp)>, o2::aod::PointsSelfIndex::iterator>;
1003 REQUIRE(bpp);
1004 auto opps = pp.pointSeq_as<o2::aod::PointsSelfIndex>();
1005 for (auto& ppp : opps) {
1006 auto bppp = std::same_as<std::decay_t<decltype(ppp)>, o2::aod::PointsSelfIndex::iterator>;
1007 REQUIRE(bppp);
1008 auto oppps = ppp.pointSeq_as<o2::aod::PointsSelfIndex>();
1009 for (auto& pppp : oppps) {
1010 auto bpppp = std::same_as<std::decay_t<decltype(pppp)>, o2::aod::PointsSelfIndex::iterator>;
1011 REQUIRE(bpppp);
1012 auto opppps = pppp.pointSeq_as<o2::aod::PointsSelfIndex>();
1013 }
1014 }
1015 }
1016 }
1017
1020 auto corewriter = b.cursor<o2::aod::Points3Ds>();
1021 for (auto i = 0; i < 20; ++i) {
1022 corewriter(0, -1 * i, 0.5 * i, 2 * i);
1023 }
1024 auto t1 = b.finalize();
1025
1026 c1 = 0;
1027 c2 = 0;
1028 TableBuilder be;
1029 auto extwriter = be.cursor<o2::aod::PointsSelfRef>();
1030 for (auto i = 0; i < 20; ++i) {
1031 pset.clear();
1032 slice[0] = -1;
1033 slice[1] = -1;
1034 if (c1 < withSlices.size() && i == withSlices[c1]) {
1035 slice[0] = bounds[c1].first;
1036 slice[1] = bounds[c1].second;
1037 ++c1;
1038 }
1039 if (c2 < withSets.size() && i == withSets[c2]) {
1040 for (auto z = 0U; z < sizes[c2]; ++z) {
1041 pset.push_back(i + 1 + z);
1042 }
1043 ++c2;
1044 }
1045 extwriter(0, references[i], slice, pset);
1046 }
1047 auto t2 = be.finalize();
1048
1049 FullPoints fp({t1, t2});
1050 fp.bindInternalIndicesTo(&fp);
1051
1052 // FIXME: only 4 levels of recursive self-index dereference are tested
1053 // self-index binding should stay the same for recursive dereferences
1054 for (auto& p : fp) {
1055 REQUIRE(std::same_as<std::decay_t<decltype(p)>, FullPoints::iterator>);
1056 auto ops = p.pointSeq_as<FullPoints>();
1057 for (auto& pp : ops) {
1058 REQUIRE(std::same_as<std::decay_t<decltype(pp)>, FullPoints::iterator>);
1059 auto opps = pp.pointSeq_as<FullPoints>();
1060 for (auto& ppp : opps) {
1061 REQUIRE(std::same_as<std::decay_t<decltype(ppp)>, FullPoints::iterator>);
1062 auto oppps = ppp.pointSeq_as<FullPoints>();
1063 for (auto& pppp : oppps) {
1064 REQUIRE(std::same_as<std::decay_t<decltype(pppp)>, FullPoints::iterator>);
1065 auto opppps = pppp.pointSeq_as<FullPoints>();
1066 }
1067 }
1068 }
1069 }
1070
1071 auto const& fpa = fp;
1072
1073 // iterators acquired through different means should have consistent types
1074 for (auto const& it1 : fpa) {
1075 [[maybe_unused]] auto it2 = fpa.rawIteratorAt(0);
1076 [[maybe_unused]] auto it3 = fpa.iteratorAt(0);
1077 auto bit1 = std::same_as<std::decay_t<decltype(it1)>, std::decay_t<decltype(it2)>>;
1078 REQUIRE(bit1);
1079 auto bit2 = std::same_as<std::decay_t<decltype(it1)>, std::decay_t<decltype(it3)>>;
1080 REQUIRE(bit2);
1081 }
1082
1083 using FilteredPoints = o2::soa::Filtered<FullPoints>;
1084 FilteredPoints ffp({t1, t2}, SelectionVector{1, 2, 3});
1085 ffp.bindInternalIndicesTo(&ffp);
1086
1087 // Filter should not interfere with self-index and the binding should stay the same
1088 for (auto& p : ffp) {
1089 REQUIRE(std::same_as<std::decay_t<decltype(p)>, FilteredPoints::iterator>);
1090 REQUIRE(std::same_as<std::decay_t<decltype(p)>::parent_t, FilteredPoints>);
1091 auto ops = p.pointSeq_as<typename std::decay_t<decltype(p)>::parent_t>();
1092 for (auto& pp : ops) {
1093 REQUIRE(std::same_as<std::decay_t<decltype(pp)>::parent_t, FilteredPoints>);
1094 auto opps = pp.pointSeq_as<FilteredPoints>();
1095 for (auto& ppp : opps) {
1096 REQUIRE(std::same_as<std::decay_t<decltype(ppp)>, FilteredPoints::iterator>);
1097 auto oppps = ppp.pointSeq_as<FilteredPoints>();
1098 for (auto& pppp : oppps) {
1099 REQUIRE(std::same_as<std::decay_t<decltype(pppp)>, FilteredPoints::iterator>);
1100 auto opppps = pppp.pointSeq_as<FilteredPoints>();
1101 }
1102 }
1103 }
1104 }
1105
1106 auto const& ffpa = ffp;
1107
1108 // rawIteratorAt() should create an unfiltered iterator, unlike begin() and iteratorAt()
1109 for (auto const& it1 : ffpa) {
1110 [[maybe_unused]] auto it2 = ffpa.rawIteratorAt(0);
1111 [[maybe_unused]] auto it3 = ffpa.iteratorAt(0);
1112 using T1 = std::decay_t<decltype(it1)>;
1113 using T2 = std::decay_t<decltype(it2)>;
1114 using T3 = std::decay_t<decltype(it3)>;
1115 auto bit1 = !std::same_as<T1, T2>;
1116 REQUIRE(bit1);
1117 auto bit2 = !std::same_as<T1, T3>;
1118 REQUIRE(bit2);
1119 auto bit3 = std::same_as<typename T1::policy_t, typename T3::policy_t>;
1120 REQUIRE(bit3);
1121 auto bit4 = std::same_as<typename T1::policy_t, o2::soa::FilteredIndexPolicy>;
1122 REQUIRE(bit4);
1123 auto bit5 = std::same_as<typename T2::policy_t, o2::soa::DefaultIndexPolicy>;
1124 REQUIRE(bit5);
1125 }
1126}
1127
1128TEST_CASE("TestListColumns")
1129{
1131 auto writer = b.cursor<o2::aod::Lists>();
1132 std::vector<float> floats;
1133 std::vector<int> ints;
1134 for (auto i = 1; i < 11; ++i) {
1135 floats.clear();
1136 ints.clear();
1137 for (auto j = 0; j < i; ++j) {
1138 floats.push_back(0.1231233f * (float)j + 0.1982798f);
1139 ints.push_back(j + 10);
1140 }
1141
1142 writer(0, floats, ints);
1143 }
1144 auto lt = b.finalize();
1145 o2::aod::Lists tbl{lt};
1146 auto s = 1U;
1147 for (auto& row : tbl) {
1148 auto f = row.l1();
1149 auto i = row.l2();
1150 auto constexpr bf = std::same_as<decltype(f), gsl::span<const float, (size_t)-1>>;
1151 auto constexpr bi = std::same_as<decltype(i), gsl::span<const int, (size_t)-1>>;
1152 REQUIRE(bf);
1153 REQUIRE(bi);
1154 REQUIRE(f.size() == s);
1155 REQUIRE(i.size() == s);
1156
1157 for (auto j = 0u; j < f.size(); ++j) {
1158 REQUIRE(f[j] == 0.1231233f * (float)j + 0.1982798f);
1159 REQUIRE(i[j] == (int)j + 10);
1160 }
1161 ++s;
1162 }
1163}
1164
1165TEST_CASE("TestSliceByCached")
1166{
1168 auto writer = b.cursor<o2::aod::Origints>();
1169 for (auto i = 0; i < 20; ++i) {
1170 writer(0, i, i % 3 == 0);
1171 }
1172 auto origins = b.finalize();
1173 o2::aod::Origints o{origins};
1174
1176 auto writer_w = w.cursor<o2::aod::References>();
1177 auto step = -1;
1178 for (auto i = 0; i < 5 * 20; ++i) {
1179 if (i % 5 == 0) {
1180 ++step;
1181 }
1182 writer_w(0, step);
1183 }
1184 auto refs = w.finalize();
1185 o2::aod::References r{refs};
1186
1187 std::string key = "fIndex" + o2::framework::cutString(o2::soa::getLabelFromType<o2::aod::Origints>());
1188 ArrowTableSlicingCache atscache({{o2::soa::getLabelFromType<o2::aod::References>(), o2::soa::getMatcherFromTypeForKey<o2::aod::References>(key), key}});
1189 auto s = atscache.updateCacheEntry(0, refs);
1190 SliceCache cache{&atscache};
1191
1192 for (auto& oi : o) {
1193 auto cachedSlice = r.sliceByCached(o2::aod::test::origintId, oi.globalIndex(), cache);
1194 REQUIRE(cachedSlice.size() == 5);
1195 for (auto& ri : cachedSlice) {
1196 REQUIRE(ri.origintId() == oi.globalIndex());
1197 }
1198 }
1199}
1200
1201TEST_CASE("TestSliceByCachedMismatched")
1202{
1204 auto writer = b.cursor<o2::aod::Origints>();
1205 for (auto i = 0; i < 20; ++i) {
1206 writer(0, i, i % 3 == 0);
1207 }
1208 auto origins = b.finalize();
1209 o2::aod::Origints o{origins};
1210
1212 auto writer_w = w.cursor<o2::aod::References>();
1213 auto step = -1;
1214 for (auto i = 0; i < 5 * 20; ++i) {
1215 if (i % 5 == 0) {
1216 ++step;
1217 }
1218 writer_w(0, step);
1219 }
1220 auto refs = w.finalize();
1221 o2::aod::References r{refs};
1222
1223 TableBuilder w2;
1224 auto writer_w2 = w2.cursor<o2::aod::OtherReferences>();
1225 step = -1;
1226 for (auto i = 0; i < 5 * 20; ++i) {
1227 if (i % 3 == 0) {
1228 ++step;
1229 }
1230 writer_w2(0, step);
1231 }
1232 auto refs2 = w2.finalize();
1233 o2::aod::OtherReferences r2{refs2};
1234
1236 J rr{{refs, refs2}};
1237
1238 auto key = "fIndex" + o2::framework::cutString(o2::soa::getLabelFromType<o2::aod::Origints>()) + "_alt";
1239 ArrowTableSlicingCache atscache({{o2::soa::getLabelFromTypeForKey<J>(key), o2::soa::getMatcherFromTypeForKey<J>(key), key}});
1240 auto s = atscache.updateCacheEntry(0, refs2);
1241 SliceCache cache{&atscache};
1242
1243 for (auto& oi : o) {
1244 auto cachedSlice = rr.sliceByCached(o2::aod::test::altOrigintId, oi.globalIndex(), cache);
1245 REQUIRE(cachedSlice.size() == 3);
1246 for (auto& ri : cachedSlice) {
1247 REQUIRE(ri.altOrigintId() == oi.globalIndex());
1248 }
1249 }
1250}
1251
1252TEST_CASE("TestSliceByCachedFiltered")
1253{
1255 auto writer = b.cursor<o2::aod::Origints>();
1256 for (auto i = 0; i < 20; ++i) {
1257 writer(0, i, i % 3 == 0);
1258 }
1259 auto origins = b.finalize();
1260 o2::aod::Origints o{origins};
1261
1263 auto writer_w = w.cursor<o2::aod::References>();
1264 auto step = -1;
1265 for (auto i = 0; i < 5 * 20; ++i) {
1266 if (i % 5 == 0) {
1267 ++step;
1268 }
1269 writer_w(0, step);
1270 }
1271 auto refs = w.finalize();
1272 o2::aod::References r{refs};
1273
1274 TableBuilder w2;
1275 auto writer_w2 = w2.cursor<o2::aod::OtherReferences>();
1276 step = -1;
1277 for (auto i = 0; i < 5 * 20; ++i) {
1278 if (i % 3 == 0) {
1279 ++step;
1280 }
1281 writer_w2(0, step);
1282 }
1283 auto refs2 = w2.finalize();
1284 o2::aod::OtherReferences r2{refs2};
1285
1287 J rr{{refs, refs2}};
1288
1289 auto rrf = rr.select(o2::aod::test::altOrigintId > 2 && o2::aod::test::altOrigintId < 15);
1290
1291 auto key = "fIndex" + o2::framework::cutString(o2::soa::getLabelFromType<o2::aod::Origints>()) + "_alt";
1292 ArrowTableSlicingCache atscache({{o2::soa::getLabelFromTypeForKey<J>(key), o2::soa::getMatcherFromTypeForKey<J>(key), key}});
1293 auto s = atscache.updateCacheEntry(0, refs2);
1294 SliceCache cache{&atscache};
1295
1296 for (auto& oi : o) {
1297 auto cachedSlice = rrf.sliceByCached(o2::aod::test::altOrigintId, oi.globalIndex(), cache);
1298 if (oi.globalIndex() <= 2 || oi.globalIndex() >= 15) {
1299 CHECK(cachedSlice.size() == 0);
1300 } else {
1301 CHECK(cachedSlice.size() == 3);
1302 }
1303 for (auto& ri : cachedSlice) {
1304 REQUIRE(ri.altOrigintId() == oi.globalIndex());
1305 }
1306 }
1307}
1308
1309TEST_CASE("TestIndexUnboundExceptions")
1310{
1312 auto prwriter = b.cursor<o2::aod::PointsRefF>();
1313 auto a = std::array{0, 1};
1314 auto aa = std::vector{2, 3, 4};
1315 prwriter(0, 0, &a[0], aa);
1316 a = {4, 10};
1317 aa = {12, 2, 19};
1318 prwriter(0, 1, &a[0], aa);
1319 auto t = b.finalize();
1320 auto prt = o2::aod::PointsRefF{t};
1321
1322 for (auto& row : prt) {
1323 try {
1324 [[maybe_unused]] auto sp = row.singlePoint();
1325 } catch (RuntimeErrorRef ref) {
1326 REQUIRE(std::string{error_from_ref(ref).what} == "Index pointing to Points3Ds is not bound! Did you subscribe to the table?");
1327 }
1328 try {
1329 auto ps = row.pointSlice();
1330 } catch (RuntimeErrorRef ref) {
1331 REQUIRE(std::string{error_from_ref(ref).what} == "Index pointing to Points3Ds is not bound! Did you subscribe to the table?");
1332 }
1333 try {
1334 auto pg = row.pointGroup();
1335 } catch (RuntimeErrorRef ref) {
1336 REQUIRE(std::string{error_from_ref(ref).what} == "Index pointing to Points3Ds is not bound! Did you subscribe to the table?");
1337 }
1338 }
1339}
1340
1341namespace o2::aod
1342{
1343namespace test
1344{
1345DECLARE_SOA_COLUMN(SmallIntArray, smallIntArray, int8_t[32]);
1346DECLARE_SOA_BITMAP_COLUMN(BoolArray, boolArray, 32);
1347} // namespace test
1348
1349DECLARE_SOA_TABLE(BILists, "TEST", "BILISTS", o2::soa::Index<>, test::SmallIntArray, test::BoolArray);
1350} // namespace o2::aod
1351
1352TEST_CASE("TestArrayColumns")
1353{
1355 auto writer = b.cursor<o2::aod::BILists>();
1356 int8_t ii[32];
1357 for (auto i = 0; i < 20; ++i) {
1358 uint32_t bb = 0;
1359 for (auto j = 0; j < 32; ++j) {
1360 ii[j] = j;
1361 if (j % 2 == 0) {
1362 bb |= 1 << j;
1363 }
1364 }
1365 writer(0, ii, bb);
1366 }
1367 auto t = b.finalize();
1368
1369 o2::aod::BILists li{t};
1370 for (auto const& row : li) {
1371 auto iir = row.smallIntArray();
1372 [[maybe_unused]] auto bbrr = row.boolArray_raw();
1373 REQUIRE(std::same_as<std::decay_t<decltype(iir)>, int8_t const*>);
1374 for (auto i = 0; i < 32; ++i) {
1375 REQUIRE(iir[i] == i);
1376 REQUIRE(row.boolArray_bit(i) == (i % 2 == 0));
1377 }
1378 }
1379}
1380
1381namespace o2::aod
1382{
1383namespace table
1384{
1386DECLARE_SOA_COLUMN(Two, two, float);
1387DECLARE_SOA_COLUMN(Three, three, double);
1388DECLARE_SOA_COLUMN(Four, four, int[2]);
1389DECLARE_SOA_DYNAMIC_COLUMN(Five, five, [](const int in[2]) -> float { return (float)in[0] / (float)in[1]; });
1390} // namespace table
1391
1392DECLARE_SOA_TABLE(MixTest, "AOD", "MIXTST",
1393 table::One, table::Two, table::Three, table::Four,
1394 table::Five<table::Four>);
1395} // namespace o2::aod
1396
1397TEST_CASE("TestCombinedGetter")
1398{
1400 auto writer = b.cursor<o2::aod::MixTest>();
1401 int f[2];
1402 for (auto i = 0; i < 20; ++i) {
1403 f[0] = i;
1404 f[1] = i + 1;
1406 }
1407 auto t = b.finalize();
1408 o2::aod::MixTest mt{t};
1409 auto count = 0;
1410 for (auto const& row : mt) {
1411 auto features1 = row.getValues<float, o2::aod::table::One, o2::aod::table::Three>();
1412 auto features2 = row.getValues<double, o2::aod::table::One, o2::aod::table::Two, o2::aod::table::Three>();
1413 auto features3 = row.getValues<float, o2::aod::table::Two, o2::aod::table::Five<o2::aod::table::Four>>();
1414 auto b1 = std::same_as<std::array<float, 2>, decltype(features1)>;
1415 REQUIRE(b1);
1416 auto b2 = std::same_as<std::array<double, 3>, decltype(features2)>;
1417 REQUIRE(b2);
1418 auto b3 = std::same_as<std::array<float, 2>, decltype(features3)>;
1419 REQUIRE(b3);
1420 REQUIRE(features1[0] == (float)count);
1421 REQUIRE(features1[1] == (float)(o2::constants::math::Almost0 * count));
1422
1423 REQUIRE(features2[0] == (double)count);
1424 REQUIRE(features2[1] == (double)(o2::constants::math::PI * count));
1425 REQUIRE(features2[2] == (double)(o2::constants::math::Almost0 * count));
1426
1427 REQUIRE(features3[0] == (float)(o2::constants::math::PI * count));
1428 REQUIRE(features3[1] == (float)((float)count / (float)(count + 1)));
1429 ++count;
1430 }
1431}
1432
1433TEST_CASE("TestWritingCursorLastIndexAndReserve")
1434{
1435 // Nails down the WritingCursor semantics the AOD-producer reserves depend on:
1436 // lastIndex() returns the *last index* (rows - 1), not the row count, and
1437 // reserve(newRows + lastIndex() + 1) reserves exactly the post-batch total so a
1438 // fully-filled, no-skip batch neither overruns (the fwdTrkCls crash) nor trips
1439 // the release() / per-row UnsafeAppend guard.
1440 Produces<o2::aod::Points> cursor; // Points has two persistent columns: X, Y
1441 auto* builder = new TableBuilder();
1443
1444 // Empty cursor: no row written, so the last index is -1 and rows == lastIndex()+1 == 0.
1445 REQUIRE(cursor.lastIndex() == -1);
1446
1447 // operator() increments before the append, but only to the index of the row it
1448 // writes: after N writes lastIndex() == N - 1, NOT N.
1449 cursor(10, 20);
1450 REQUIRE(cursor.lastIndex() == 0);
1451 cursor(11, 21);
1452 REQUIRE(cursor.lastIndex() == 1);
1453 cursor(12, 22);
1454 REQUIRE(cursor.lastIndex() == 2);
1455 REQUIRE(cursor.lastIndex() + 1 == 3); // rows-so-far == last index + 1
1456
1457 // Reserve a second batch the correct way: total = newRows + rowsSoFar
1458 // = newRows + (lastIndex() + 1).
1459 // The (buggy) newRows + lastIndex() would reserve 4 here and under-reserve the
1460 // 5th row; the + 1 makes it exactly 5.
1461 int64_t const newRows = 2;
1462 int64_t const reserved = newRows + cursor.lastIndex() + 1; // correct total -> reserve(5)
1463 cursor.reserve(reserved);
1464 cursor(13, 23); // row index 3
1465 cursor(14, 24); // row index 4 — fills the batch exactly (5 rows total)
1466 REQUIRE(cursor.lastIndex() == 4);
1467
1468 // The contract release() enforces: rows filled (lastIndex()+1) must not exceed
1469 // what was reserved. Correct (+1) gives reserved == 5 -> 5 <= 5 (green); the buggy
1470 // newRows + lastIndex() reserves only 4 -> 5 <= 4 fails (red).
1471 REQUIRE(cursor.lastIndex() + 1 <= reserved);
1472
1473 auto table = builder->finalize();
1474 REQUIRE(table->num_rows() == 5);
1475 REQUIRE(table->num_columns() == 2);
1476 cursor.release();
1477}
1478
1479namespace o2::aod
1480{
1481namespace test
1482{
1483DECLARE_SOA_COLUMN(UInt8, guint8, uint8_t);
1484DECLARE_SOA_COLUMN(UInt16, guint16, uint16_t);
1485DECLARE_SOA_COLUMN(UInt32, guint32, uint32_t);
1486DECLARE_SOA_COLUMN(UInt64, guint64, uint64_t);
1487} // namespace test
1488
1489DECLARE_SOA_TABLE(UnsignedIntTest8, "TEST", "TSHI8", test::UInt8);
1490DECLARE_SOA_TABLE(UnsignedIntTest16, "TEST", "TSHI16", test::UInt16);
1491DECLARE_SOA_TABLE(UnsignedIntTest32, "TEST", "TSHI32", test::UInt32);
1492DECLARE_SOA_TABLE(UnsignedIntTest64, "TEST", "TSHI64", test::UInt64);
1493} // namespace o2::aod
1494
1495TEST_CASE("TestUnsignedIntExpressions")
1496{
1497 auto max8 = std::numeric_limits<uint8_t>::max();
1498 auto max16 = std::numeric_limits<uint8_t>::max();
1499 auto max32 = std::numeric_limits<uint8_t>::max();
1500 auto max64 = std::numeric_limits<uint8_t>::max();
1501
1502 TableBuilder b8;
1503 auto writer8 = b8.cursor<o2::aod::UnsignedIntTest8>();
1504 for (uint64_t i = 0; i < max8; i += (max8 / 100)) {
1505 writer8(0, i);
1506 }
1507 auto t8 = b8.finalize();
1508 o2::aod::UnsignedIntTest8 at8{{t8}};
1509
1510 uint8_t limit8 = max8 / 2 + 1;
1511 o2::framework::expressions::Filter test8 = o2::aod::test::guint8 < limit8;
1513
1515
1516 REQUIRE(at8.size() == 128);
1517 REQUIRE(fat8.size() == 64);
1518
1519 TableBuilder b16;
1520 auto writer16 = b16.cursor<o2::aod::UnsignedIntTest16>();
1521 for (uint64_t i = 0; i < max16; i += (max16 / 100)) {
1522 writer16(0, i);
1523 }
1524 auto t16 = b16.finalize();
1525 o2::aod::UnsignedIntTest16 at16{{t16}};
1526
1527 uint16_t limit16 = max16 / 2 + 1;
1528 o2::framework::expressions::Filter test16 = o2::aod::test::guint16 < limit16;
1529 auto s16 = o2::framework::expressions::createSelection(t16, test16);
1530
1532
1533 REQUIRE(at16.size() == 128);
1534 REQUIRE(fat16.size() == 64);
1535
1536 TableBuilder b32;
1537 auto writer32 = b32.cursor<o2::aod::UnsignedIntTest32>();
1538 for (uint64_t i = 0; i < max32; i += (max32 / 100)) {
1539 writer32(0, i);
1540 }
1541 auto t32 = b32.finalize();
1542 o2::aod::UnsignedIntTest32 at32{{t32}};
1543
1544 uint32_t limit32 = max32 / 2 + 1;
1545 o2::framework::expressions::Filter test32 = o2::aod::test::guint32 < limit32;
1546 auto s32 = o2::framework::expressions::createSelection(t32, test32);
1547
1549
1550 REQUIRE(at32.size() == 128);
1551 REQUIRE(fat32.size() == 64);
1552
1553 TableBuilder b64;
1554 auto writer64 = b64.cursor<o2::aod::UnsignedIntTest64>();
1555 for (uint64_t i = 0; i < max64; i += (max64 / 100)) {
1556 writer64(0, i);
1557 }
1558 auto t64 = b64.finalize();
1559 o2::aod::UnsignedIntTest64 at64{{t64}};
1560
1561 uint64_t limit64 = max64 / 2 + 1;
1562 o2::framework::expressions::Filter test64 = o2::aod::test::guint64 < limit64;
1563 auto s64 = o2::framework::expressions::createSelection(t64, test64);
1564
1566
1567 REQUIRE(at64.size() == 128);
1568 REQUIRE(fat64.size() == 64);
1569}
#define DECLARE_SOA_ARRAY_INDEX_COLUMN(_Name_, _Getter_)
Definition ASoA.h:2810
#define DECLARE_SOA_SLICE_INDEX_COLUMN(_Name_, _Getter_)
Definition ASoA.h:2669
#define DECLARE_SOA_DYNAMIC_COLUMN(_Name_, _Getter_,...)
Definition ASoA.h:3118
#define DECLARE_SOA_SELF_INDEX_COLUMN(_Name_, _Getter_)
Definition ASoA.h:2953
#define DECLARE_SOA_TABLE(_Name_, _Origin_, _Desc_,...)
Definition ASoA.h:3206
#define DECLARE_SOA_EXPRESSION_COLUMN(_Name_, _Getter_, _Type_, _Expression_)
Definition ASoA.h:2524
#define DECLARE_SOA_COLUMN(_Name_, _Getter_, _Type_)
Definition ASoA.h:2450
#define DECLARE_SOA_INDEX_COLUMN_FULL(_Name_, _Getter_, _Type_, _Table_, _Suffix_)
Definition ASoA.h:2891
#define DECLARE_SOA_SELF_SLICE_INDEX_COLUMN(_Name_, _Getter_)
Definition ASoA.h:3017
#define DECLARE_SOA_COLUMN_FULL(_Name_, _Getter_, _Type_, _Label_)
Definition ASoA.h:2344
#define DECLARE_SOA_TABLE_VERSIONED(_Name_, _Origin_, _Desc_, _Version_,...)
Definition ASoA.h:3209
#define DECLARE_SOA_INDEX_COLUMN(_Name_, _Getter_)
Definition ASoA.h:2892
#define DECLARE_SOA_BITMAP_COLUMN(_Name_, _Getter_, _Size_)
Definition ASoA.h:2485
#define DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(_Name_, _Getter_)
Definition ASoA.h:3088
std::shared_ptr< arrow::Schema > schema
int32_t i
uint32_t op
const int16_t bb
Test
Definition Utils.h:55
useful math constants
uint16_t pos
Definition RawData.h:3
uint32_t one
Definition RawData.h:4
uint32_t j
Definition RawData.h:0
benchmark::State & st
StringRef key
std::shared_ptr< T > get(const HistName &histName)
auto persist(std::array< char const *, sizeof...(ARGS)+1 > const &columnNames)
std::shared_ptr< arrow::Table > finalize()
void bindInternalIndicesTo(I const *ptr)
Definition ASoA.h:3699
unfiltered_iterator begin()
Definition ASoA.h:2029
auto select(framework::expressions::Filter const &f) const
Definition ASoA.h:2154
#define CHECK
float sum(float s, o2::dcs::DataPointValue v)
Definition dcs-ccdb.cxx:39
GLdouble n
Definition glcorearb.h:1982
GLint GLenum GLint x
Definition glcorearb.h:403
const GLfloat * m
Definition glcorearb.h:4066
GLint GLsizei count
Definition glcorearb.h:399
GLuint color
Definition glcorearb.h:1272
GLuint * ids
Definition glcorearb.h:647
GLuint GLsizei const GLuint const GLintptr const GLsizeiptr * sizes
Definition glcorearb.h:2595
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
Definition glcorearb.h:5034
GLdouble f
Definition glcorearb.h:310
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLint y
Definition glcorearb.h:270
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLintptr offset
Definition glcorearb.h:660
GLuint segments
Definition glcorearb.h:4946
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition glcorearb.h:1308
GLboolean r
Definition glcorearb.h:1233
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLubyte GLubyte GLubyte GLubyte w
Definition glcorearb.h:852
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
Definition glcorearb.h:5034
std::shared_ptr< gandiva::SelectionVector > Selection
Definition Expressions.h:45
constexpr float Almost0
constexpr float PI
gandiva::Selection createSelection(std::shared_ptr< arrow::Table > const &table, Filter const &expression)
Function for creating gandiva selection from our internal filter tree.
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
RuntimeError & error_from_ref(RuntimeErrorRef)
std::string cutString(std::string &&str)
Definition ASoA.cxx:313
auto createFieldsFromColumns(framework::pack< C... >)
Definition ASoA.h:77
constexpr auto join(Ts const &... t)
Definition ASoA.h:3515
std::vector< int64_t > SelectionVector
Definition ASoA.h:444
FIXME: do not use data model tables.
char what[MAX_RUNTIME_ERROR_SIZE]
int64_t lastIndex()
Last index inserted in the table.
bool resetCursor(LifetimeHolder< TableBuilder > builder)
A struct, containing the root of the expression tree.
TEST_CASE("TestMarkers")
Definition test_ASoA.cxx:76
HistogramRegistry foo()
std::vector< int > row