diff --git a/types/README.md b/types/README.md index 7a8c70b..27dd4a7 100644 --- a/types/README.md +++ b/types/README.md @@ -1,6 +1,8 @@ # Types * [`fundamental`](fundamental): fundamental column types + * [`optional`](optional): `std::optional` with different element types * [`string`](string): `std::string` with all `[Split]Index{32,64}` column types + * [`unique_ptr`](unique_ptr): `std::unique_ptr` with different element types * [`variant`](variant): `std::variant` with `Switch` column type * [`vector`](vector): `std::vector` with all `[Split]Index{32,64}` column types diff --git a/types/optional/README.md b/types/optional/README.md new file mode 100644 index 0000000..dbee5b7 --- /dev/null +++ b/types/optional/README.md @@ -0,0 +1,18 @@ +# `std::optional` + +## Fields + + * `[Split]Index{32,64}`: `std::optional` + * with the corresponding column type for the first (principal) column + * `String`: `std::optional` + * `Variant`: `std::optional>` + * `VectorInt32`: `std::optional>` + * `VectorOpt`: `std::vector>>` + +with otherwise the default column types. + +## Entries + +1. Simple values +2. No value +3. Zero / empty values diff --git a/types/optional/read.C b/types/optional/read.C new file mode 100644 index 0000000..fdf939d --- /dev/null +++ b/types/optional/read.C @@ -0,0 +1,131 @@ +#include +#include + +using ROOT::Experimental::REntry; +using ROOT::Experimental::RNTupleReader; + +#include +#include +#include +#include +#include +#include +#include +#include + +using VariantTy = std::variant; +using VectorInt32Ty = std::vector; + +template static void PrintValue(const T &value, std::ostream &os); + +template <> void PrintValue(const std::int32_t &value, std::ostream &os) { + os << value; +} + +template <> void PrintValue(const std::string &value, std::ostream &os) { + os << "\"" << value << "\""; +} + +template <> void PrintValue(const VariantTy &value, std::ostream &os) { + if (value.index() == 0) { + PrintValue(std::get(value), os); + } else if (value.index() == 1) { + PrintValue(std::get(value), os); + } +} + +template <> void PrintValue(const VectorInt32Ty &value, std::ostream &os) { + os << "["; + bool first = true; + for (auto element : value) { + if (first) { + first = false; + } else { + os << ","; + } + os << "\n " << element; + } + if (!value.empty()) { + os << "\n "; + } + os << "]"; +} + +template +static void PrintOptionalValue(const REntry &entry, std::string_view name, + std::ostream &os, bool last = false) { + auto &value = *entry.GetPtr>(name); + os << " \"" << name << "\": "; + if (!value.has_value()) { + os << "null"; + } else { + PrintValue(*value, os); + } + if (!last) { + os << ","; + } + os << "\n"; +} + +static void PrintVectorOptValue(const REntry &entry, std::string_view name, + std::ostream &os, bool last = false) { + auto &value = *entry.GetPtr>>(name); + os << " \"" << name << "\": ["; + bool first = true; + for (auto &&element : value) { + if (first) { + first = false; + } else { + os << ","; + } + os << "\n "; + if (!element.has_value()) { + os << "null"; + } else { + os << *element; + } + } + if (!value.empty()) { + os << "\n "; + } + os << "]"; + if (!last) { + os << ","; + } + os << "\n"; +} + +void read(std::string_view input = "types.optional.root", + std::string_view output = "types.optional.json") { + std::ofstream os(std::string{output}); + os << "[\n"; + + auto reader = RNTupleReader::Open("ntpl", input); + auto &entry = reader->GetModel().GetDefaultEntry(); + bool first = true; + for (auto index : *reader) { + reader->LoadEntry(index); + + if (first) { + first = false; + } else { + os << ",\n"; + } + os << " {\n"; + + PrintOptionalValue(entry, "Index32", os); + PrintOptionalValue(entry, "Index64", os); + PrintOptionalValue(entry, "SplitIndex32", os); + PrintOptionalValue(entry, "SplitIndex64", os); + PrintOptionalValue(entry, "String", os); + PrintOptionalValue(entry, "Variant", os); + PrintOptionalValue(entry, "VectorInt32", os); + PrintVectorOptValue(entry, "VectorOpt", os, /*last=*/true); + + os << " }"; + // Newline is intentionally missing, may need to print a comma before the + // next entry. + } + os << "\n"; + os << "]\n"; +} diff --git a/types/optional/write.C b/types/optional/write.C new file mode 100644 index 0000000..36e037e --- /dev/null +++ b/types/optional/write.C @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include + +using ROOT::Experimental::EColumnType; +using ROOT::Experimental::RField; +using ROOT::Experimental::RNTupleModel; +using ROOT::Experimental::RNTupleWriteOptions; +using ROOT::Experimental::RNTupleWriter; + +#include +#include +#include +#include +#include +#include +#include + +using OptInt32Ty = std::optional; +using VariantTy = std::variant; +using VectorInt32Ty = std::vector; + +static std::shared_ptr MakeIntField(RNTupleModel &model, + std::string_view name, + EColumnType indexType) { + auto field = std::make_unique>(name); + field->SetColumnRepresentatives({{indexType}}); + model.AddField(std::move(field)); + return model.GetDefaultEntry().GetPtr(name); +} + +void write(std::string_view filename = "types.optional.root") { + auto model = RNTupleModel::Create(); + + // Non-split index encoding + auto Index32 = MakeIntField(*model, "Index32", EColumnType::kIndex32); + auto Index64 = MakeIntField(*model, "Index64", EColumnType::kIndex64); + + // Split index encoding + auto SplitIndex32 = + MakeIntField(*model, "SplitIndex32", EColumnType::kSplitIndex32); + auto SplitIndex64 = + MakeIntField(*model, "SplitIndex64", EColumnType::kSplitIndex64); + + auto String = model->MakeField>("String"); + auto Variant = model->MakeField>("Variant"); + auto VectorInt32 = + model->MakeField>("VectorInt32"); + auto VectorOpt = + model->MakeField>>("VectorOpt"); + + RNTupleWriteOptions options; + options.SetCompression(0); + auto writer = + RNTupleWriter::Recreate(std::move(model), "ntpl", filename, options); + + // First entry: simple values + *Index32 = 1; + *Index64 = 2; + *SplitIndex32 = 3; + *SplitIndex64 = 4; + *String = "abc"; + *Variant = "def"; + *VectorInt32 = {1, 2, 3}; + *VectorOpt = {4, 5, 6}; + writer->Fill(); + + // Second entry: no value + Index32->reset(); + Index64->reset(); + SplitIndex32->reset(); + SplitIndex64->reset(); + String->reset(); + Variant->reset(); + VectorInt32->reset(); + *VectorOpt = {{}}; + writer->Fill(); + + // Third entry: zero / empty value + *Index32 = 0; + *Index64 = 0; + *SplitIndex32 = 0; + *SplitIndex64 = 0; + *String = ""; + *Variant = 0; + *VectorInt32 = VectorInt32Ty{}; + *VectorOpt = {}; + writer->Fill(); +} diff --git a/types/unique_ptr/README.md b/types/unique_ptr/README.md new file mode 100644 index 0000000..94882ab --- /dev/null +++ b/types/unique_ptr/README.md @@ -0,0 +1,18 @@ +# `std::unique_ptr` + +## Fields + + * `[Split]Index{32,64}`: `std::unique_ptr` + * with the corresponding column type for the first (principal) column + * `String`: `std::unique_ptr` + * `Variant`: `std::unique_ptr>` + * `VectorInt32`: `std::unique_ptr>` + * `VectorPtr`: `std::vector>>` + +with otherwise the default column types. + +## Entries + +1. Simple values +2. No value +3. Zero / empty values diff --git a/types/unique_ptr/read.C b/types/unique_ptr/read.C new file mode 100644 index 0000000..2cc9468 --- /dev/null +++ b/types/unique_ptr/read.C @@ -0,0 +1,130 @@ +#include +#include + +using ROOT::Experimental::REntry; +using ROOT::Experimental::RNTupleReader; + +#include +#include +#include +#include +#include +#include +#include + +using VariantTy = std::variant; +using VectorInt32Ty = std::vector; + +template static void PrintValue(const T &value, std::ostream &os); + +template <> void PrintValue(const std::int32_t &value, std::ostream &os) { + os << value; +} + +template <> void PrintValue(const std::string &value, std::ostream &os) { + os << "\"" << value << "\""; +} + +template <> void PrintValue(const VariantTy &value, std::ostream &os) { + if (value.index() == 0) { + PrintValue(std::get(value), os); + } else if (value.index() == 1) { + PrintValue(std::get(value), os); + } +} + +template <> void PrintValue(const VectorInt32Ty &value, std::ostream &os) { + os << "["; + bool first = true; + for (auto element : value) { + if (first) { + first = false; + } else { + os << ","; + } + os << "\n " << element; + } + if (!value.empty()) { + os << "\n "; + } + os << "]"; +} + +template +static void PrintUniquePtrValue(const REntry &entry, std::string_view name, + std::ostream &os, bool last = false) { + auto &value = *entry.GetPtr>(name); + os << " \"" << name << "\": "; + if (!value) { + os << "null"; + } else { + PrintValue(*value, os); + } + if (!last) { + os << ","; + } + os << "\n"; +} + +static void PrintVectorPtrValue(const REntry &entry, std::string_view name, + std::ostream &os, bool last = false) { + auto &value = *entry.GetPtr>>(name); + os << " \"" << name << "\": ["; + bool first = true; + for (auto &&element : value) { + if (first) { + first = false; + } else { + os << ","; + } + os << "\n "; + if (!element) { + os << "null"; + } else { + os << *element; + } + } + if (!value.empty()) { + os << "\n "; + } + os << "]"; + if (!last) { + os << ","; + } + os << "\n"; +} + +void read(std::string_view input = "types.unique_ptr.root", + std::string_view output = "types.unique_ptr.json") { + std::ofstream os(std::string{output}); + os << "[\n"; + + auto reader = RNTupleReader::Open("ntpl", input); + auto &entry = reader->GetModel().GetDefaultEntry(); + bool first = true; + for (auto index : *reader) { + reader->LoadEntry(index); + + if (first) { + first = false; + } else { + os << ",\n"; + } + os << " {\n"; + + PrintUniquePtrValue(entry, "Index32", os); + PrintUniquePtrValue(entry, "Index64", os); + PrintUniquePtrValue(entry, "SplitIndex32", os); + PrintUniquePtrValue(entry, "SplitIndex64", os); + PrintUniquePtrValue(entry, "String", os); + PrintUniquePtrValue(entry, "Variant", os); + PrintUniquePtrValue(entry, "VectorInt32", os); + PrintVectorPtrValue(entry, "VectorPtr", os, /*last=*/true); + + os << " }"; + // Newline is intentionally missing, may need to print a comma before the + // next entry. + } + os << "\n"; + os << "]\n"; +} diff --git a/types/unique_ptr/write.C b/types/unique_ptr/write.C new file mode 100644 index 0000000..cca10a9 --- /dev/null +++ b/types/unique_ptr/write.C @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include + +using ROOT::Experimental::EColumnType; +using ROOT::Experimental::RField; +using ROOT::Experimental::RNTupleModel; +using ROOT::Experimental::RNTupleWriteOptions; +using ROOT::Experimental::RNTupleWriter; + +#include +#include +#include +#include +#include +#include + +using PtrInt32Ty = std::unique_ptr; +using VariantTy = std::variant; +using VectorInt32Ty = std::vector; + +static std::shared_ptr MakeIntField(RNTupleModel &model, + std::string_view name, + EColumnType indexType) { + auto field = std::make_unique>(name); + field->SetColumnRepresentatives({{indexType}}); + model.AddField(std::move(field)); + return model.GetDefaultEntry().GetPtr(name); +} + +void write(std::string_view filename = "types.unique_ptr.root") { + auto model = RNTupleModel::Create(); + + // Non-split index encoding + auto Index32 = MakeIntField(*model, "Index32", EColumnType::kIndex32); + auto Index64 = MakeIntField(*model, "Index64", EColumnType::kIndex64); + + // Split index encoding + auto SplitIndex32 = + MakeIntField(*model, "SplitIndex32", EColumnType::kSplitIndex32); + auto SplitIndex64 = + MakeIntField(*model, "SplitIndex64", EColumnType::kSplitIndex64); + + auto String = model->MakeField>("String"); + auto Variant = model->MakeField>("Variant"); + auto VectorInt32 = + model->MakeField>("VectorInt32"); + auto VectorPtr = + model->MakeField>>("VectorPtr"); + + RNTupleWriteOptions options; + options.SetCompression(0); + auto writer = + RNTupleWriter::Recreate(std::move(model), "ntpl", filename, options); + + // First entry: simple values + *Index32 = std::make_unique(1); + *Index64 = std::make_unique(2); + *SplitIndex32 = std::make_unique(3); + *SplitIndex64 = std::make_unique(4); + *String = std::make_unique("abc"); + *Variant = std::make_unique("def"); + *VectorInt32 = std::make_unique(); + **VectorInt32 = {1, 2, 3}; + VectorPtr->push_back(std::make_unique(4)); + VectorPtr->push_back(std::make_unique(5)); + VectorPtr->push_back(std::make_unique(6)); + writer->Fill(); + + // Second entry: no value + Index32->reset(); + Index64->reset(); + SplitIndex32->reset(); + SplitIndex64->reset(); + String->reset(); + Variant->reset(); + VectorInt32->reset(); + VectorPtr->clear(); + VectorPtr->push_back(nullptr); + writer->Fill(); + + // Third entry: zero / empty value + *Index32 = std::make_unique(0); + *Index64 = std::make_unique(0); + *SplitIndex32 = std::make_unique(0); + *SplitIndex64 = std::make_unique(0); + *String = std::make_unique(""); + *Variant = std::make_unique(0); + *VectorInt32 = std::make_unique(); + VectorPtr->clear(); + writer->Fill(); +}