Project
Loading...
Searching...
No Matches
TableBuilder.h
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#ifndef O2_FRAMEWORK_TABLEBUILDER_H_
13#define O2_FRAMEWORK_TABLEBUILDER_H_
14
15#include "Framework/ASoA.h"
18
19// Apparently needs to be on top of the arrow includes.
20
21#include <arrow/chunked_array.h>
22#include <arrow/status.h>
23#include <arrow/memory_pool.h>
24#include <arrow/stl.h>
25#include <arrow/type_traits.h>
26#include <arrow/table.h>
27#include <arrow/builder.h>
28#include <arrow/util/key_value_metadata.h>
29
30#include <vector>
31#include <string>
32#include <memory>
33#include <tuple>
34#include <type_traits>
35#include <concepts>
36
37namespace arrow
38{
39class ArrayBuilder;
40class Table;
41class Array;
42} // namespace arrow
43
44extern template class arrow::NumericBuilder<arrow::UInt8Type>;
45extern template class arrow::NumericBuilder<arrow::UInt32Type>;
46extern template class arrow::NumericBuilder<arrow::FloatType>;
47extern template class arrow::NumericBuilder<arrow::Int32Type>;
48extern template class arrow::NumericBuilder<arrow::Int8Type>;
49
50namespace o2::framework
51{
52namespace detail
53{
55template <typename T>
57};
58
59template <typename T, int N>
60struct ConversionTraits<T (&)[N]> {
61 using ArrowType = ::arrow::FixedSizeListType;
62};
63
64template <typename T, int N>
65struct ConversionTraits<T[N]> {
66 using ArrowType = ::arrow::FixedSizeListType;
67};
68
69template <typename T, int N>
70struct ConversionTraits<std::array<T, N>> {
71 using ArrowType = ::arrow::FixedSizeListType;
72};
73
74template <typename T>
75struct ConversionTraits<std::vector<T>> {
76 using ArrowType = ::arrow::ListType;
77};
78
79#define O2_ARROW_STL_CONVERSION(c_type, ArrowType_) \
80 template <> \
81 struct ConversionTraits<c_type> { \
82 using ArrowType = ::arrow::ArrowType_; \
83 };
84
85// FIXME: for now we use Int8 to store booleans
86O2_ARROW_STL_CONVERSION(bool, BooleanType)
88O2_ARROW_STL_CONVERSION(int16_t, Int16Type)
90O2_ARROW_STL_CONVERSION(long long, Int64Type)
91O2_ARROW_STL_CONVERSION(long, Int64Type)
95O2_ARROW_STL_CONVERSION(long long unsigned, UInt64Type)
96O2_ARROW_STL_CONVERSION(long unsigned, UInt64Type)
97O2_ARROW_STL_CONVERSION(float, FloatType)
98O2_ARROW_STL_CONVERSION(double, DoubleType)
99O2_ARROW_STL_CONVERSION(std::string, StringType)
100O2_ARROW_STL_CONVERSION(std::span<std::byte>, BinaryViewType)
101} // namespace detail
102
103void addLabelToSchema(std::shared_ptr<arrow::Schema>& schema, const char* label);
104
106 template <typename T>
107 static arrow::Status appendToList(std::unique_ptr<arrow::FixedSizeListBuilder>& builder, const T* data, int size = 1)
108 {
109 using ArrowType = typename detail::ConversionTraits<std::decay_t<T>>::ArrowType;
110 using BuilderType = typename arrow::TypeTraits<ArrowType>::BuilderType;
111 size_t numElements = static_cast<const arrow::FixedSizeListType*>(builder->type().get())->list_size();
112
113 auto status = builder->AppendValues(size);
114 auto ValueBuilder = static_cast<BuilderType*>(builder->value_builder());
115 status &= ValueBuilder->AppendValues(data, numElements * size, nullptr);
116
117 return status;
118 }
119
120 template <typename HolderType, typename T>
121 static arrow::Status append(HolderType& holder, T value)
122 {
123 return static_cast<typename HolderType::Policy&>(holder).append(holder.builder, value);
124 }
125
126 template <typename HolderType>
127 static arrow::Status flush(HolderType& holder)
128 {
129 return static_cast<typename HolderType::Policy&>(holder).flush(holder.builder);
130 }
131
135 template <typename HolderType, typename T>
136 static arrow::Status append(HolderType& holder, const T* data)
137 {
138 if constexpr (std::is_same_v<decltype(holder.builder), std::unique_ptr<arrow::FixedSizeListBuilder>>) {
139 return appendToList<T>(holder.builder, data);
140 } else {
141 return holder.builder->Append(reinterpret_cast<const uint8_t*>(data));
142 }
143 }
145 template <typename HolderType, typename T, int N>
146 static arrow::Status append(HolderType& holder, const T (&data)[N])
147 {
148 return holder.builder->Append(reinterpret_cast<const uint8_t*>(data));
149 }
150
152 template <typename HolderType, typename T, int N>
153 static arrow::Status append(HolderType& holder, std::array<const T, N> const& data)
154 {
155 return holder.builder->Append(reinterpret_cast<const uint8_t*>(data.data()));
156 }
157
159 template <typename HolderType, typename T>
160 static arrow::Status append(HolderType& holder, std::span<const T> data)
161 {
162 using ArrowType = typename detail::ConversionTraits<T>::ArrowType;
163 using ValueBuilderType = typename arrow::TypeTraits<ArrowType>::BuilderType;
164 auto status = holder.builder->Reserve(data.size());
165 status &= holder.builder->Append();
166 auto vbuilder = static_cast<ValueBuilderType*>(holder.builder->value_builder());
167 status &= vbuilder->AppendValues(data.begin(), data.end());
168
169 return status;
170 }
171
172 template <typename HolderType, typename T>
173 static void unsafeAppend(HolderType& holder, std::span<const T> value)
174 {
175 auto status = append(holder, value);
176 if (!status.ok()) {
177 throw runtime_error("Unable to append to column");
178 }
179 }
180
181 template <typename HolderType, typename T>
182 static void unsafeAppend(HolderType& holder, T value)
183 {
184 return holder.builder->UnsafeAppend(value);
185 }
186
187 template <typename HolderType, typename T>
188 static void unsafeAppend(HolderType& holder, T* value)
189 {
190 if constexpr (std::is_same_v<decltype(holder.builder), std::unique_ptr<arrow::FixedSizeListBuilder>>) {
191 auto status = appendToList<T>(holder.builder, value);
192 } else {
193 return holder.builder->UnsafeAppend(reinterpret_cast<const uint8_t*>(value));
194 }
195 }
196
197 template <typename HolderType, typename ITERATOR>
198 static arrow::Status append(HolderType& holder, std::pair<ITERATOR, ITERATOR> ip)
199 {
201 using ValueBuilderType = typename arrow::TypeTraits<ArrowType>::BuilderType;
202 // FIXME: for the moment we do not fill things.
203 auto status = holder.builder->Append();
204 auto valueBuilder = reinterpret_cast<ValueBuilderType*>(holder.builder->value_builder());
205 return status & valueBuilder->AppendValues(&*ip.first, std::distance(ip.first, ip.second));
206 }
207
208 // Lists do not have UnsafeAppend so we need to use the slow path in any case.
209 template <typename HolderType, typename ITERATOR>
210 static void unsafeAppend(HolderType& holder, std::pair<ITERATOR, ITERATOR> ip)
211 {
213 using ValueBuilderType = typename arrow::TypeTraits<ArrowType>::BuilderType;
214 // FIXME: for the moment we do not fill things.
215 auto status = holder.builder->Append();
216 auto valueBuilder = reinterpret_cast<ValueBuilderType*>(holder.builder->value_builder());
217 status &= valueBuilder->AppendValues(&*ip.first, std::distance(ip.first, ip.second));
218 if (!status.ok()) {
219 throw runtime_error("Unable to append values to valueBuilder!");
220 }
221 return;
222 }
223};
224
225template <typename T>
227 using FillType = T;
228 using STLValueType = T;
230 using BuilderType = typename arrow::TypeTraits<ArrowType>::BuilderType;
231
232 static std::unique_ptr<BuilderType> make(arrow::MemoryPool* pool)
233 {
234 return std::make_unique<BuilderType>(pool);
235 }
236
237 static std::shared_ptr<arrow::DataType> make_datatype()
238 {
239 return arrow::TypeTraits<ArrowType>::type_singleton();
240 }
241
242 static arrow::Status append(BuilderType& builder, T value)
243 {
244 return builder.Append(value);
245 }
246
247 template <int N>
248 static arrow::Status append(BuilderType& builder, std::array<T, N>& value)
249 {
250 return builder.Append(value);
251 }
252};
253
254template <>
256 using FillType = bool;
259 using BuilderType = typename arrow::TypeTraits<ArrowType>::BuilderType;
260
261 static std::unique_ptr<BuilderType> make(arrow::MemoryPool* pool)
262 {
263 return std::make_unique<BuilderType>(pool);
264 }
265
266 static std::shared_ptr<arrow::DataType> make_datatype()
267 {
268 return arrow::TypeTraits<ArrowType>::type_singleton();
269 }
270
271 static arrow::Status append(BuilderType& builder, bool value)
272 {
273 return builder.Append(value);
274 }
275};
276
277template <>
278struct BuilderMaker<std::span<std::byte>> {
279 using FillType = std::span<std::byte>;
280 using STLValueType = std::span<std::byte>;
282 using BuilderType = typename arrow::TypeTraits<ArrowType>::BuilderType;
283
284 static std::unique_ptr<BuilderType> make(arrow::MemoryPool* pool)
285 {
286 return std::make_unique<BuilderType>(pool);
287 }
288
289 static std::shared_ptr<arrow::DataType> make_datatype()
290 {
291 return arrow::TypeTraits<ArrowType>::type_singleton();
292 }
293
294 static arrow::Status append(BuilderType& builder, std::span<std::byte> value)
295 {
296 return builder.Append((char*)value.data(), (int64_t)value.size());
297 }
298};
299
300template <typename ITERATOR>
301struct BuilderMaker<std::pair<ITERATOR, ITERATOR>> {
302 using FillType = std::pair<ITERATOR, ITERATOR> const&;
303 using STLValueType = typename ITERATOR::value_type;
304 using ArrowType = arrow::ListType;
306 using BuilderType = arrow::ListBuilder;
307 using ValueBuilder = typename arrow::TypeTraits<ValueType>::BuilderType;
308
309 static std::unique_ptr<BuilderType> make(arrow::MemoryPool* pool)
310 {
311 auto valueBuilder = std::make_shared<ValueBuilder>(pool);
312 return std::make_unique<arrow::ListBuilder>(pool, valueBuilder);
313 }
314
315 static std::shared_ptr<arrow::DataType> make_datatype()
316 {
317 return arrow::list(arrow::TypeTraits<ValueType>::type_singleton());
318 }
319};
320
321template <typename T, int N>
322struct BuilderMaker<T (&)[N]> {
323 using FillType = const T*;
324 using STLValueType = T;
325 using BuilderType = arrow::FixedSizeListBuilder;
326 using ArrowType = arrow::FixedSizeListType;
328
329 static std::unique_ptr<BuilderType> make(arrow::MemoryPool* pool)
330 {
331 std::unique_ptr<arrow::ArrayBuilder> valueBuilder;
332 auto status =
333 arrow::MakeBuilder(pool, arrow::TypeTraits<ElementType>::type_singleton(), &valueBuilder);
334 return std::make_unique<BuilderType>(pool, std::move(valueBuilder), N);
335 }
336
337 static std::shared_ptr<arrow::DataType> make_datatype()
338 {
339 return arrow::fixed_size_list(arrow::TypeTraits<ElementType>::type_singleton(), N);
340 }
341};
342
343template <typename T, int N>
344struct BuilderMaker<T[N]> {
345 using FillType = const T*;
346 using BuilderType = arrow::FixedSizeListBuilder;
347 using ArrowType = arrow::FixedSizeListType;
349
350 static std::unique_ptr<BuilderType> make(arrow::MemoryPool* pool)
351 {
352 std::unique_ptr<arrow::ArrayBuilder> valueBuilder;
353 auto status =
354 arrow::MakeBuilder(pool, arrow::TypeTraits<ElementType>::type_singleton(), &valueBuilder);
355 return std::make_unique<BuilderType>(pool, std::move(valueBuilder), N);
356 }
357
358 static std::shared_ptr<arrow::DataType> make_datatype()
359 {
360 return arrow::fixed_size_list(arrow::TypeTraits<ElementType>::type_singleton(), N);
361 }
362};
363
364template <typename T, int N>
365struct BuilderMaker<std::array<T, N>> {
366 using FillType = const T*;
367 using BuilderType = arrow::FixedSizeListBuilder;
368 using ArrowType = arrow::FixedSizeListType;
370
371 static std::unique_ptr<BuilderType> make(arrow::MemoryPool* pool)
372 {
373 std::unique_ptr<arrow::ArrayBuilder> valueBuilder;
374 auto status =
375 arrow::MakeBuilder(pool, arrow::TypeTraits<ElementType>::type_singleton(), &valueBuilder);
376 return std::make_unique<BuilderType>(pool, std::move(valueBuilder), N);
377 }
378
379 static std::shared_ptr<arrow::DataType> make_datatype()
380 {
381 return arrow::fixed_size_list(arrow::TypeTraits<ElementType>::type_singleton(), N);
382 }
383};
384
385template <typename T>
386struct BuilderMaker<std::vector<T>> {
387 using FillType = std::span<const T>;
388 using BuilderType = arrow::ListBuilder;
389 using ArrowType = arrow::ListType;
391
392 static std::unique_ptr<BuilderType> make(arrow::MemoryPool* pool)
393 {
394 std::unique_ptr<arrow::ArrayBuilder> valueBuilder;
395 auto status =
396 arrow::MakeBuilder(pool, arrow::TypeTraits<ElementType>::type_singleton(), &valueBuilder);
397 return std::make_unique<BuilderType>(pool, std::move(valueBuilder));
398 }
399
400 static std::shared_ptr<arrow::DataType> make_datatype()
401 {
402 return arrow::list(arrow::TypeTraits<ElementType>::type_singleton());
403 }
404};
405
406template <typename... ARGS>
408{
409 return std::make_tuple(std::make_unique<ARGS>()...);
410}
411
412template <typename T>
415 using BuilderType = typename arrow::TypeTraits<ArrowType>::BuilderType;
416};
417
418// Support for building tables where each entry is an iterator pair.
419// We map them to an arrow::list for now.
420template <typename ITERATOR>
421struct BuilderTraits<std::pair<ITERATOR, ITERATOR>> {
422 using ArrowType = arrow::ListType;
423 using BuilderType = arrow::ListBuilder;
424};
425
426// Support for building array columns
427// FIXME: move to use FixedSizeList<T> once we move to 0.16.1
428template <typename T, int N>
429struct BuilderTraits<T[N]> {
430 using ArrowType = arrow::FixedSizeListType;
431 using BuilderType = arrow::FixedSizeListBuilder;
432};
433
434template <typename T>
435struct BuilderTraits<std::vector<T>> {
436 using ArrowType = arrow::ListType;
437 using BuilderType = arrow::ListBuilder;
438};
439
440template <typename T>
442 template <typename BUILDER>
443 arrow::Status append(BUILDER& builder, T value)
444 {
445 return builder->Append(value);
446 }
447
448 template <typename BUILDER>
449 requires std::same_as<std::span<std::byte>, T>
450 arrow::Status append(BUILDER& builder, T value)
451 {
452 return builder->Append((char*)value.data(), (int64_t)value.size());
453 }
454
455 template <typename BUILDER>
456 arrow::Status flush(BUILDER&)
457 {
458 return arrow::Status::OK();
459 }
460};
461
462template <typename T>
464 static constexpr int CHUNK_SIZE = 256;
465
466 template <typename BUILDER>
467 arrow::Status append(BUILDER& builder, T value)
468 {
469 cache[pos % CHUNK_SIZE] = value;
470 ++pos;
471 if (pos % CHUNK_SIZE == 0) {
472 return builder->AppendValues(cache, CHUNK_SIZE, nullptr);
473 }
474 return arrow::Status::OK();
475 }
476
477 template <typename BUILDER>
478 arrow::Status flush(BUILDER& builder)
479 {
480 if (pos % CHUNK_SIZE != 0) {
481 return builder->AppendValues(cache, pos % CHUNK_SIZE, nullptr);
482 }
483 return arrow::Status::OK();
484 }
485 T cache[CHUNK_SIZE];
486 int pos = 0;
487};
488
489template <typename T>
491 static consteval DirectInsertion<T> policy();
492 using Policy = decltype(policy());
493};
494
495template <size_t I, typename T>
496struct BuilderHolder : InsertionTrait<T>::Policy {
497 static constexpr size_t index = I;
500 using BuilderType = typename arrow::TypeTraits<ArrowType>::BuilderType;
501
502 BuilderHolder(arrow::MemoryPool* pool, size_t nRows = 0)
503 : builder{BuilderMaker<T>::make(pool)}
504 {
505 if (nRows > 0) {
506 auto s = builder->Reserve(nRows);
507 if (!s.ok()) {
508 throw runtime_error_f("Unable to reserve %ll rows", nRows);
509 }
510 }
511 }
512
513 std::unique_ptr<BuilderType> builder;
514};
515
517 template <typename... ARGS, size_t NCOLUMNS>
518 static std::array<arrow::DataType, NCOLUMNS> makeArrowColumnTypes()
519 {
521 }
522
524 template <typename... Ts, typename VALUES>
525 static bool append(std::tuple<Ts...>& holders, VALUES&& values)
526 {
527 return (BuilderUtils::append(std::get<Ts::index>(holders), std::get<Ts::index>(values)).ok() && ...);
528 }
529
533 template <typename... Ts, typename VALUES>
534 static void unsafeAppend(std::tuple<Ts...>& holders, VALUES&& values)
535 {
536 (BuilderUtils::unsafeAppend(std::get<Ts::index>(holders), std::get<Ts::index>(values)), ...);
537 }
538
540 template <typename... Ts>
541 static bool finalize(std::vector<std::shared_ptr<arrow::Array>>& arrays, std::tuple<Ts...>& holders)
542 {
543 return (finalize(arrays[Ts::index], std::get<Ts::index>(holders)) && ...);
544 }
545
546 template <typename HOLDER>
547 static bool finalize(std::shared_ptr<arrow::Array>& array, HOLDER& holder)
548 {
549 return BuilderUtils::flush(holder).ok() && holder.builder->Finish(&array).ok();
550 }
551};
552
553template <typename... ARGS>
554constexpr auto tuple_to_pack(std::tuple<ARGS...>&&)
555{
556 return framework::pack<ARGS...>{};
557}
558
561#ifdef DPL_STRUCTURED_BINDING_PACKS
562#ifdef __clang__
563#pragma clang diagnostic push
564#pragma clang diagnostic ignored "-Wc++26-extensions"
565#endif
566template <class T>
567auto constexpr to_tuple(T&& object) noexcept
568{
569 auto&& [... members] = object;
570 return std::make_tuple(members...);
571}
572#ifdef __clang__
573#pragma clang diagnostic pop
574#endif
575
576#else // DPL_STRUCTURED_BINDING_PACKS
577
578template <class T>
579auto constexpr to_tuple(T&& object) noexcept
580{
581 using type = std::decay_t<T>;
583 auto&& [p0, p1, p2, p3] = object;
584 return std::make_tuple(p0, p1, p2, p3);
586 auto&& [p0, p1, p2] = object;
587 return std::make_tuple(p0, p1, p2);
589 auto&& [p0, p1] = object;
590 return std::make_tuple(p0, p1);
591 } else if constexpr (is_braces_constructible<type, any_type>{}) {
592 auto&& [p0] = object;
593 return std::make_tuple(p0);
594 } else {
595 return std::make_tuple();
596 }
597}
598
599#endif // DPL_STRUCTURED_BINDING_PACKS
600
601template <typename... ARGS>
602constexpr auto makeHolderTypes()
603{
604 return []<std::size_t... Is>(std::index_sequence<Is...>) {
605 return std::tuple(BuilderHolder<Is, ARGS>(arrow::default_memory_pool())...);
606 }(std::make_index_sequence<sizeof...(ARGS)>{});
607}
608
609template <typename... ARGS>
610auto makeHolders(arrow::MemoryPool* pool, size_t nRows)
611{
612 return [pool, nRows]<std::size_t... Is>(std::index_sequence<Is...>) {
613 return new std::tuple(BuilderHolder<Is, ARGS>(pool, nRows)...);
614 }(std::make_index_sequence<sizeof...(ARGS)>{});
615}
616
617template <typename... ARGS>
618using IndexedHoldersTuple = decltype(makeHolderTypes<ARGS...>());
619
620template <typename T>
621concept ShouldNotDeconstruct = std::is_bounded_array_v<T> || std::is_arithmetic_v<T> || framework::is_base_of_template_v<std::vector, T> || std::same_as<std::span<std::byte>, T>;
622
627{
628 static void throwError(RuntimeErrorRef const& ref);
629
630 template <typename... ARGS>
631 using HoldersTuple = typename std::tuple<BuilderHolder<0, ARGS>...>;
632
633 template <typename... ARGS>
634 using HoldersTupleIndexed = decltype(makeHolderTypes<ARGS...>());
635
638 template <typename... ARGS>
639 auto getBuilders(o2::framework::pack<ARGS...>)
640 {
641 return (HoldersTupleIndexed<ARGS...>*)mHolders;
642 }
643
644 void validate() const;
645
646 template <typename... ARGS, size_t I = sizeof...(ARGS)>
647 auto makeBuilders(std::array<char const*, I> const& columnNames, size_t nRows)
648 {
649 char const* const* names_ptr = columnNames.data();
650 mSchema = std::make_shared<arrow::Schema>(
651 std::vector<std::shared_ptr<arrow::Field>>({std::make_shared<arrow::Field>(*names_ptr++, BuilderMaker<ARGS>::make_datatype(), true, nullptr)...}));
652
653 mHolders = makeHolders<ARGS...>(mMemoryPool, nRows);
654 mFinalizer = [](std::vector<std::shared_ptr<arrow::Array>>& arrays, void* holders) -> bool {
655 return TableBuilderHelpers::finalize(arrays, *(HoldersTupleIndexed<ARGS...>*)holders);
656 };
657 mDestructor = [](void* holders) mutable -> void {
658 delete (HoldersTupleIndexed<ARGS...>*)holders;
659 };
660 }
661
662 public:
663 template <typename ARG0, typename... ARGS>
664 requires(sizeof...(ARGS) == 0) && (!ShouldNotDeconstruct<ARG0>)
665 static constexpr int countColumns()
666 {
667 using argsPack_t = decltype(tuple_to_pack(framework::to_tuple(std::declval<ARG0>())));
668 return framework::pack_size(argsPack_t{});
669 }
670
671 template <typename ARG0, typename... ARGS>
672 requires(sizeof...(ARGS) > 0) || ShouldNotDeconstruct<ARG0>
673 static constexpr int countColumns()
674 {
675 return 1 + sizeof...(ARGS);
676 }
677
678 void setLabel(const char* label);
679
680 TableBuilder(arrow::MemoryPool* pool = arrow::default_memory_pool())
681 : mHolders{nullptr},
682 mMemoryPool{pool}
683 {
684 }
685
687 {
688 mDestructor(mHolders);
689 }
690
693 template <typename ARG0, typename... ARGS>
694 requires(sizeof...(ARGS) > 0) || ShouldNotDeconstruct<ARG0>
695 auto persist(std::array<char const*, sizeof...(ARGS) + 1> const& columnNames)
696 {
697 auto persister = persistTuple(framework::pack<ARG0, ARGS...>{}, columnNames);
698 // Callback used to fill the builders
699 return [persister = persister](unsigned int slot, typename BuilderMaker<ARG0>::FillType arg, typename BuilderMaker<ARGS>::FillType... args) -> void {
700 persister(slot, std::forward_as_tuple(arg, args...));
701 };
702 }
703
704 // Special case for a single parameter to handle the serialization of struct
705 // which can be decomposed
706 template <typename ARG0, typename... ARGS>
707 requires(sizeof...(ARGS) == 0) && (!ShouldNotDeconstruct<ARG0>)
708 auto persist(std::array<char const*, countColumns<ARG0, ARGS...>()> const& columnNames)
709 {
710 using argsPack_t = decltype(tuple_to_pack(framework::to_tuple(std::declval<ARG0>())));
711 auto persister = persistTuple(argsPack_t{}, columnNames);
712 return [persister = persister](unsigned int slot, ARG0 const& obj) -> void {
713 auto t = to_tuple(obj);
714 persister(slot, t);
715 };
716 }
717
719 template <typename... ARGS>
720 auto persistTuple(framework::pack<ARGS...>, std::array<char const*, sizeof...(ARGS)> const& columnNames)
721 {
722 constexpr int nColumns = sizeof...(ARGS);
723 validate();
724 mArrays.resize(nColumns);
725 makeBuilders<ARGS...>(columnNames, 10);
726
727 // Callback used to fill the builders
728 using FillTuple = std::tuple<typename BuilderMaker<ARGS>::FillType...>;
729 return [holders = mHolders](unsigned int /*slot*/, FillTuple const& t) -> void {
730 auto status = TableBuilderHelpers::append(*(HoldersTupleIndexed<ARGS...>*)holders, t);
731 if (status == false) {
732 throwError(runtime_error("Unable to append"));
733 }
734 };
735 }
736
739 template <typename ARG0, typename... ARGS>
740 requires(sizeof...(ARGS) > 0) || ShouldNotDeconstruct<ARG0>
742 {
743 using FillTuple = std::tuple<typename BuilderMaker<ARG0>::FillType, typename BuilderMaker<ARGS>::FillType...>;
744 return [holders = mHolders](unsigned int /*slot*/, typename BuilderMaker<ARG0>::FillType arg, typename BuilderMaker<ARGS>::FillType... args) -> void {
745 TableBuilderHelpers::unsafeAppend(*(HoldersTupleIndexed<ARG0, ARGS...>*)holders, std::forward_as_tuple(arg, args...));
746 };
747 }
748
749 // Same as above, but starting from a o2::soa::Table, which has all the
750 // information already available.
751 template <typename T>
752 auto cursor()
753 {
754 return [this]<typename... Cs>(pack<Cs...>) {
755 return this->template persist<typename Cs::type...>({Cs::columnLabel()...});
756 }(typename T::table_t::persistent_columns_t{});
757 }
758
760 template <typename T>
762 {
763 return [this]<typename... Cs>(pack<Cs...>) {
764 return this->template unsafePersist<typename Cs::type...>();
765 }(typename T::table_t::persistent_columns_t{});
766 }
767
768 template <typename... Cs>
770 {
771 return this->template persist<typename Cs::type...>({Cs::columnLabel()...});
772 }
773
774 template <typename T, typename E>
775 auto cursor()
776 {
777 return [this]<typename... Cs>(pack<Cs...>) {
778 return this->template persist<E>({Cs::columnLabel()...});
779 }(typename T::table_t::persistent_columns_t{});
780 }
781
783 template <typename... Ts>
784 auto reserveArrays(std::tuple<Ts...>& holders, int s)
785 {
786 return (std::get<Ts::index>(holders).builder->Reserve(s).ok() && ...);
787 }
788
789 template <typename... ARGS>
791 {
792 reserveArrays(*(HoldersTupleIndexed<ARGS...>*)mHolders, s);
793 }
794
796 void extracted(bool& status);
797 std::shared_ptr<arrow::Table> finalize();
798
799 private:
800 bool (*mFinalizer)(std::vector<std::shared_ptr<arrow::Array>>& arrays, void* holders);
801 void (*mDestructor)(void* holders);
802 void* mHolders;
803 arrow::MemoryPool* mMemoryPool;
804 std::shared_ptr<arrow::Schema> mSchema;
805 std::vector<std::shared_ptr<arrow::Array>> mArrays;
806};
807} // namespace o2::framework
808#endif // FRAMEWORK_TABLEBUILDER_H
std::shared_ptr< arrow::Schema > schema
unsigned short int uint16_t
unsigned int uint32_t
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error s
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc Replace constant variables static by constexpr expressions Compile RTC in deterministic with NO_FAST_MATH flags and GPUCA_DETERMINISTIC_MODE define Use RTC to optimize GPU code h configStandalone Processing proc_rtctech Use a file lock to serialize access to the cache folder int32_t
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc bool
constexpr int p2()
constexpr int p1()
constexpr to accelerate the coordinates changing
bounded_vector< int > members
uint16_t pos
Definition RawData.h:3
#define O2_ARROW_STL_CONVERSION(c_type, ArrowType_)
auto cursor(framework::pack< Cs... >)
auto persist(std::array< char const *, countColumns< ARG0, ARGS... >()> const &columnNames)
auto persistTuple(framework::pack< ARGS... >, std::array< char const *, sizeof...(ARGS)> const &columnNames)
Same a the above, but use a tuple to persist stuff.
static constexpr int countColumns()
void extracted(bool &status)
Actually creates the arrow::Table from the builders.
static constexpr int countColumns()
auto unsafeCursor()
Same as cursor(), but uses UnsafeAppend. Only safe after reserve().
auto reserve(o2::framework::pack< ARGS... > &&, int s)
TableBuilder(arrow::MemoryPool *pool=arrow::default_memory_pool())
auto reserveArrays(std::tuple< Ts... > &holders, int s)
Reserve method to expand the columns as needed.
auto persist(std::array< char const *, sizeof...(ARGS)+1 > const &columnNames)
GLsizeiptr size
Definition glcorearb.h:659
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
GLenum GLsizei GLsizei GLint * values
Definition glcorearb.h:1576
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLuint object
Definition glcorearb.h:4041
const GLuint * arrays
Definition glcorearb.h:1314
GLint ref
Definition glcorearb.h:291
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
void addLabelToSchema(std::shared_ptr< arrow::Schema > &schema, const char *label)
RuntimeErrorRef runtime_error(const char *)
constexpr auto makeHolderTypes()
auto constexpr to_tuple(T &&object) noexcept
constexpr auto tuple_to_pack(std::tuple< ARGS... > &&)
auto makeHolders(arrow::MemoryPool *pool, size_t nRows)
decltype(makeHolderTypes< ARGS... >()) IndexedHoldersTuple
auto make_builders()
RuntimeErrorRef runtime_error_f(const char *,...)
typename detail::ConversionTraits< T >::ArrowType ArrowType
std::unique_ptr< BuilderType > builder
typename arrow::TypeTraits< ArrowType >::BuilderType BuilderType
typename InsertionTrait< T >::Policy Policy
BuilderHolder(arrow::MemoryPool *pool, size_t nRows=0)
typename detail::ConversionTraits< T >::ArrowType ElementType
static std::unique_ptr< BuilderType > make(arrow::MemoryPool *pool)
arrow::FixedSizeListBuilder BuilderType
arrow::FixedSizeListType ArrowType
static std::shared_ptr< arrow::DataType > make_datatype()
static std::unique_ptr< BuilderType > make(arrow::MemoryPool *pool)
typename detail::ConversionTraits< T >::ArrowType ElementType
arrow::FixedSizeListType ArrowType
static std::shared_ptr< arrow::DataType > make_datatype()
arrow::FixedSizeListBuilder BuilderType
typename arrow::TypeTraits< ArrowType >::BuilderType BuilderType
static arrow::Status append(BuilderType &builder, bool value)
static std::unique_ptr< BuilderType > make(arrow::MemoryPool *pool)
static std::shared_ptr< arrow::DataType > make_datatype()
typename detail::ConversionTraits< bool >::ArrowType ArrowType
typename detail::ConversionTraits< T >::ArrowType ElementType
static std::unique_ptr< BuilderType > make(arrow::MemoryPool *pool)
static std::shared_ptr< arrow::DataType > make_datatype()
static std::unique_ptr< BuilderType > make(arrow::MemoryPool *pool)
typename detail::ConversionTraits< typename ITERATOR::value_type >::ArrowType ValueType
typename arrow::TypeTraits< ValueType >::BuilderType ValueBuilder
static std::shared_ptr< arrow::DataType > make_datatype()
static arrow::Status append(BuilderType &builder, std::span< std::byte > value)
typename arrow::TypeTraits< ArrowType >::BuilderType BuilderType
typename detail::ConversionTraits< std::span< std::byte > >::ArrowType ArrowType
static std::unique_ptr< BuilderType > make(arrow::MemoryPool *pool)
static std::shared_ptr< arrow::DataType > make_datatype()
static std::unique_ptr< BuilderType > make(arrow::MemoryPool *pool)
typename detail::ConversionTraits< T >::ArrowType ElementType
static std::shared_ptr< arrow::DataType > make_datatype()
typename arrow::TypeTraits< ArrowType >::BuilderType BuilderType
static arrow::Status append(BuilderType &builder, std::array< T, N > &value)
static arrow::Status append(BuilderType &builder, T value)
typename detail::ConversionTraits< T >::ArrowType ArrowType
static std::unique_ptr< BuilderType > make(arrow::MemoryPool *pool)
static std::shared_ptr< arrow::DataType > make_datatype()
arrow::FixedSizeListBuilder BuilderType
arrow::FixedSizeListType ArrowType
typename arrow::TypeTraits< ArrowType >::BuilderType BuilderType
typename detail::ConversionTraits< T >::ArrowType ArrowType
static arrow::Status flush(HolderType &holder)
static arrow::Status appendToList(std::unique_ptr< arrow::FixedSizeListBuilder > &builder, const T *data, int size=1)
static arrow::Status append(HolderType &holder, const T(&data)[N])
Appender for the array case.
static arrow::Status append(HolderType &holder, T value)
static void unsafeAppend(HolderType &holder, std::span< const T > value)
static arrow::Status append(HolderType &holder, std::span< const T > data)
Appender for the vector case.
static arrow::Status append(HolderType &holder, const T *data)
static arrow::Status append(HolderType &holder, std::pair< ITERATOR, ITERATOR > ip)
static arrow::Status append(HolderType &holder, std::array< const T, N > const &data)
Appender for the array case.
static void unsafeAppend(HolderType &holder, T *value)
static void unsafeAppend(HolderType &holder, std::pair< ITERATOR, ITERATOR > ip)
static void unsafeAppend(HolderType &holder, T value)
arrow::Status append(BUILDER &builder, T value)
arrow::Status flush(BUILDER &builder)
arrow::Status append(BUILDER &builder, T value)
arrow::Status append(BUILDER &builder, T value)
arrow::Status flush(BUILDER &)
static consteval DirectInsertion< T > policy()
static bool finalize(std::shared_ptr< arrow::Array > &array, HOLDER &holder)
static bool append(std::tuple< Ts... > &holders, VALUES &&values)
Invokes the append method for each entry in the tuple.
static std::array< arrow::DataType, NCOLUMNS > makeArrowColumnTypes()
static bool finalize(std::vector< std::shared_ptr< arrow::Array > > &arrays, std::tuple< Ts... > &holders)
Invokes the append method for each entry in the tuple.
static void unsafeAppend(std::tuple< Ts... > &holders, VALUES &&values)
FIXME: adapt type conversion to new arrow.