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"
17#include "gandiva/tree_expr_builder.h"
18#include "arrow/status.h"
19#include "gandiva/filter.h"
20#include <catch_amalgamated.hpp>
21#include <arrow/util/key_value_metadata.h>
22
23using namespace o2::framework;
24using namespace arrow;
25using namespace o2::soa;
26
27namespace o2::aod
28{
29namespace test
30{
35DECLARE_SOA_DYNAMIC_COLUMN(Sum, sum, [](int x, int y) { return x + y; });
36DECLARE_SOA_EXPRESSION_COLUMN(ESum, esum, int, test::x + test::y);
37} // namespace test
38
39DECLARE_SOA_TABLE(Points, "TEST", "POINTS", test::X, test::Y);
40DECLARE_SOA_TABLE(Points3Ds, "TEST", "PTS3D", o2::soa::Index<>, test::X, test::Y, test::Z);
41
42DECLARE_SOA_TABLE_VERSIONED(Points3DMk1s, "TEST", "PTS3D", 1, o2::soa::Index<>, o2::soa::Marker<1>, test::X, test::Y, test::Z);
43DECLARE_SOA_TABLE_VERSIONED(Points3DMk2s, "TEST", "PTS3D", 2, o2::soa::Index<>, o2::soa::Marker<2>, test::X, test::Y, test::Z);
44DECLARE_SOA_TABLE_VERSIONED(Points3DMk3s, "TEST", "PTS3D", 3, o2::soa::Index<>, o2::soa::Marker<3>, test::X, test::Y, test::Z);
45
46namespace test
47{
48DECLARE_SOA_COLUMN_FULL(SomeBool, someBool, bool, "someBool");
49DECLARE_SOA_COLUMN_FULL(Color, color, int32_t, "color");
50} // namespace test
51
52DECLARE_SOA_TABLE(Infos, "TEST", "INFOS", test::Color, test::SomeBool);
53
54namespace test
55{
58DECLARE_SOA_INDEX_COLUMN_FULL(PointA, pointA, int, Points, "_A");
59DECLARE_SOA_INDEX_COLUMN_FULL(PointB, pointB, int, Points, "_B");
60DECLARE_SOA_COLUMN_FULL(Thickness, thickness, int, "thickness");
61} // namespace test
62
63DECLARE_SOA_TABLE(Segments, "TEST", "SEGMENTS", test::N, test::PointAId, test::PointBId, test::InfoId);
64DECLARE_SOA_TABLE(SegmentsExtras, "TEST", "SEGMENTSPLUS", test::Thickness);
65
66namespace test
67{
68DECLARE_SOA_COLUMN(L1, l1, std::vector<float>);
69DECLARE_SOA_COLUMN(L2, l2, std::vector<int>);
70} // namespace test
71
72DECLARE_SOA_TABLE(Lists, "TEST", "LISTS", o2::soa::Index<>, test::L1, test::L2);
73} // namespace o2::aod
74
75TEST_CASE("TestMarkers")
76{
78 auto pwriter = b1.cursor<o2::aod::Points3Ds>();
79 for (auto i = 0; i < 20; ++i) {
80 pwriter(0, -1 * i, (int)(i / 2), 2 * i);
81 }
82 auto t1 = b1.finalize();
83
84 auto pt = o2::aod::Points3Ds{t1};
85 auto pt1 = o2::aod::Points3DMk1s{t1};
86 auto pt2 = o2::aod::Points3DMk2s{t1};
87 auto pt3 = o2::aod::Points3DMk3s{t1};
88 REQUIRE(pt1.begin().mark() == (size_t)1);
89 REQUIRE(pt2.begin().mark() == (size_t)2);
90 REQUIRE(pt3.begin().mark() == (size_t)3);
91}
92
93TEST_CASE("TestTableIteration")
94{
95 TableBuilder builder;
96 auto rowWriter = builder.persist<int32_t, int32_t>({"fX", "fY"});
97 rowWriter(0, 0, 0);
98 rowWriter(0, 0, 1);
99 rowWriter(0, 0, 2);
100 rowWriter(0, 0, 3);
101 rowWriter(0, 1, 4);
102 rowWriter(0, 1, 5);
103 rowWriter(0, 1, 6);
104 rowWriter(0, 1, 7);
105 auto table = builder.finalize();
106
107 auto i = ColumnIterator<int32_t>(table->column(0).get());
108 int64_t pos = 0;
109 i.mCurrentPos = &pos;
110 REQUIRE(*i == 0);
111 pos++;
112 REQUIRE(*i == 0);
113 pos++;
114 REQUIRE(*i == 0);
115 pos++;
116 REQUIRE(*i == 0);
117 pos++;
118 REQUIRE(*i == 1);
119 pos++;
120 REQUIRE(*i == 1);
121 pos++;
122 REQUIRE(*i == 1);
123 pos++;
124 REQUIRE(*i == 1);
125
126 arrow::ChunkedArray* chunks[2] = {
127 table->column(0).get(),
128 table->column(1).get()};
129 o2::aod::Points::iterator tests(chunks, {table->num_rows(), 0});
130 REQUIRE(tests.x() == 0);
131 REQUIRE(tests.y() == 0);
132 ++tests;
133 REQUIRE(tests.x() == 0);
134 REQUIRE(tests.y() == 1);
135 using Test = InPlaceTable<"T/0"_h, o2::aod::test::X, o2::aod::test::Y>;
136 Test tests2{table};
137 size_t value = 0;
138 auto b = tests2.begin();
139 auto e = tests2.end();
140 REQUIRE(b != e);
141 ++b;
142 ++b;
143 ++b;
144 ++b;
145 ++b;
146 ++b;
147 ++b;
148 ++b;
149 REQUIRE(b == e);
150
151 b = tests2.begin();
152 REQUIRE(b != e);
153 REQUIRE(((b + 1) == (b + 1)));
154 REQUIRE(((b + 7) != b));
155 REQUIRE(((b + 7) != e));
156 REQUIRE(((b + 8) == e));
157
158 for (auto& t : tests2) {
159 REQUIRE(t.x() == value / 4);
160 REQUIRE((size_t)t.y() == value);
161 REQUIRE(value < 8);
162 value++;
163 }
164
165 for (auto t1 = tests2.begin(); t1 != tests2.end(); ++t1) {
166 for (auto t2 = t1 + 1; t2 != tests2.end(); ++t2) {
167 }
168 }
169}
170
171TEST_CASE("TestDynamicColumns")
172{
173 TableBuilder builder;
174 auto rowWriter = builder.persist<int32_t, int32_t>({"fX", "fY"});
175 rowWriter(0, 0, 0);
176 rowWriter(0, 0, 1);
177 rowWriter(0, 0, 2);
178 rowWriter(0, 0, 3);
179 rowWriter(0, 1, 4);
180 rowWriter(0, 1, 5);
181 rowWriter(0, 1, 6);
182 rowWriter(0, 1, 7);
183 auto table = builder.finalize();
184
185 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>>;
186
187 Test1 tests1{table};
188 for (auto& test : tests1) {
189 REQUIRE(test.sum() == (test.x() + test.y()));
190 }
191
192 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>>;
193
194 Test2 tests2{table};
195 for (auto& test : tests2) {
196 CHECK(test.sum() == (test.y() + test.y()));
197 }
198}
199
200TEST_CASE("TestColumnIterators")
201{
202 TableBuilder builder;
203 auto rowWriter = builder.persist<int32_t, int32_t>({"fX", "fY"});
204 rowWriter(0, 0, 0);
205 rowWriter(0, 0, 1);
206 rowWriter(0, 0, 2);
207 rowWriter(0, 0, 3);
208 rowWriter(0, 1, 4);
209 rowWriter(0, 1, 5);
210 rowWriter(0, 1, 6);
211 rowWriter(0, 1, 7);
212 auto table = builder.finalize();
213
214 int64_t index1 = 0;
215 int64_t index2 = 0;
216 ColumnIterator<int32_t> foo{table->column(1).get()};
217 foo.mCurrentPos = &index1;
218 auto bar{foo};
219 bar.mCurrentPos = &index2;
220 REQUIRE(foo.mCurrent == bar.mCurrent);
221 REQUIRE(foo.mLast == bar.mLast);
222 REQUIRE(foo.mColumn == bar.mColumn);
223 REQUIRE(foo.mFirstIndex == bar.mFirstIndex);
224 REQUIRE(foo.mCurrentChunk == bar.mCurrentChunk);
225
226 auto foobar = std::move(foo);
227 REQUIRE(foobar.mCurrent == bar.mCurrent);
228 REQUIRE(foobar.mLast == bar.mLast);
229 REQUIRE(foobar.mColumn == bar.mColumn);
230 REQUIRE(foobar.mFirstIndex == bar.mFirstIndex);
231 REQUIRE(foobar.mCurrentChunk == bar.mCurrentChunk);
232}
233
234TEST_CASE("TestJoinedTables")
235{
236 TableBuilder builderX;
237 auto rowWriterX = builderX.persist<int32_t>({"fX"});
238 rowWriterX(0, 0);
239 rowWriterX(0, 1);
240 rowWriterX(0, 2);
241 rowWriterX(0, 3);
242 rowWriterX(0, 4);
243 rowWriterX(0, 5);
244 rowWriterX(0, 6);
245 rowWriterX(0, 7);
246 auto tableX = builderX.finalize();
247
248 TableBuilder builderY;
249 auto rowWriterY = builderY.persist<int32_t>({"fY"});
250 rowWriterY(0, 7);
251 rowWriterY(0, 6);
252 rowWriterY(0, 5);
253 rowWriterY(0, 4);
254 rowWriterY(0, 3);
255 rowWriterY(0, 2);
256 rowWriterY(0, 1);
257 rowWriterY(0, 0);
258 auto tableY = builderY.finalize();
259
260 TableBuilder builderZ;
261 auto rowWriterZ = builderZ.persist<int32_t>({"fZ"});
262 rowWriterZ(0, 8);
263 rowWriterZ(0, 8);
264 rowWriterZ(0, 8);
265 rowWriterZ(0, 8);
266 rowWriterZ(0, 8);
267 rowWriterZ(0, 8);
268 rowWriterZ(0, 8);
269 rowWriterZ(0, 8);
270 auto tableZ = builderZ.finalize();
271
272 TableBuilder builderW;
273 auto rowWriterW = builderW.persist<int32_t>({"fW"});
274 rowWriterW(0, 8);
275 rowWriterW(0, 8);
276 rowWriterW(0, 8);
277 auto tableW = builderW.finalize();
278
279 using TestX = InPlaceTable<"A0"_h, o2::aod::test::X>;
280 using TestY = InPlaceTable<"A1"_h, o2::aod::test::Y>;
281 using TestZ = InPlaceTable<"A2"_h, o2::aod::test::Z>;
282 using TestW = InPlaceTable<"A3"_h, o2::aod::test::W>;
283 using Test = Join<TestX, TestY>;
284
285 REQUIRE(Test::contains<TestX>());
286 REQUIRE(Test::contains<TestY>());
287 REQUIRE(!Test::contains<TestZ>());
288
289 Test tests{{tableX, tableY}, 0};
290
291 REQUIRE(tests.contains<TestX>());
292 REQUIRE(tests.contains<TestY>());
293 REQUIRE(!tests.contains<TestZ>());
294
295 for (auto& test : tests) {
296 REQUIRE(7 == test.x() + test.y());
297 }
298
299 auto tests2 = join(TestX{tableX}, TestY{tableY});
300 static_assert(std::same_as<Test::self_t, decltype(tests2)>, "Joined tables should have the same type, regardless how we construct them");
301 for (auto& test : tests2) {
302 REQUIRE(7 == test.x() + test.y());
303 }
304
305 auto tests3 = join(TestX{tableX}, TestY{tableY}, TestZ{tableZ});
306
307 for (auto& test : tests3) {
308 REQUIRE(15 == test.x() + test.y() + test.z());
309 }
310 using TestMoreThanTwo = Join<TestX, TestY, TestZ>;
311 TestMoreThanTwo tests4{{tableX, tableY, tableZ}, 0};
312 for (auto& test : tests4) {
313 REQUIRE(15 == test.x() + test.y() + test.z());
314 }
315
316 try {
317 auto testF = join(TestZ{tableZ}, TestW{tableW});
318 } catch (RuntimeErrorRef ref) {
319 REQUIRE(std::string{error_from_ref(ref).what} == "Tables TEST and TEST have different sizes (8 vs 3) and cannot be joined!");
320 }
321}
322
323TEST_CASE("TestConcatTables")
324{
325 TableBuilder builderA;
326 auto rowWriterA = builderA.persist<int32_t, int32_t>({"fX", "fY"});
327 rowWriterA(0, 0, 0);
328 rowWriterA(0, 1, 0);
329 rowWriterA(0, 2, 0);
330 rowWriterA(0, 3, 0);
331 rowWriterA(0, 4, 0);
332 rowWriterA(0, 5, 0);
333 rowWriterA(0, 6, 0);
334 rowWriterA(0, 7, 0);
335 auto tableA = builderA.finalize();
336 REQUIRE(tableA->num_rows() == 8);
337
338 TableBuilder builderB;
339 auto rowWriterB = builderB.persist<int32_t>({"fX"});
340 rowWriterB(0, 8);
341 rowWriterB(0, 9);
342 rowWriterB(0, 10);
343 rowWriterB(0, 11);
344 rowWriterB(0, 12);
345 rowWriterB(0, 13);
346 rowWriterB(0, 14);
347 rowWriterB(0, 15);
348 auto tableB = builderB.finalize();
349
350 TableBuilder builderC;
351 auto rowWriterC = builderC.persist<int32_t>({"fZ"});
352 rowWriterC(0, 8);
353 rowWriterC(0, 9);
354 rowWriterC(0, 10);
355 rowWriterC(0, 11);
356 rowWriterC(0, 12);
357 rowWriterC(0, 13);
358 rowWriterC(0, 14);
359 rowWriterC(0, 15);
360 auto tableC = builderC.finalize();
361
362 TableBuilder builderD;
363 auto rowWriterD = builderD.persist<int32_t, int32_t>({"fX", "fZ"});
364 rowWriterD(0, 16, 8);
365 rowWriterD(0, 17, 9);
366 rowWriterD(0, 18, 10);
367 rowWriterD(0, 19, 11);
368 rowWriterD(0, 20, 12);
369 rowWriterD(0, 21, 13);
370 rowWriterD(0, 22, 14);
371 rowWriterD(0, 23, 15);
372 auto tableD = builderD.finalize();
373
374 using TestA = InPlaceTable<0, o2::soa::Index<>, o2::aod::test::X, o2::aod::test::Y>; // o2::aod::TestA;
375 using TestB = InPlaceTable<0, o2::soa::Index<>, o2::aod::test::X>; // o2::aod::TestB;
376 using TestC = InPlaceTable<0, o2::aod::test::Z>; // o2::aod::TestC;
377 using TestD = InPlaceTable<0, o2::aod::test::X, o2::aod::test::Z>; // o2::aod::TestD;
378 using ConcatTest = Concat<TestA, TestB>;
379 using JoinedTest = Join<TestA, TestC>;
380 using NestedJoinTest = Join<JoinedTest, TestD>;
381 using NestedConcatTest = Concat<Join<TestA, TestB>, TestD>;
382
383 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");
384
385 static_assert(std::same_as<ConcatTest::columns_t, o2::framework::pack<o2::soa::Index<>, o2::aod::test::X>>, "Bad intersection of columns");
386 ConcatTest tests{tableA, tableB};
387 REQUIRE(16 == tests.size());
388 for (auto& test : tests) {
389 REQUIRE(test.index() == test.x());
390 }
391
392 static_assert(std::same_as<NestedConcatTest::columns_t, o2::framework::pack<o2::aod::test::X>>, "Bad nested concat");
393
394 // Hardcode a selection for the first 5 odd numbers
395 using FilteredTest = Filtered<TestA>;
396 using namespace o2::framework;
397 expressions::Filter testf = (o2::aod::test::x == 1) || (o2::aod::test::x == 3);
398 gandiva::Selection selection;
399 auto status = gandiva::SelectionVector::MakeInt64(tests.size(), arrow::default_memory_pool(), &selection);
400 REQUIRE(status.ok());
401
402 auto fptr = tableA->schema()->GetFieldByName("fX");
403 REQUIRE(fptr != nullptr);
404 REQUIRE(fptr->name() == "fX");
405 REQUIRE(fptr->type()->id() == arrow::Type::INT32);
406
407 auto node_x = gandiva::TreeExprBuilder::MakeField(fptr);
408 auto literal_1 = gandiva::TreeExprBuilder::MakeLiteral(static_cast<int32_t>(1));
409 auto literal_3 = gandiva::TreeExprBuilder::MakeLiteral(static_cast<int32_t>(3));
410 auto equals_to_1 = gandiva::TreeExprBuilder::MakeFunction("equal", {node_x, literal_1}, arrow::boolean());
411 auto equals_to_3 = gandiva::TreeExprBuilder::MakeFunction("equal", {node_x, literal_3}, arrow::boolean());
412 auto node_or = gandiva::TreeExprBuilder::MakeOr({equals_to_1, equals_to_3});
413 auto condition = gandiva::TreeExprBuilder::MakeCondition(node_or);
414 REQUIRE(condition->ToString() == "bool equal((int32) fX, (const int32) 1) || bool equal((int32) fX, (const int32) 3)");
415 std::shared_ptr<gandiva::Filter> filter;
416 status = gandiva::Filter::Make(tableA->schema(), condition, &filter);
417 REQUIRE(status.ToString() == "OK");
418
419 arrow::TableBatchReader reader(*tableA);
420 std::shared_ptr<RecordBatch> batch;
421 auto s = reader.ReadNext(&batch);
422 REQUIRE(s.ok());
423 REQUIRE(batch != nullptr);
424 REQUIRE(batch->num_rows() == 8);
425 auto st = filter->Evaluate(*batch, selection);
426 REQUIRE(st.ToString() == "OK");
427
428 gandiva::Selection selection_f = expressions::createSelection(tableA, testf);
429
430 TestA testA{tableA};
431 FilteredTest filtered{{testA.asArrowTable()}, selection_f};
432 REQUIRE(2 == filtered.size());
433
434 auto i = 0;
435 REQUIRE(filtered.begin() != filtered.end());
436 for (auto& f : filtered) {
437 REQUIRE(i * 2 + 1 == f.x());
438 REQUIRE(i * 2 + 1 == f.index());
439 i++;
440 }
441 REQUIRE(i == 2);
442
443 // Hardcode a selection for the first 5 odd numbers
444 using FilteredConcatTest = Filtered<ConcatTest::table_t>;
445 using namespace o2::framework;
446 gandiva::Selection selectionConcat;
447 status = gandiva::SelectionVector::MakeInt64(tests.size(), arrow::default_memory_pool(), &selectionConcat);
448 REQUIRE(status.ok() == true);
449 selectionConcat->SetIndex(0, 0);
450 selectionConcat->SetIndex(1, 5);
451 selectionConcat->SetIndex(2, 10);
452 selectionConcat->SetNumSlots(3);
453 ConcatTest concatTest{tableA, tableB};
454 FilteredConcatTest concatTestTable{{concatTest.asArrowTable()}, selectionConcat};
455 REQUIRE(3 == concatTestTable.size());
456
457 i = 0;
458 auto b = concatTestTable.begin();
459 auto e = concatTestTable.end();
460
461 REQUIRE(b.mRowIndex == 0);
462 REQUIRE(b.getSelectionRow() == 0);
463 REQUIRE(e.index == 3);
464
465 REQUIRE(concatTestTable.begin() != concatTestTable.end());
466 for (auto& f : concatTestTable) {
467 REQUIRE(i * 5 == f.x());
468 REQUIRE(i * 5 == f.index());
469 REQUIRE(i == f.filteredIndex());
470 i++;
471 }
472 REQUIRE(i == 3);
473
474 // Test with a Joined table
475 using FilteredJoinTest = Filtered<JoinedTest::table_t>;
476 gandiva::Selection selectionJoin;
477 status = gandiva::SelectionVector::MakeInt64(tests.size(), arrow::default_memory_pool(), &selectionJoin);
478 REQUIRE(status.ok() == true);
479 selectionJoin->SetIndex(0, 0);
480 selectionJoin->SetIndex(1, 2);
481 selectionJoin->SetIndex(2, 4);
482 selectionJoin->SetNumSlots(3);
483 JoinedTest testJoin{{tableA, tableC}, 0};
484 FilteredJoinTest filteredJoin{{testJoin.asArrowTable()}, selectionJoin};
485
486 i = 0;
487 REQUIRE(filteredJoin.begin() != filteredJoin.end());
488 for (auto& f : filteredJoin) {
489 REQUIRE(i * 2 == f.x());
490 REQUIRE(i * 2 == f.index());
491 i++;
492 }
493 REQUIRE(i == 3);
494}
495
496TEST_CASE("TestDereference")
497{
498 TableBuilder builderA;
499 auto pointsWriter = builderA.cursor<o2::aod::Points>();
500 pointsWriter(0, 0, 0);
501 pointsWriter(0, 3, 4);
502 auto pointsT = builderA.finalize();
503 o2::aod::Points points{pointsT};
504 REQUIRE(pointsT->num_rows() == 2);
505
506 TableBuilder builderA2;
507 auto infoWriter = builderA2.cursor<o2::aod::Infos>();
508 infoWriter(0, 0, true);
509 infoWriter(0, 1, false);
510 infoWriter(0, 4, true);
511 auto infosT = builderA2.finalize();
512 o2::aod::Infos infos{infosT};
513 REQUIRE(infos.begin().someBool() == true);
514 REQUIRE((infos.begin() + 1).someBool() == false);
515 REQUIRE((infos.begin() + 2).someBool() == true);
516 REQUIRE((infos.begin() + 2).color() == 4);
517 REQUIRE(infosT->num_rows() == 3);
518
519 TableBuilder builderB;
520 auto segmentsWriter = builderB.cursor<o2::aod::Segments>();
521 segmentsWriter(0, 10, 0, 1, 2);
522 auto segmentsT = builderB.finalize();
523 o2::aod::Segments segments{segmentsT};
524 REQUIRE(segmentsT->num_rows() == 1);
525
526 TableBuilder builderC;
527 auto segmentsExtraWriter = builderC.cursor<o2::aod::SegmentsExtras>();
528 segmentsExtraWriter(0, 1);
529 auto segmentsExtraT = builderC.finalize();
530 o2::aod::SegmentsExtras segmentsExtras{segmentsExtraT};
531 REQUIRE(segmentsExtraT->num_rows() == 1);
532
533 REQUIRE(segments.begin().pointAId() == 0);
534 REQUIRE(segments.begin().pointBId() == 1);
535 static_assert(std::same_as<decltype(segments.begin().pointA()), o2::aod::Points::iterator>);
536 auto i = segments.begin();
537 using namespace o2::framework;
538 i.bindExternalIndices(&points, &infos);
539 REQUIRE(i.n() == 10);
540 REQUIRE(i.info().color() == 4);
541 REQUIRE(i.info().someBool() == true);
542 REQUIRE(i.pointA().x() == 0);
543 REQUIRE(i.pointA().y() == 0);
544 REQUIRE(i.pointB().x() == 3);
545 REQUIRE(i.pointB().y() == 4);
546
547 segments.bindExternalIndices(&points, &infos);
548 auto j = segments.begin();
549 REQUIRE(j.n() == 10);
550 REQUIRE(j.info().color() == 4);
551 REQUIRE(j.info().someBool() == true);
552 REQUIRE(j.pointA().x() == 0);
553 REQUIRE(j.pointA().y() == 0);
554 REQUIRE(j.pointB().x() == 3);
555 REQUIRE(j.pointB().y() == 4);
556
557 auto joined = join(segments, segmentsExtras);
558 joined.bindExternalIndices(&points, &infos);
559 auto se = joined.begin();
560 REQUIRE(se.n() == 10);
561 REQUIRE(se.info().color() == 4);
562 REQUIRE(se.pointA().x() == 0);
563 REQUIRE(se.pointA().y() == 0);
564 REQUIRE(se.pointB().x() == 3);
565 REQUIRE(se.pointB().y() == 4);
566 REQUIRE(se.thickness() == 1);
567}
568
569TEST_CASE("TestSchemaCreation")
570{
571 auto schema = std::make_shared<arrow::Schema>(createFieldsFromColumns(o2::aod::Points::persistent_columns_t{}));
572 REQUIRE(schema->num_fields() == 2);
573 REQUIRE(schema->field(0)->name() == "fX");
574 REQUIRE(schema->field(1)->name() == "fY");
575}
576
577TEST_CASE("TestFilteredOperators")
578{
579 TableBuilder builderA;
580 auto rowWriterA = builderA.persist<int32_t, int32_t>({"fX", "fY"});
581 rowWriterA(0, 0, 8);
582 rowWriterA(0, 1, 9);
583 rowWriterA(0, 2, 10);
584 rowWriterA(0, 3, 11);
585 rowWriterA(0, 4, 12);
586 rowWriterA(0, 5, 13);
587 rowWriterA(0, 6, 14);
588 rowWriterA(0, 7, 15);
589 auto tableA = builderA.finalize();
590 REQUIRE(tableA->num_rows() == 8);
591
592 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>;
593 using FilteredTest = Filtered<TestA>;
594 using namespace o2::framework;
595
596 expressions::Filter f1 = o2::aod::test::x < 4;
597 expressions::Filter f2 = o2::aod::test::y > 13;
598
599 TestA testA{tableA};
600 auto s1 = expressions::createSelection(testA.asArrowTable(), f1);
601 FilteredTest filtered1{{testA.asArrowTable()}, s1};
602 REQUIRE(4 == filtered1.size());
603 REQUIRE(filtered1.begin() != filtered1.end());
604
605 auto s2 = expressions::createSelection(testA.asArrowTable(), f2);
606 FilteredTest filtered2{{testA.asArrowTable()}, s2};
607 REQUIRE(2 == filtered2.size());
608 REQUIRE(filtered2.begin() != filtered2.end());
609
610 FilteredTest filteredUnion = filtered1 + filtered2;
611 REQUIRE(6 == filteredUnion.size());
612
613 std::vector<std::tuple<int32_t, int32_t>> expectedUnion{{0, 8}, {1, 9}, {2, 10}, {3, 11}, {6, 14}, {7, 15}};
614 auto i = 0;
615 for (auto& f : filteredUnion) {
616 REQUIRE(std::get<0>(expectedUnion[i]) == f.x());
617 REQUIRE(std::get<1>(expectedUnion[i]) == f.y());
618 REQUIRE(std::get<0>(expectedUnion[i]) == f.index());
619 i++;
620 }
621 REQUIRE(i == 6);
622
623 FilteredTest filteredIntersection = filtered1 * filtered2;
624 REQUIRE(0 == filteredIntersection.size());
625
626 i = 0;
627 for (auto const& _ : filteredIntersection) {
628 i++;
629 }
630 REQUIRE(i == 0);
631
632 expressions::Filter f3 = o2::aod::test::x < 3;
633 auto s3 = expressions::createSelection(testA.asArrowTable(), f3);
634 FilteredTest filtered3{{testA.asArrowTable()}, s3};
635 REQUIRE(3 == filtered3.size());
636 REQUIRE(filtered3.begin() != filtered3.end());
637
638 FilteredTest unionIntersection = (filtered1 + filtered2) * filtered3;
639 REQUIRE(3 == unionIntersection.size());
640
641 i = 0;
642 for (auto& f : unionIntersection) {
643 REQUIRE(i == f.x());
644 REQUIRE(i + 8 == f.y());
645 REQUIRE(i == f.index());
646 i++;
647 }
648 REQUIRE(i == 3);
649}
650
651TEST_CASE("TestNestedFiltering")
652{
653 TableBuilder builderA;
654 auto rowWriterA = builderA.persist<int32_t, int32_t>({"fX", "fY"});
655 rowWriterA(0, 0, 8);
656 rowWriterA(0, 1, 9);
657 rowWriterA(0, 2, 10);
658 rowWriterA(0, 3, 11);
659 rowWriterA(0, 4, 12);
660 rowWriterA(0, 5, 13);
661 rowWriterA(0, 6, 14);
662 rowWriterA(0, 7, 15);
663 auto tableA = builderA.finalize();
664 REQUIRE(tableA->num_rows() == 8);
665
666 using TestA = InPlaceTable<0, o2::soa::Index<>, o2::aod::test::X, o2::aod::test::Y>;
667 using FilteredTest = Filtered<TestA>;
668 using NestedFilteredTest = Filtered<Filtered<TestA>>;
669 using TripleNestedFilteredTest = Filtered<Filtered<Filtered<TestA>>>;
670 using namespace o2::framework;
671
672 expressions::Filter f1 = o2::aod::test::x < 4;
673 expressions::Filter f2 = o2::aod::test::y > 9;
674 expressions::Filter f3 = o2::aod::test::x < 3;
675
676 TestA testA{tableA};
677 auto s1 = expressions::createSelection(testA.asArrowTable(), f1);
678 FilteredTest filtered{{testA.asArrowTable()}, s1};
679 REQUIRE(4 == filtered.size());
680 REQUIRE(filtered.begin() != filtered.end());
681
682 auto s2 = expressions::createSelection(filtered.asArrowTable(), f2);
683 NestedFilteredTest nestedFiltered{{filtered}, s2};
684 REQUIRE(2 == nestedFiltered.size());
685 auto i = 0;
686 for (auto& f : nestedFiltered) {
687 REQUIRE(i + 2 == f.x());
688 REQUIRE(i + 10 == f.y());
689 REQUIRE(i + 2 == f.index());
690 i++;
691 }
692 REQUIRE(i == 2);
693
694 auto s3 = expressions::createSelection(nestedFiltered.asArrowTable(), f3);
695 TripleNestedFilteredTest tripleFiltered{{nestedFiltered}, s3};
696 REQUIRE(1 == tripleFiltered.size());
697 i = 0;
698 for (auto& f : tripleFiltered) {
699 REQUIRE(i + 2 == f.x());
700 REQUIRE(i + 10 == f.y());
701 REQUIRE(i + 2 == f.index());
702 i++;
703 }
704 REQUIRE(i == 1);
705}
706
707TEST_CASE("TestEmptyTables")
708{
709 TableBuilder bPoints;
710 [[maybe_unused]] auto pwriter = bPoints.cursor<o2::aod::Points>();
711 auto pempty = bPoints.finalize();
712
713 TableBuilder bInfos;
714 [[maybe_unused]] auto iwriter = bInfos.cursor<o2::aod::Infos>();
715 auto iempty = bInfos.finalize();
716
717 o2::aod::Points p{pempty};
718 o2::aod::Infos i{iempty};
719
721 PI pi{{pempty, iempty}, 0};
722 REQUIRE(pi.size() == 0);
723 auto spawned = Extend<o2::aod::Points, o2::aod::test::ESum>(p);
724 REQUIRE(spawned.size() == 0);
725}
726
727namespace o2::aod
728{
729DECLARE_SOA_TABLE(Origints, "TEST", "ORIG", o2::soa::Index<>, test::X, test::SomeBool);
730namespace test
731{
732DECLARE_SOA_INDEX_COLUMN(Origint, origint);
733DECLARE_SOA_INDEX_COLUMN_FULL(AltOrigint, altOrigint, int, Origints, "_alt");
735} // namespace test
736
737DECLARE_SOA_TABLE(References, "TEST", "REFS", o2::soa::Index<>, test::OrigintId);
738DECLARE_SOA_TABLE(OtherReferences, "TEST", "OREFS", o2::soa::Index<>, test::AltOrigintId);
739DECLARE_SOA_TABLE(ManyReferences, "TEST", "MREFS", o2::soa::Index<>, test::OrigintIds);
740} // namespace o2::aod
741
742TEST_CASE("TestIndexToFiltered")
743{
745 auto writer = b.cursor<o2::aod::Origints>();
746 for (auto i = 0; i < 20; ++i) {
747 writer(0, i, i % 3 == 0);
748 }
749 auto origins = b.finalize();
750 o2::aod::Origints o{origins};
751
753 auto writer_z = z.cursor<o2::aod::ManyReferences>();
754 std::vector<int> ids;
755 for (auto i = 0; i < 5; ++i) {
756 ids.clear();
757 for (auto j = 0; j < 20; ++j) {
758 ids.push_back(j);
759 }
760 writer_z(0, ids);
761 }
762 auto mrefs = z.finalize();
763 o2::aod::ManyReferences m{mrefs};
764
766 auto writer_w = w.cursor<o2::aod::References>();
767 for (auto i = 0; i < 5 * 20; ++i) {
768 writer_w(0, i % 20);
769 }
770 auto refs = w.finalize();
771 o2::aod::References r{refs};
772 expressions::Filter flt = o2::aod::test::someBool == true;
774 auto selection = expressions::createSelection(o.asArrowTable(), flt);
775 Flt f{{o.asArrowTable()}, selection};
776 r.bindExternalIndices(&f);
777 auto it = r.begin();
778 it.moveByIndex(23);
779 REQUIRE(it.origint_as<Flt>().globalIndex() == 3);
780 it++;
781 REQUIRE(it.origint_as<Flt>().globalIndex() == 4);
782 it++;
783 REQUIRE(it.origint_as<Flt>().globalIndex() == 5);
784
785 m.bindExternalIndices(&f);
786 for (auto const& row : m) {
787 auto os = row.origints_as<Flt>();
788 auto fos = row.filtered_origints_as<Flt>();
789 REQUIRE(os.size() == 20);
790 REQUIRE(fos.size() == 6);
791 }
792}
793namespace o2::aod
794{
795namespace test
796{
797DECLARE_SOA_INDEX_COLUMN_FULL(SinglePoint, singlePoint, int32_t, Points3Ds, "");
798DECLARE_SOA_ARRAY_INDEX_COLUMN(Points3D, pointGroup);
799DECLARE_SOA_SLICE_INDEX_COLUMN(Points3D, pointSlice);
800DECLARE_SOA_SELF_INDEX_COLUMN(OtherPoint, otherPoint);
803} // namespace test
804
805DECLARE_SOA_TABLE(PointsRef, "TEST", "PTSREF", test::Points3DIdSlice, test::Points3DIds);
806DECLARE_SOA_TABLE(PointsRefF, "TEST", "PTSREFF", test::SinglePointId, test::Points3DIdSlice, test::Points3DIds);
807DECLARE_SOA_TABLE(PointsSelfIndex, "TEST", "PTSSLF", o2::soa::Index<>, test::X, test::Y, test::Z, test::OtherPointId,
808 test::PointSeqIdSlice, test::PointSetIds);
809} // namespace o2::aod
810
811TEST_CASE("TestAdvancedIndices")
812{
814 auto pwriter = b1.persist<int, int, int>({"fX", "fY", "fZ"});
815 for (auto i = 0; i < 20; ++i) {
816 pwriter(0, -1 * i, (int)(i / 2), 2 * i);
817 }
818 auto tpts1 = b1.finalize();
819
820 TableBuilder b2;
821 auto prwriter = b2.cursor<o2::aod::PointsRef>();
822 auto a = std::array{0, 1};
823 auto aa = std::vector{2, 3, 4};
824 prwriter(0, &a[0], aa);
825 a = {4, 10};
826 aa = {12, 2, 19};
827 prwriter(0, &a[0], aa);
828 auto t2 = b2.finalize();
829
830 auto pt = o2::aod::Points3Ds{tpts1};
831 auto prt = o2::aod::PointsRef{t2};
832 prt.bindExternalIndices(&pt);
833
834 auto it = prt.begin();
835 auto s1 = it.pointSlice();
836 auto g1 = it.pointGroup();
837 auto bb = std::same_as<decltype(s1), o2::aod::Points3Ds>;
838 REQUIRE(bb);
839 REQUIRE(s1.size() == 2);
840 aa = {2, 3, 4};
841 for (int i = 0; i < 3; ++i) {
842 REQUIRE(g1[i].globalIndex() == aa[i]);
843 }
844
845 // Check the X coordinate of the points in the pointGroup
846 // for the first point.
847 for (auto& p : it.pointGroup_as<o2::aod::Points3Ds>()) {
848 REQUIRE(p.x() == -1 * p.globalIndex());
849 }
850
851 ++it;
852 auto s2 = it.pointSlice();
853 auto g2 = it.pointGroup();
854 REQUIRE(s2.size() == 7);
855 aa = {12, 2, 19};
856 for (int i = 0; i < 3; ++i) {
857 REQUIRE(g2[i].globalIndex() == aa[i]);
858 }
859
861 expressions::Filter fltx = (o2::aod::test::x <= -6);
862 Flt f{{tpts1}, expressions::createSelection(tpts1, fltx)};
863 prt.bindExternalIndices(&f);
864
865 auto it2 = prt.begin();
866 auto s1f = it2.pointSlice_as<Flt>();
867 auto g1f = it2.pointGroup_as<Flt>();
868 REQUIRE(s1f.size() == 2);
869 aa = {2, 3, 4};
870 for (int i = 0; i < 3; ++i) {
871 REQUIRE(g1f[i].globalIndex() == aa[i]);
872 }
873
874 ++it2;
875 auto s2f = it2.pointSlice_as<Flt>();
876 auto g2f = it2.pointGroup_as<Flt>();
877 REQUIRE(s2f.size() == 7);
878 aa = {12, 2, 19};
879 for (int i = 0; i < 3; ++i) {
880 REQUIRE(g2f[i].globalIndex() == aa[i]);
881 }
882
883 TableBuilder b3;
884 auto pswriter = b3.cursor<o2::aod::PointsSelfIndex>();
885 int references[] = {19, 2, 0, 13, 4, 6, 5, 5, 11, 9, 3, 8, 16, 14, 1, 18, 12, 18, 2, 7};
886 int slice[2] = {-1, -1};
887 std::vector<int> pset;
888 std::array<int, 4> withSlices = {3, 6, 13, 19};
889 std::array<std::pair<int, int>, 4> bounds = {std::pair{1, 5}, std::pair{3, 3}, std::pair{11, 11}, std::pair{10, 18}};
890 std::array<int, 4> withSets = {0, 1, 13, 14};
891 unsigned int sizes[] = {3, 1, 5, 4};
892 unsigned int c1 = 0;
893 unsigned int c2 = 0;
894 for (auto i = 0; i < 20; ++i) {
895 pset.clear();
896 slice[0] = -1;
897 slice[1] = -1;
898 if (c1 < withSlices.size() && i == withSlices[c1]) {
899 slice[0] = bounds[c1].first;
900 slice[1] = bounds[c1].second;
901 ++c1;
902 }
903 if (c2 < withSets.size() && i == withSets[c2]) {
904 for (auto z = 0U; z < sizes[c2]; ++z) {
905 pset.push_back(i + 1 + z);
906 }
907 ++c2;
908 }
909 pswriter(0, -1 * i, 0.5 * i, 2 * i, references[i], slice, pset);
910 }
911 auto t3 = b3.finalize();
912 auto pst = o2::aod::PointsSelfIndex{t3};
913 pst.bindInternalIndicesTo(&pst);
914 auto i = 0;
915 c1 = 0;
916 c2 = 0;
917 for (auto& p : pst) {
918 auto op = p.otherPoint_as<o2::aod::PointsSelfIndex>();
919 auto bbb = std::same_as<decltype(op), o2::aod::PointsSelfIndex::iterator>;
920 REQUIRE(bbb);
921 REQUIRE(op.globalIndex() == references[i]);
922
923 auto ops = p.pointSeq_as<o2::aod::PointsSelfIndex>();
924 auto bbbs = std::same_as<decltype(ops), o2::aod::PointsSelfIndex>;
925 REQUIRE(bbbs);
926
927 if (i == withSlices[c1]) {
928 auto it = ops.begin();
929 REQUIRE(ops.size() == bounds[c1].second - bounds[c1].first + 1);
930 REQUIRE(it.globalIndex() == bounds[c1].first);
931 for (auto j = 1; j < ops.size(); ++j) {
932 ++it;
933 }
934 REQUIRE(it.globalIndex() == bounds[c1].second);
935 ++c1;
936 } else {
937 REQUIRE(ops.size() == 0);
938 }
939
940 auto opss = p.pointSet_as<o2::aod::PointsSelfIndex>();
941 auto bbba = std::same_as<decltype(opss), std::vector<o2::aod::PointsSelfIndex::iterator>>;
942 REQUIRE(bbba);
943
944 auto opss_ids = p.pointSetIds();
945 if (c2 < withSets.size() && i == withSets[c2]) {
946 REQUIRE(opss.size() == sizes[c2]);
947 REQUIRE(opss.begin()->globalIndex() == i + 1);
948 REQUIRE(opss.back().globalIndex() == i + sizes[c2]);
949 int c3 = 0;
950 for (auto& id : opss_ids) {
951 REQUIRE(id == i + 1 + c3);
952 ++c3;
953 }
954 ++c2;
955 } else {
956 REQUIRE(opss.size() == 0);
957 }
958 ++i;
959 }
960}
961
962namespace o2::aod
963{
964DECLARE_SOA_TABLE(PointsSelfRef, "TEST", "PTSSR", test::OtherPointId, test::PointSeqIdSlice, test::PointSetIds);
965} // namespace o2::aod
966
967TEST_CASE("TestSelfIndexRecursion")
968{
969 TableBuilder b3;
970 auto pswriter = b3.cursor<o2::aod::PointsSelfIndex>();
971 int references[] = {19, 2, 0, 13, 4, 6, 5, 5, 11, 9, 3, 8, 16, 14, 1, 18, 12, 18, 2, 7};
972 int slice[2] = {-1, -1};
973 std::vector<int> pset;
974 std::array<int, 4> withSlices = {3, 6, 13, 19};
975 std::array<std::pair<int, int>, 4> bounds = {std::pair{1, 5}, std::pair{3, 3}, std::pair{11, 11}, std::pair{10, 18}};
976 std::array<int, 4> withSets = {0, 1, 13, 14};
977 unsigned int sizes[] = {3, 1, 5, 4};
978 unsigned int c1 = 0;
979 unsigned int c2 = 0;
980 for (auto i = 0; i < 20; ++i) {
981 pset.clear();
982 slice[0] = -1;
983 slice[1] = -1;
984 if (c1 < withSlices.size() && i == withSlices[c1]) {
985 slice[0] = bounds[c1].first;
986 slice[1] = bounds[c1].second;
987 ++c1;
988 }
989 if (c2 < withSets.size() && i == withSets[c2]) {
990 for (auto z = 0U; z < sizes[c2]; ++z) {
991 pset.push_back(i + 1 + z);
992 }
993 ++c2;
994 }
995 pswriter(0, -1 * i, 0.5 * i, 2 * i, references[i], slice, pset);
996 }
997 auto t3 = b3.finalize();
998 auto pst = o2::aod::PointsSelfIndex{t3};
999 pst.bindInternalIndicesTo(&pst);
1000
1001 // FIXME: only 4 levels of recursive self-index dereference are tested
1002 for (auto& p : pst) {
1003 auto ops = p.pointSeq_as<o2::aod::PointsSelfIndex>();
1004 for (auto& pp : ops) {
1005 auto bpp = std::same_as<std::decay_t<decltype(pp)>, o2::aod::PointsSelfIndex::iterator>;
1006 REQUIRE(bpp);
1007 auto opps = pp.pointSeq_as<o2::aod::PointsSelfIndex>();
1008 for (auto& ppp : opps) {
1009 auto bppp = std::same_as<std::decay_t<decltype(ppp)>, o2::aod::PointsSelfIndex::iterator>;
1010 REQUIRE(bppp);
1011 auto oppps = ppp.pointSeq_as<o2::aod::PointsSelfIndex>();
1012 for (auto& pppp : oppps) {
1013 auto bpppp = std::same_as<std::decay_t<decltype(pppp)>, o2::aod::PointsSelfIndex::iterator>;
1014 REQUIRE(bpppp);
1015 auto opppps = pppp.pointSeq_as<o2::aod::PointsSelfIndex>();
1016 }
1017 }
1018 }
1019 }
1020
1023 auto corewriter = b.cursor<o2::aod::Points3Ds>();
1024 for (auto i = 0; i < 20; ++i) {
1025 corewriter(0, -1 * i, 0.5 * i, 2 * i);
1026 }
1027 auto t1 = b.finalize();
1028
1029 c1 = 0;
1030 c2 = 0;
1031 TableBuilder be;
1032 auto extwriter = be.cursor<o2::aod::PointsSelfRef>();
1033 for (auto i = 0; i < 20; ++i) {
1034 pset.clear();
1035 slice[0] = -1;
1036 slice[1] = -1;
1037 if (c1 < withSlices.size() && i == withSlices[c1]) {
1038 slice[0] = bounds[c1].first;
1039 slice[1] = bounds[c1].second;
1040 ++c1;
1041 }
1042 if (c2 < withSets.size() && i == withSets[c2]) {
1043 for (auto z = 0U; z < sizes[c2]; ++z) {
1044 pset.push_back(i + 1 + z);
1045 }
1046 ++c2;
1047 }
1048 extwriter(0, references[i], slice, pset);
1049 }
1050 auto t2 = be.finalize();
1051
1052 FullPoints fp({t1, t2});
1053 fp.bindInternalIndicesTo(&fp);
1054
1055 // FIXME: only 4 levels of recursive self-index dereference are tested
1056 // self-index binding should stay the same for recursive dereferences
1057 for (auto& p : fp) {
1058 REQUIRE(std::same_as<std::decay_t<decltype(p)>, FullPoints::iterator>);
1059 auto ops = p.pointSeq_as<FullPoints>();
1060 for (auto& pp : ops) {
1061 REQUIRE(std::same_as<std::decay_t<decltype(pp)>, FullPoints::iterator>);
1062 auto opps = pp.pointSeq_as<FullPoints>();
1063 for (auto& ppp : opps) {
1064 REQUIRE(std::same_as<std::decay_t<decltype(ppp)>, FullPoints::iterator>);
1065 auto oppps = ppp.pointSeq_as<FullPoints>();
1066 for (auto& pppp : oppps) {
1067 REQUIRE(std::same_as<std::decay_t<decltype(pppp)>, FullPoints::iterator>);
1068 auto opppps = pppp.pointSeq_as<FullPoints>();
1069 }
1070 }
1071 }
1072 }
1073
1074 auto const& fpa = fp;
1075
1076 // iterators acquired through different means should have consistent types
1077 for (auto& it1 : fpa) {
1078 [[maybe_unused]] auto it2 = fpa.rawIteratorAt(0);
1079 [[maybe_unused]] auto it3 = fpa.iteratorAt(0);
1080 auto bit1 = std::same_as<std::decay_t<decltype(it1)>, std::decay_t<decltype(it2)>>;
1081 REQUIRE(bit1);
1082 auto bit2 = std::same_as<std::decay_t<decltype(it1)>, std::decay_t<decltype(it3)>>;
1083 REQUIRE(bit2);
1084 }
1085
1086 using FilteredPoints = o2::soa::Filtered<FullPoints>;
1087 FilteredPoints ffp({t1, t2}, {1, 2, 3}, 0);
1088 ffp.bindInternalIndicesTo(&ffp);
1089
1090 // Filter should not interfere with self-index and the binding should stay the same
1091 for (auto& p : ffp) {
1092 REQUIRE(std::same_as<std::decay_t<decltype(p)>, FilteredPoints::iterator>);
1093 REQUIRE(std::same_as<std::decay_t<decltype(p)>::parent_t, FilteredPoints>);
1094 auto ops = p.pointSeq_as<typename std::decay_t<decltype(p)>::parent_t>();
1095 for (auto& pp : ops) {
1096 REQUIRE(std::same_as<std::decay_t<decltype(pp)>::parent_t, FilteredPoints>);
1097 auto opps = pp.pointSeq_as<FilteredPoints>();
1098 for (auto& ppp : opps) {
1099 REQUIRE(std::same_as<std::decay_t<decltype(ppp)>, FilteredPoints::iterator>);
1100 auto oppps = ppp.pointSeq_as<FilteredPoints>();
1101 for (auto& pppp : oppps) {
1102 REQUIRE(std::same_as<std::decay_t<decltype(pppp)>, FilteredPoints::iterator>);
1103 auto opppps = pppp.pointSeq_as<FilteredPoints>();
1104 }
1105 }
1106 }
1107 }
1108
1109 auto const& ffpa = ffp;
1110
1111 // rawIteratorAt() should create an unfiltered iterator, unlike begin() and iteratorAt()
1112 for (auto& it1 : ffpa) {
1113 [[maybe_unused]] auto it2 = ffpa.rawIteratorAt(0);
1114 [[maybe_unused]] auto it3 = ffpa.iteratorAt(0);
1115 using T1 = std::decay_t<decltype(it1)>;
1116 using T2 = std::decay_t<decltype(it2)>;
1117 using T3 = std::decay_t<decltype(it3)>;
1118 auto bit1 = !std::same_as<T1, T2>;
1119 REQUIRE(bit1);
1120 auto bit2 = !std::same_as<T1, T3>;
1121 REQUIRE(bit2);
1122 auto bit3 = std::same_as<typename T1::policy_t, typename T3::policy_t>;
1123 REQUIRE(bit3);
1124 auto bit4 = std::same_as<typename T1::policy_t, o2::soa::FilteredIndexPolicy>;
1125 REQUIRE(bit4);
1126 auto bit5 = std::same_as<typename T2::policy_t, o2::soa::DefaultIndexPolicy>;
1127 REQUIRE(bit5);
1128 }
1129}
1130
1131TEST_CASE("TestListColumns")
1132{
1134 auto writer = b.cursor<o2::aod::Lists>();
1135 std::vector<float> floats;
1136 std::vector<int> ints;
1137 for (auto i = 1; i < 11; ++i) {
1138 floats.clear();
1139 ints.clear();
1140 for (auto j = 0; j < i; ++j) {
1141 floats.push_back(0.1231233f * (float)j + 0.1982798f);
1142 ints.push_back(j + 10);
1143 }
1144
1145 writer(0, floats, ints);
1146 }
1147 auto lt = b.finalize();
1148 o2::aod::Lists tbl{lt};
1149 auto s = 1U;
1150 for (auto& row : tbl) {
1151 auto f = row.l1();
1152 auto i = row.l2();
1153 auto constexpr bf = std::same_as<decltype(f), gsl::span<const float, (size_t)-1>>;
1154 auto constexpr bi = std::same_as<decltype(i), gsl::span<const int, (size_t)-1>>;
1155 REQUIRE(bf);
1156 REQUIRE(bi);
1157 REQUIRE(f.size() == s);
1158 REQUIRE(i.size() == s);
1159
1160 for (auto j = 0u; j < f.size(); ++j) {
1161 REQUIRE(f[j] == 0.1231233f * (float)j + 0.1982798f);
1162 REQUIRE(i[j] == (int)j + 10);
1163 }
1164 ++s;
1165 }
1166}
1167
1168TEST_CASE("TestSliceByCached")
1169{
1171 auto writer = b.cursor<o2::aod::Origints>();
1172 for (auto i = 0; i < 20; ++i) {
1173 writer(0, i, i % 3 == 0);
1174 }
1175 auto origins = b.finalize();
1176 o2::aod::Origints o{origins};
1177
1179 auto writer_w = w.cursor<o2::aod::References>();
1180 auto step = -1;
1181 for (auto i = 0; i < 5 * 20; ++i) {
1182 if (i % 5 == 0) {
1183 ++step;
1184 }
1185 writer_w(0, step);
1186 }
1187 auto refs = w.finalize();
1188 o2::aod::References r{refs};
1189
1190 ArrowTableSlicingCache atscache({{o2::soa::getLabelFromType<o2::aod::References>(), "fIndex" + o2::framework::cutString(o2::soa::getLabelFromType<o2::aod::Origints>())}});
1191 auto s = atscache.updateCacheEntry(0, refs);
1192 SliceCache cache{&atscache};
1193
1194 for (auto& oi : o) {
1195 auto cachedSlice = r.sliceByCached(o2::aod::test::origintId, oi.globalIndex(), cache);
1196 REQUIRE(cachedSlice.size() == 5);
1197 for (auto& ri : cachedSlice) {
1198 REQUIRE(ri.origintId() == oi.globalIndex());
1199 }
1200 }
1201}
1202
1203TEST_CASE("TestSliceByCachedMismatched")
1204{
1206 auto writer = b.cursor<o2::aod::Origints>();
1207 for (auto i = 0; i < 20; ++i) {
1208 writer(0, i, i % 3 == 0);
1209 }
1210 auto origins = b.finalize();
1211 o2::aod::Origints o{origins};
1212
1214 auto writer_w = w.cursor<o2::aod::References>();
1215 auto step = -1;
1216 for (auto i = 0; i < 5 * 20; ++i) {
1217 if (i % 5 == 0) {
1218 ++step;
1219 }
1220 writer_w(0, step);
1221 }
1222 auto refs = w.finalize();
1223 o2::aod::References r{refs};
1224
1225 TableBuilder w2;
1226 auto writer_w2 = w2.cursor<o2::aod::OtherReferences>();
1227 step = -1;
1228 for (auto i = 0; i < 5 * 20; ++i) {
1229 if (i % 3 == 0) {
1230 ++step;
1231 }
1232 writer_w2(0, step);
1233 }
1234 auto refs2 = w2.finalize();
1235 o2::aod::OtherReferences r2{refs2};
1236
1238 J rr{{refs, refs2}};
1239
1240 auto key = "fIndex" + o2::framework::cutString(o2::soa::getLabelFromType<o2::aod::Origints>()) + "_alt";
1241 ArrowTableSlicingCache atscache({{o2::soa::getLabelFromTypeForKey<J>(key), key}});
1242 auto s = atscache.updateCacheEntry(0, refs2);
1243 SliceCache cache{&atscache};
1244
1245 for (auto& oi : o) {
1246 auto cachedSlice = rr.sliceByCached(o2::aod::test::altOrigintId, oi.globalIndex(), cache);
1247 REQUIRE(cachedSlice.size() == 3);
1248 for (auto& ri : cachedSlice) {
1249 REQUIRE(ri.altOrigintId() == oi.globalIndex());
1250 }
1251 }
1252}
1253
1254TEST_CASE("TestIndexUnboundExceptions")
1255{
1257 auto prwriter = b.cursor<o2::aod::PointsRefF>();
1258 auto a = std::array{0, 1};
1259 auto aa = std::vector{2, 3, 4};
1260 prwriter(0, 0, &a[0], aa);
1261 a = {4, 10};
1262 aa = {12, 2, 19};
1263 prwriter(0, 1, &a[0], aa);
1264 auto t = b.finalize();
1265 auto prt = o2::aod::PointsRefF{t};
1266
1267 for (auto& row : prt) {
1268 try {
1269 [[maybe_unused]] auto sp = row.singlePoint();
1270 } catch (RuntimeErrorRef ref) {
1271 REQUIRE(std::string{error_from_ref(ref).what} == "Index pointing to Points3Ds is not bound! Did you subscribe to the table?");
1272 }
1273 try {
1274 auto ps = row.pointSlice();
1275 } catch (RuntimeErrorRef ref) {
1276 REQUIRE(std::string{error_from_ref(ref).what} == "Index pointing to Points3Ds is not bound! Did you subscribe to the table?");
1277 }
1278 try {
1279 auto pg = row.pointGroup();
1280 } catch (RuntimeErrorRef ref) {
1281 REQUIRE(std::string{error_from_ref(ref).what} == "Index pointing to Points3Ds is not bound! Did you subscribe to the table?");
1282 }
1283 }
1284}
1285
1286namespace o2::aod
1287{
1288namespace test
1289{
1290DECLARE_SOA_COLUMN(SmallIntArray, smallIntArray, int8_t[32]);
1291DECLARE_SOA_BITMAP_COLUMN(BoolArray, boolArray, 32);
1292} // namespace test
1293
1294DECLARE_SOA_TABLE(BILists, "TEST", "BILISTS", o2::soa::Index<>, test::SmallIntArray, test::BoolArray);
1295} // namespace o2::aod
1296
1297TEST_CASE("TestArrayColumns")
1298{
1300 auto writer = b.cursor<o2::aod::BILists>();
1301 int8_t ii[32];
1302 uint32_t bb;
1303 for (auto i = 0; i < 20; ++i) {
1304 bb = 0;
1305 for (auto j = 0; j < 32; ++j) {
1306 ii[j] = j;
1307 if (j % 2 == 0) {
1308 bb |= 1 << j;
1309 }
1310 }
1311 writer(0, ii, bb);
1312 }
1313 auto t = b.finalize();
1314
1315 o2::aod::BILists li{t};
1316 for (auto const& row : li) {
1317 auto iir = row.smallIntArray();
1318 [[maybe_unused]] auto bbrr = row.boolArray_raw();
1319 REQUIRE(std::same_as<std::decay_t<decltype(iir)>, int8_t const*>);
1320 for (auto i = 0; i < 32; ++i) {
1321 REQUIRE(iir[i] == i);
1322 REQUIRE(row.boolArray_bit(i) == (i % 2 == 0));
1323 }
1324 }
1325}
1326
1327namespace o2::aod
1328{
1329namespace table
1330{
1332DECLARE_SOA_COLUMN(Two, two, float);
1333DECLARE_SOA_COLUMN(Three, three, double);
1334DECLARE_SOA_COLUMN(Four, four, int[2]);
1335DECLARE_SOA_DYNAMIC_COLUMN(Five, five, [](const int in[2]) -> float { return (float)in[0] / (float)in[1]; });
1336} // namespace table
1337
1338DECLARE_SOA_TABLE(MixTest, "AOD", "MIXTST",
1339 table::One, table::Two, table::Three, table::Four,
1340 table::Five<table::Four>);
1341} // namespace o2::aod
1342
1343TEST_CASE("TestCombinedGetter")
1344{
1346 auto writer = b.cursor<o2::aod::MixTest>();
1347 int f[2];
1348 for (auto i = 0; i < 20; ++i) {
1349 f[0] = i;
1350 f[1] = i + 1;
1352 }
1353 auto t = b.finalize();
1354 o2::aod::MixTest mt{t};
1355 auto count = 0;
1356 for (auto const& row : mt) {
1357 auto features1 = row.getValues<float, o2::aod::table::One, o2::aod::table::Three>();
1358 auto features2 = row.getValues<double, o2::aod::table::One, o2::aod::table::Two, o2::aod::table::Three>();
1359 auto features3 = row.getValues<float, o2::aod::table::Two, o2::aod::table::Five<o2::aod::table::Four>>();
1360 auto b1 = std::same_as<std::array<float, 2>, decltype(features1)>;
1361 REQUIRE(b1);
1362 auto b2 = std::same_as<std::array<double, 3>, decltype(features2)>;
1363 REQUIRE(b2);
1364 auto b3 = std::same_as<std::array<float, 2>, decltype(features3)>;
1365 REQUIRE(b3);
1366 REQUIRE(features1[0] == (float)count);
1367 REQUIRE(features1[1] == (float)(o2::constants::math::Almost0 * count));
1368
1369 REQUIRE(features2[0] == (double)count);
1370 REQUIRE(features2[1] == (double)(o2::constants::math::PI * count));
1371 REQUIRE(features2[2] == (double)(o2::constants::math::Almost0 * count));
1372
1373 REQUIRE(features3[0] == (float)(o2::constants::math::PI * count));
1374 REQUIRE(features3[1] == (float)((float)count / (float)(count + 1)));
1375 ++count;
1376 }
1377}
#define DECLARE_SOA_ARRAY_INDEX_COLUMN(_Name_, _Getter_)
Definition ASoA.h:2712
#define DECLARE_SOA_SLICE_INDEX_COLUMN(_Name_, _Getter_)
Definition ASoA.h:2556
#define DECLARE_SOA_DYNAMIC_COLUMN(_Name_, _Getter_,...)
Definition ASoA.h:3026
#define DECLARE_SOA_SELF_INDEX_COLUMN(_Name_, _Getter_)
Definition ASoA.h:2855
#define DECLARE_SOA_TABLE(_Name_, _Origin_, _Desc_,...)
Definition ASoA.h:3112
#define DECLARE_SOA_EXPRESSION_COLUMN(_Name_, _Getter_, _Type_, _Expression_)
Definition ASoA.h:2411
#define DECLARE_SOA_COLUMN(_Name_, _Getter_, _Type_)
Definition ASoA.h:2337
#define DECLARE_SOA_INDEX_COLUMN_FULL(_Name_, _Getter_, _Type_, _Table_, _Suffix_)
Definition ASoA.h:2793
#define DECLARE_SOA_SELF_SLICE_INDEX_COLUMN(_Name_, _Getter_)
Definition ASoA.h:2919
#define DECLARE_SOA_COLUMN_FULL(_Name_, _Getter_, _Type_, _Label_)
Definition ASoA.h:2308
#define DECLARE_SOA_TABLE_VERSIONED(_Name_, _Origin_, _Desc_, _Version_,...)
Definition ASoA.h:3115
#define DECLARE_SOA_INDEX_COLUMN(_Name_, _Getter_)
Definition ASoA.h:2794
#define DECLARE_SOA_BITMAP_COLUMN(_Name_, _Getter_, _Size_)
Definition ASoA.h:2372
#define DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(_Name_, _Getter_)
Definition ASoA.h:2996
int32_t i
uint32_t op
bool o
const GPUTPCGMMerger::trackCluster & b1
const int16_t bb
bool const GPUTPCGMMerger::trackCluster * c1
bool const GPUTPCGMMerger::trackCluster const clcomparestruct * c2
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:3505
unfiltered_iterator begin()
Definition ASoA.h:1978
#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
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:46
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 PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
RuntimeError & error_from_ref(RuntimeErrorRef)
std::string cutString(std::string &&str)
Definition ASoA.cxx:177
auto createFieldsFromColumns(framework::pack< C... >)
Definition ASoA.h:407
constexpr auto join(Ts const &... t)
Definition ASoA.h:3315
FIXME: do not use data model tables.
char what[MAX_RUNTIME_ERROR_SIZE]
A struct, containing the root of the expression tree.
TEST_CASE("TestMarkers")
Definition test_ASoA.cxx:75
HistogramRegistry foo()
std::vector< int > row