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