Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
*.pcm
*.so
Nested*.cxx
User*.cxx
1 change: 1 addition & 0 deletions types/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* [`unique_ptr`](unique_ptr): `std::unique_ptr` with different element types
* [`unordered_multiset`](unordered_multiset): `std::unordered_multiset` with all `[Split]Index{32,64}` column types
* [`unordered_set`](unordered_set): `std::unordered_set` with all `[Split]Index{32,64}` column types
* [`user`](user): user-defined types, such as classes and enums
* [`variant`](variant): `std::variant` with `Switch` column type
* [`vector`](vector): `std::vector` with all `[Split]Index{32,64}` column types

Expand Down
4 changes: 4 additions & 0 deletions types/user/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# User-defined Types

* [`class`]: user-defined class(es)
* [`enum`]: user-defined enum(s)
12 changes: 12 additions & 0 deletions types/user/class/LinkDef.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <cstdint>
#include <string>
#include <variant>

#ifdef __CLING__
#pragma link C++ class Base+;
#pragma link C++ class Nested+;
// ROOT does not (yet) support std::variant, but this line silences a warning
// that fVariant would not be saved (which is not true for RNTuple).
#pragma link C++ class std::variant<std::int32_t, std::string>;
#pragma link C++ class User+;
#endif
20 changes: 20 additions & 0 deletions types/user/class/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
CXX=g++
CXXFLAGS_ROOT=$(shell root-config --cflags)
ifeq ($(CXXFLAGS_ROOT),)
$(error cannot find root-config: make sure to source thisroot.sh)
endif
CXXFLAGS=-Wall $(CXXFLAGS_ROOT)
LDFLAGS=$(shell root-config --libs)

.PHONY: all clean

all: UserClass.cxx libUserClass.so

UserClass.cxx: UserClass.hxx LinkDef.h
rootcling -f $@ $^

libUserClass.so: UserClass.cxx
$(CXX) -shared -fPIC -o $@ $^ $(CXXFLAGS) $(LDFLAGS)

clean:
rm -f UserClass.cxx UserClass_rdict.pcm libUserClass.so
20 changes: 20 additions & 0 deletions types/user/class/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# User-defined class(es)

## Fields

* `f` of type `User` with the following subfields:
* `:_0` of type `Base`
* `fInt` of type `std::int32_t`
* `fString` of type `std::string`
* `fVariant` of type `std::variant<std::int32_t, std::string>`
* `fVector` of type `std::vector<std::int32_t>`
* `fNested` of type `Nested`
* `fInt` of type `std::int32_t`
* `VectorUser` of type `std::vector<User>`

with the default column types.

## Entries

1. Simple values
2. Zero / empty values
27 changes: 27 additions & 0 deletions types/user/class/UserClass.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once

#include <cstdint>
#include <string>
#include <variant>
#include <vector>

using Variant = std::variant<std::int32_t, std::string>;
using Vector = std::vector<std::int32_t>;

class Base {
public:
std::int32_t fInt;
};

class Nested {
public:
std::int32_t fInt;
};

class User : public Base {
public:
std::string fString;
Variant fVariant;
Vector fVector;
Nested fNested;
};
122 changes: 122 additions & 0 deletions types/user/class/read.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#include <ROOT/REntry.hxx>
#include <ROOT/RNTupleReader.hxx>

using ROOT::Experimental::REntry;
using ROOT::Experimental::RNTupleReader;

#include <TSystem.h>

#include <cstdint>
#include <fstream>
#include <ostream>
#include <string>
#include <string_view>
#include <variant>
#include <vector>

#include "UserClass.hxx"

static void PrintUserMembers(const User &value, std::ostream &os,
std::string_view indent) {
os << indent << "\":_0\": {\n";
os << indent << " \"fInt\": " << value.fInt << "\n";
os << indent << "},\n";
os << indent << "\"fString\": \"" << value.fString << "\",\n";

os << indent << "\"fVariant\": ";
if (value.fVariant.index() == 0) {
os << std::get<std::int32_t>(value.fVariant);
} else if (value.fVariant.index() == 1) {
os << "\"" << std::get<std::string>(value.fVariant) << "\"";
}
os << ",\n";

os << indent << "\"fVector\": [";
bool first = true;
for (auto element : value.fVector) {
if (first) {
first = false;
} else {
os << ",";
}
os << "\n" << indent << " " << element;
}
if (!value.fVector.empty()) {
os << "\n" << indent;
}
os << "],\n";

os << indent << "\"fNested\": {\n";
os << indent << " \"fInt\": " << value.fNested.fInt << "\n";
os << indent << "}\n";
}

static void PrintUserValue(const REntry &entry, std::string_view name,
std::ostream &os, bool last = false) {
auto &value = *entry.GetPtr<User>(name);
os << " \"" << name << "\": {\n";
PrintUserMembers(value, os, " ");
os << " }";
if (!last) {
os << ",";
}
os << "\n";
}

static void PrintUserVector(const REntry &entry, std::string_view name,
std::ostream &os, bool last = false) {
auto &vector = *entry.GetPtr<std::vector<User>>(name);
os << " \"" << name << "\": [";
bool first = true;
for (const auto &element : vector) {
if (first) {
first = false;
} else {
os << ",";
}
os << "\n {\n";
PrintUserMembers(element, os, " ");
os << " }";
}
if (!vector.empty()) {
os << "\n ";
}
os << "]";
if (!last) {
os << ",";
}
os << "\n";
}

void read(std::string_view input = "types.user.class.root",
std::string_view output = "types.user.class.json") {
if (gSystem->Load("libUserClass") == -1)
throw std::runtime_error("could not find the required ROOT dictionaries, "
"please make sure to run `make` first");

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";

PrintUserValue(entry, "f", os);
PrintUserVector(entry, "Vector", os, /*last=*/true);

os << " }";
// Newline is intentionally missing, may need to print a comma before the
// next entry.
}
os << "\n";
os << "]\n";
}
60 changes: 60 additions & 0 deletions types/user/class/write.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include <ROOT/RNTupleModel.hxx>
#include <ROOT/RNTupleWriteOptions.hxx>
#include <ROOT/RNTupleWriter.hxx>

using ROOT::Experimental::RNTupleModel;
using ROOT::Experimental::RNTupleWriteOptions;
using ROOT::Experimental::RNTupleWriter;

#include <TSystem.h>

#include <string_view>

#include "UserClass.hxx"

void write(std::string_view filename = "types.user.class.root") {
if (gSystem->Load("libUserClass") == -1)
throw std::runtime_error("could not find the required ROOT dictionaries, "
"please make sure to run `make` first");

auto model = RNTupleModel::Create();

auto value = model->MakeField<User>("f");
auto vector = model->MakeField<std::vector<User>>("Vector");

RNTupleWriteOptions options;
options.SetCompression(0);
auto writer =
RNTupleWriter::Recreate(std::move(model), "ntpl", filename, options);

// First entry: simple values
value->fInt = 1;
value->fString = "b";
value->fVariant = 3;
value->fVector = {4};
value->fNested.fInt = 5;

vector->resize(2);
vector->at(0).fInt = 6;
vector->at(0).fString = "g";
vector->at(0).fVariant = "h";
vector->at(0).fVector = {9, 10};
vector->at(0).fNested.fInt = 11;

vector->at(1).fInt = 12;
vector->at(1).fString = "m";
vector->at(1).fVariant = 14;
vector->at(1).fVector = {15};
vector->at(1).fNested.fInt = 16;

writer->Fill();

// Second entry: zero / empty values
value->fInt = 0;
value->fString = "";
value->fVariant = 0;
value->fVector.clear();
value->fNested.fInt = 0;
vector->clear();
writer->Fill();
}
10 changes: 10 additions & 0 deletions types/user/enum/LinkDef.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifdef __CLING__
#pragma link C++ enum EnumInt8+;
#pragma link C++ enum EnumUInt8+;
#pragma link C++ enum EnumInt16+;
#pragma link C++ enum EnumUInt16+;
#pragma link C++ enum EnumInt32+;
#pragma link C++ enum EnumUInt32+;
#pragma link C++ enum EnumInt64+;
#pragma link C++ enum EnumUInt64+;
#endif
20 changes: 20 additions & 0 deletions types/user/enum/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
CXX=g++
CXXFLAGS_ROOT=$(shell root-config --cflags)
ifeq ($(CXXFLAGS_ROOT),)
$(error cannot find root-config: make sure to source thisroot.sh)
endif
CXXFLAGS=-Wall $(CXXFLAGS_ROOT)
LDFLAGS=$(shell root-config --libs)

.PHONY: all clean

all: UserEnum.cxx libUserEnum.so

UserEnum.cxx: UserEnum.hxx LinkDef.h
rootcling -f $@ $^

libUserEnum.so: UserEnum.cxx
$(CXX) -shared -fPIC -o $@ $^ $(CXXFLAGS) $(LDFLAGS)

clean:
rm -f UserEnum.cxx UserEnum_rdict.pcm libUserEnum.so
12 changes: 12 additions & 0 deletions types/user/enum/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# User-defined enum(s)

## Fields

* `Enum[U]Int{8,16,32,64}`

with the default column types.

## Entries

1. Simple values
2. Zero values
43 changes: 43 additions & 0 deletions types/user/enum/UserEnum.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#pragma once

#include <cstdint>

enum class EnumInt8 : std::int8_t {
Zero = 0,
Simple = 1,
};

enum class EnumUInt8 : std::uint8_t {
Zero = 0,
Simple = 2,
};

enum class EnumInt16 : std::int16_t {
Zero = 0,
Simple = 3,
};

enum class EnumUInt16 : std::uint16_t {
Zero = 0,
Simple = 4,
};

enum class EnumInt32 : std::int32_t {
Zero = 0,
Simple = 5,
};

enum class EnumUInt32 : std::uint32_t {
Zero = 0,
Simple = 6,
};

enum class EnumInt64 : std::int64_t {
Zero = 0,
Simple = 7,
};

enum class EnumUInt64 : std::uint64_t {
Zero = 0,
Simple = 8,
};
Loading