138 template <
typename T>
181 template <
typename T,
typename KeyType = key_type,
typename KeyExtractor = DefaultKeyExtractor>
195 using Fill = std::function<
void(TBranch& branch, T
const&)>;
199 using BranchCallback = std::variant<std::monostate, Fill, FillExt, Spectator, SpectatorExt>;
219 template <
typename... Args>
222 init(std::forward<Args>(args)...);
235 template <
typename... Args>
238 init(std::forward<Args>(args)...);
242 template <
typename Arg,
typename... Args>
243 void init(Arg&& arg, Args&&... args)
245 using Type = std::decay_t<Arg>;
258 }
else if constexpr (std::is_integral<Type>::value) {
263 if constexpr (
sizeof...(args) > 0) {
264 init(std::forward<Args>(args)...);
270 template <
typename Arg>
273 static_assert(always_static_assert_v<Arg>,
"no matching function signature for passed object. Please check:\n- Is it a callable object?\n- Does it have correct parameters and return type?\n- Are all type correctly qualified");
290 template <
typename... Args>
292 const char* treename,
295 parseConstructorArgs(std::forward<Args>(args)...);
296 if (!mTreeStructure) {
297 std::runtime_error(
"Failed to create the branch configuration");
310 void init(
const char*
filename,
const char* treename,
const char* treetitle =
nullptr)
312 mFile = std::make_unique<TFile>(
filename,
"RECREATE",
"", 505);
313 mTree = std::make_unique<TTree>(treename, treetitle !=
nullptr ? treetitle : treename);
314 mTree->SetDirectory(mFile.get());
315 mTreeStructure->setup(mBranchSpecs, mTree.get());
326 auto& spec = mBranchSpecs.at(
index);
331 std::generate(spec.names.begin(), spec.names.end(), [&]() { return spec.getName(branchName, idx++); });
334 spec.names.at(0) = branchName;
342 template <
typename ContextType>
345 if (!mTree || !mFile || mFile->IsZombie()) {
346 throw std::runtime_error(
"Writer is invalid state, probably closed previously");
349 mTreeStructure->exec(std::forward<ContextType>(context), mBranchSpecs);
363 mCustomClose(mFile.get(), mTree.get());
374 mFile.reset(
nullptr);
381 if (mIsClosed || !mFile) {
385 LOG(info) <<
"Autosaving " << mTree->GetName() <<
" at entry " << mTree->GetEntries();
386 mTree->AutoSave(
"overwrite");
396 return (mTreeStructure !=
nullptr ? mTreeStructure->size() : 0);
405 template <
typename T>
408 auto tree = branchRef.GetTree();
409 auto name = branchRef.GetName();
410 auto branch =
tree->GetBranch(
name);
412 if (branch->GetEntries()) {
413 branch->SetAddress(newdata);
416 auto branchleaves = branch->GetListOfLeaves();
417 branch->DropBaskets(
"all");
418 branch->DeleteBaskets(
"all");
419 tree->GetListOfBranches()->Remove(branch);
420 for (
auto entry : *branchleaves) {
424 tree->GetListOfBranches()->Compress();
425 tree->GetListOfLeaves()->Compress();
433 std::vector<key_type> keys;
434 std::vector<std::string> names;
435 std::vector<TBranch*> branches;
436 TClass* classinfo =
nullptr;
445 class TreeStructureInterface
448 static const size_t STAGE = 0;
449 TreeStructureInterface() =
default;
450 virtual ~TreeStructureInterface() =
default;
454 virtual void setup(std::vector<BranchSpec>&, TTree*) {}
459 virtual void exec(InputContext&, std::vector<BranchSpec>&) {}
462 virtual size_t size()
const {
return STAGE; }
465 void setupInstance(std::vector<BranchSpec>&, TTree*) {}
467 void process(InputContext&, std::vector<BranchSpec>&) {}
470 template <
typename T =
char>
471 using BinaryBranchStoreType = std::tuple<std::vector<T>, TBranch*,
size_t>;
484 template <
typename T,
typename _ =
void>
485 struct StructureElementTypeTrait {
488 using BinaryBranchSpecialization = std::integral_constant<char, 0>;
489 using MessageableTypeSpecialization = std::integral_constant<char, 1>;
490 using MessageableVectorSpecialization = std::integral_constant<char, 2>;
491 using ROOTTypeSpecialization = std::integral_constant<char, 3>;
496 template <
typename T>
497 struct StructureElementTypeTrait<
T,
std::
enable_if_t<std::is_same<T, const char*>::value>> {
498 using value_type =
T;
499 using store_type = BinaryBranchStoreType<char>;
500 using specialization_id = BinaryBranchSpecialization;
505 template <
typename T>
506 struct StructureElementTypeTrait<
T,
std::
enable_if_t<is_messageable<T>::value>> {
507 using value_type =
T;
508 using store_type = value_type;
509 using specialization_id = MessageableTypeSpecialization;
513 template <
typename T>
514 struct StructureElementTypeTrait<
T,
std::
enable_if_t<has_messageable_value_type<T>::value &&
515 is_specialization_v<T, std::vector>>> {
516 using value_type =
T;
517 using store_type = value_type*;
518 using specialization_id = MessageableVectorSpecialization;
522 template <
typename T>
523 struct StructureElementTypeTrait<
T,
std::
enable_if_t<has_root_dictionary<T>::value &&
524 is_messageable<T>::value == false &&
525 has_messageable_value_type<T>::value == false>> {
526 using value_type =
T;
527 using store_type = value_type*;
528 using specialization_id = ROOTTypeSpecialization;
532 template <
typename T>
533 struct StructureElementTypeTrait<
T,
534 std::
enable_if_t<is_specialization_v<T, ROOTSerialized> == true>> {
535 using value_type =
typename T::wrapped_type;
536 using store_type = value_type*;
537 using specialization_id = ROOTTypeSpecialization;
542 template <
typename DataT,
typename BASE>
543 class TreeStructureElement :
public BASE
547 using value_type =
typename StructureElementTypeTrait<DataT>::value_type;
548 using store_type =
typename StructureElementTypeTrait<DataT>::store_type;
549 using specialization_id =
typename StructureElementTypeTrait<DataT>::specialization_id;
550 static const size_t STAGE = BASE::STAGE + 1;
551 TreeStructureElement() =
default;
552 ~TreeStructureElement()
override =
default;
554 void setup(std::vector<BranchSpec>& specs, TTree*
tree)
override
556 setupInstance(specs,
tree);
561 void exec(InputContext& context, std::vector<BranchSpec>& specs)
override
565 size_t size()
const override {
return STAGE; }
571 template <typename S, typename std::enable_if_t<!std::is_same<S, BinaryBranchSpecialization>::value,
int> = 0>
572 TBranch* createBranch(TTree*
tree,
const char*
name,
size_t branchIdx)
574 return tree->Branch(
name, &(mStore.at(branchIdx)));
580 template <typename S, typename std::enable_if_t<std::is_same<S, BinaryBranchSpecialization>::value,
int> = 0>
581 TBranch* createBranch(TTree*
tree,
const char*
name,
size_t branchIdx)
584 std::get<2>(mStore.at(branchIdx)) = 1;
586 std::string sizeBranchName = std::string(
name) +
"Size";
588 std::string leafList = sizeBranchName +
"/i";
589 std::get<1>(mStore.at(branchIdx)) =
tree->Branch(sizeBranchName.c_str(), &(std::get<2>(mStore.at(branchIdx))), leafList.c_str());
590 return tree->Branch(
name, &(std::get<0>(mStore.at(branchIdx))));
594 void setupInstance(std::vector<BranchSpec>& specs, TTree*
tree)
598 PrevT::setupInstance(specs,
tree);
599 constexpr size_t SpecIndex = STAGE - 1;
600 if (specs[SpecIndex].branches.size() == 0) {
604 specs[SpecIndex].classinfo = TClass::GetClass(
typeid(value_type));
605 if (std::is_same<value_type, const char*>::value ==
false && std::is_fundamental<value_type>::value ==
false &&
606 specs[SpecIndex].classinfo ==
nullptr) {
613 throw std::runtime_error(
std::to_string(SpecIndex) +
": no dictionary available for non-fundamental type " +
typeid(value_type).
name());
615 size_t branchIdx = 0;
616 mStore.resize(specs[SpecIndex].names.size());
617 for (
auto const&
name : specs[SpecIndex].names) {
618 specs[SpecIndex].branches.at(branchIdx) = createBranch<specialization_id>(
tree,
name.c_str(), branchIdx);
619 if (specs[SpecIndex].branches.at(branchIdx) ==
nullptr) {
620 throw std::runtime_error(
std::to_string(SpecIndex) +
": can not create branch " +
name +
" for type " +
typeid(value_type).
name() +
" - LinkDef entry missing?");
622 LOG(info) << SpecIndex <<
": branch " <<
name <<
" set up";
629 template <
typename DataType>
630 bool runCallback(TBranch* branch, DataType
const&
data, DataRef
const&
ref)
632 if (std::holds_alternative<
typename BranchDef<value_type>::Spectator>(mCallback)) {
633 std::get<typename BranchDef<value_type>::Spectator>(mCallback)(
data);
635 if (std::holds_alternative<
typename BranchDef<value_type>::SpectatorExt>(mCallback)) {
636 std::get<typename BranchDef<value_type>::SpectatorExt>(mCallback)(
data,
ref);
638 if (std::holds_alternative<
typename BranchDef<value_type>::Fill>(mCallback)) {
639 std::get<typename BranchDef<value_type>::Fill>(mCallback)(*branch,
data);
642 if (std::holds_alternative<
typename BranchDef<value_type>::FillExt>(mCallback)) {
643 std::get<typename BranchDef<value_type>::FillExt>(mCallback)(*branch,
data,
ref);
651 template <typename S, typename std::enable_if_t<std::is_same<S, MessageableTypeSpecialization>::value,
int> = 0>
652 void fillData(InputContext& context, DataRef
const&
ref, TBranch* branch,
size_t branchIdx)
654 auto data = context.get<value_type>(
ref);
655 if (!runCallback(branch,
data,
ref)) {
656 mStore[branchIdx] =
data;
665 template <typename S, typename std::enable_if_t<std::is_same<S, ROOTTypeSpecialization>::value,
int> = 0>
666 void fillData(InputContext& context, DataRef
const&
ref, TBranch* branch,
size_t branchIdx)
668 auto data = context.get<
typename std::add_pointer<value_type>::type>(
ref);
669 if (!runCallback(branch, *
data,
ref)) {
672 mStore[branchIdx] =
const_cast<value_type*
>(
data.get());
679 template <typename S, typename std::enable_if_t<std::is_same<S, BinaryBranchSpecialization>::value,
int> = 0>
680 void fillData(InputContext& context, DataRef
const&
ref, TBranch* branch,
size_t branchIdx)
682 auto data = context.get<gsl::span<char>>(
ref);
683 std::get<2>(mStore.at(branchIdx)) =
data.size();
684 std::get<1>(mStore.at(branchIdx))->Fill();
685 std::get<0>(mStore.at(branchIdx)).resize(
data.size());
686 memcpy(std::get<0>(mStore.at(branchIdx)).data(),
data.data(),
data.size());
691 template <typename S, typename std::enable_if_t<std::is_same<S, MessageableVectorSpecialization>::value,
int> = 0>
692 void fillData(InputContext& context, DataRef
const&
ref, TBranch* branch,
size_t branchIdx)
694 using ElementType =
typename value_type::value_type;
695 static_assert(is_messageable<ElementType>::value,
"logical error: should be correctly selected by StructureElementTypeTrait");
701 const ElementType*
start =
nullptr;
702 const ElementType*
end =
nullptr;
703 const ElementType* cap =
nullptr;
708 auto adopt = [](
auto const&
data, value_type&
v) {
709 static_assert(
sizeof(
v) == 24);
710 if (
data.size() == 0) {
717 std::memcpy(&
v, &
impl,
sizeof(VecBase));
725 auto data = context.get<gsl::span<ElementType>>(
ref);
727 auto* dataview =
new value_type;
728 adopt(
data, *dataview);
729 if (!runCallback(branch, *dataview,
ref)) {
730 mStore[branchIdx] = dataview;
734 auto ptr = (VecBase*)dataview;
738 }
catch (RuntimeErrorRef e) {
739 if constexpr (has_root_dictionary<value_type>::value ==
true) {
741 auto data = context.get<
typename std::add_pointer<value_type>::type>(
ref);
742 if (!runCallback(branch, *
data,
ref)) {
743 mStore[branchIdx] =
const_cast<value_type*
>(
data.get());
754 void process(InputContext& context, std::vector<BranchSpec>& specs)
758 PrevT::process(context, specs);
759 constexpr size_t SpecIndex = STAGE - 1;
760 BranchSpec
const& spec = specs[SpecIndex];
761 if (spec.branches.size() == 0) {
766 for (
auto const&
key : spec.keys) {
767 auto keypos = context.getPos(
key.c_str());
768 auto parts = context.getNofParts(keypos);
769 for (
decltype(parts) part = 0; part < parts; part++) {
770 auto dataref = context.get(
key.c_str(), part);
771 size_t branchIdx = 0;
773 branchIdx = spec.getIndex(dataref);
774 if (branchIdx == ~(
size_t)0) {
779 fillData<specialization_id>(context, dataref, spec.branches.at(branchIdx), branchIdx);
785 template <
size_t N,
typename Arg,
typename... Args>
786 auto getArg(Arg&& arg, Args&&... args)
788 if constexpr (N == 0) {
790 }
else if constexpr (
sizeof...(Args) > 0) {
791 return getArg<N - 1>(std::forward<Args>(args)...);
796 template <
typename... Args>
797 void setCallback(Args&&... args)
801 if constexpr (STAGE > 1) {
802 PrevT::setCallback(std::forward<Args>(args)...);
806 auto arg = getArg<STAGE - 1>(std::forward<Args>(args)...);
807 if constexpr (std::is_same<value_type,
typename decltype(arg)
::type>
::value) {
808 if (not std::holds_alternative<std::monostate>(arg.callback)) {
809 mCallback = std::move(arg.callback);
816 std::vector<store_type> mStore;
818 typename BranchDef<value_type>::BranchCallback mCallback;
822 template <
typename Arg,
typename... Args>
823 void parseConstructorArgs(Arg&& arg, Args&&... args)
825 using Type = std::decay_t<Arg>;
826 if constexpr (can_assign<Type, CustomClose>::value) {
829 mTreeStructure = createTreeStructure<0, TreeStructureInterface>(std::forward<Arg>(arg), std::forward<Args>(args)...);
832 if constexpr (
sizeof...(Args) > 0) {
833 parseConstructorArgs(std::forward<Args>(args)...);
838 template <
size_t N,
typename BASE,
typename T,
typename... Args>
839 auto createTreeStructure(T&& def, Args&&... args)
844 mBranchSpecs.push_back({{}, {def.branchName}});
845 auto& spec = mBranchSpecs.back();
849 spec.keys.resize(def.keys.size());
850 std::generate(spec.keys.begin(), spec.keys.end(), [&def, &idx] { return T::key_extractor::asString(def.keys[idx++]); });
851 mBranchSpecs.back().branches.resize(def.nofBranches,
nullptr);
856 assert(def.nofBranches == 0 || def.nofBranches >= spec.keys.size());
858 assert(def.nofBranches <= 1 || def.getIndex);
859 if (def.nofBranches > 1) {
861 assert(def.getIndex && def.getName);
862 mBranchSpecs.back().getIndex = def.getIndex;
863 mBranchSpecs.back().names.resize(def.nofBranches);
868 mBranchSpecs.back().getName = def.getName;
870 std::generate(mBranchSpecs.back().names.begin(), mBranchSpecs.back().names.end(),
871 [&def, &idx]() { return def.getName(def.branchName, idx++); });
873 using type = TreeStructureElement<typename T::type, BASE>;
874 if constexpr (N == 0) {
878 auto instance = createTreeStructure<N + 1, type>(std::forward<Args>(args)...);
879 instance->setCallback(std::move(def), std::forward<Args>(args)...);
881 std::unique_ptr<TreeStructureInterface> ret(instance.release());
884 return std::move(createTreeStructure<N + 1, type>(std::forward<Args>(args)...));
889 template <
size_t N,
typename T>
890 std::unique_ptr<T> createTreeStructure()
892 static_assert(N > 0,
"The writer does not make sense without branch definitions");
893 return std::make_unique<T>();
897 std::unique_ptr<TFile> mFile;
899 std::unique_ptr<TTree> mTree;
901 std::vector<BranchSpec> mBranchSpecs;
903 std::unique_ptr<TreeStructureInterface> mTreeStructure;
905 bool mIsClosed =
false;