Skip to content

Commit 8e2efd4

Browse files
committed
Add test for std::unordered_set
1 parent e390940 commit 8e2efd4

File tree

11 files changed

+405
-0
lines changed

11 files changed

+405
-0
lines changed

types/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
* [`set`](set): `std::set` with all `[Split]Index{32,64}` column types
66
* [`string`](string): `std::string` with all `[Split]Index{32,64}` column types
77
* [`unique_ptr`](unique_ptr): `std::unique_ptr` with different element types
8+
* [`unordered_set`](unordered_set): `std::unordered_set` with all `[Split]Index{32,64}` column types
89
* [`variant`](variant): `std::variant` with `Switch` column type
910
* [`vector`](vector): `std::vector` with all `[Split]Index{32,64}` column types

types/unordered_set/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# `std::unordered_set`
2+
3+
* [`fundamental`](fundamental): `std::unordered_set<std::int32_t>`
4+
* [`nested`](nested): `std::unordered_set<std::unordered_set<std::int32_t>>`
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# `std::unordered_set<std::int32_t>`
2+
3+
## Fields
4+
5+
* `[Split]Index{32,64}`
6+
7+
with the corresponding column type for the offset column of the collection parent field.
8+
All child fields use the default column encoding `Int32`.
9+
10+
## Entries
11+
12+
1. Single-element sets, with ascending values
13+
2. Empty sets
14+
3. Increasing number of elements in the set:
15+
one element in the first field, two elements in the second field, etc.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#include <ROOT/REntry.hxx>
2+
#include <ROOT/RNTupleReader.hxx>
3+
4+
using ROOT::Experimental::REntry;
5+
using ROOT::Experimental::RNTupleReader;
6+
7+
#include <cstdint>
8+
#include <fstream>
9+
#include <ostream>
10+
#include <string>
11+
#include <string_view>
12+
#include <unordered_set>
13+
14+
using UnorderedSet = std::unordered_set<std::int32_t>;
15+
16+
static void PrintUnorderedSetValue(const REntry &entry, std::string_view name,
17+
std::ostream &os, bool last = false) {
18+
UnorderedSet &value = *entry.GetPtr<UnorderedSet>(name);
19+
20+
std::vector<UnorderedSet::value_type> valueSorted(value.begin(), value.end());
21+
std::sort(valueSorted.begin(), valueSorted.end());
22+
23+
os << " \"" << name << "\": [";
24+
bool first = true;
25+
for (auto element : valueSorted) {
26+
if (first) {
27+
first = false;
28+
} else {
29+
os << ",";
30+
}
31+
os << "\n " << element;
32+
}
33+
if (!valueSorted.empty()) {
34+
os << "\n ";
35+
}
36+
os << "]";
37+
if (!last) {
38+
os << ",";
39+
}
40+
os << "\n";
41+
}
42+
43+
void read(std::string_view input = "types.unordered_set.fundamental.root",
44+
std::string_view output = "types.unordered_set.fundamental.json") {
45+
std::ofstream os(std::string{output});
46+
os << "[\n";
47+
48+
auto reader = RNTupleReader::Open("ntpl", input);
49+
auto &entry = reader->GetModel().GetDefaultEntry();
50+
bool first = true;
51+
for (auto index : *reader) {
52+
reader->LoadEntry(index);
53+
54+
if (first) {
55+
first = false;
56+
} else {
57+
os << ",\n";
58+
}
59+
os << " {\n";
60+
61+
PrintUnorderedSetValue(entry, "Index32", os);
62+
PrintUnorderedSetValue(entry, "Index64", os);
63+
PrintUnorderedSetValue(entry, "SplitIndex32", os);
64+
PrintUnorderedSetValue(entry, "SplitIndex64", os, /*last=*/true);
65+
66+
os << " }";
67+
// Newline is intentionally missing, may need to print a comma before the
68+
// next entry.
69+
}
70+
os << "\n";
71+
os << "]\n";
72+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#include <ROOT/RField.hxx>
2+
#include <ROOT/RNTupleModel.hxx>
3+
#include <ROOT/RNTupleUtil.hxx>
4+
#include <ROOT/RNTupleWriteOptions.hxx>
5+
#include <ROOT/RNTupleWriter.hxx>
6+
7+
using ROOT::Experimental::EColumnType;
8+
using ROOT::Experimental::RField;
9+
using ROOT::Experimental::RNTupleModel;
10+
using ROOT::Experimental::RNTupleWriteOptions;
11+
using ROOT::Experimental::RNTupleWriter;
12+
13+
#include <cstdint>
14+
#include <memory>
15+
#include <string_view>
16+
#include <unordered_set>
17+
18+
using UnorderedSet = std::unordered_set<std::int32_t>;
19+
20+
static std::shared_ptr<UnorderedSet>
21+
MakeUnorderedSetField(RNTupleModel &model, std::string_view name,
22+
EColumnType indexType) {
23+
auto field = std::make_unique<RField<UnorderedSet>>(name);
24+
field->SetColumnRepresentatives({{indexType}});
25+
model.AddField(std::move(field));
26+
return model.GetDefaultEntry().GetPtr<UnorderedSet>(name);
27+
}
28+
29+
void write(std::string_view filename = "types.unordered_set.fundamental.root") {
30+
auto model = RNTupleModel::Create();
31+
32+
// Non-split index encoding
33+
auto Index32 =
34+
MakeUnorderedSetField(*model, "Index32", EColumnType::kIndex32);
35+
auto Index64 =
36+
MakeUnorderedSetField(*model, "Index64", EColumnType::kIndex64);
37+
38+
// Split index encoding
39+
auto SplitIndex32 =
40+
MakeUnorderedSetField(*model, "SplitIndex32", EColumnType::kSplitIndex32);
41+
auto SplitIndex64 =
42+
MakeUnorderedSetField(*model, "SplitIndex64", EColumnType::kSplitIndex64);
43+
44+
RNTupleWriteOptions options;
45+
options.SetCompression(0);
46+
auto writer =
47+
RNTupleWriter::Recreate(std::move(model), "ntpl", filename, options);
48+
49+
// First entry: single-element sets, with ascending values
50+
*Index32 = {1};
51+
*Index64 = {2};
52+
*SplitIndex32 = {3};
53+
*SplitIndex64 = {4};
54+
writer->Fill();
55+
56+
// Second entry: empty sets
57+
*Index32 = {};
58+
*Index64 = {};
59+
*SplitIndex32 = {};
60+
*SplitIndex64 = {};
61+
writer->Fill();
62+
63+
// Third entry: increasing number of elements in the set
64+
*Index32 = {1};
65+
*Index64 = {2, 3};
66+
*SplitIndex32 = {4, 5, 6};
67+
*SplitIndex64 = {7, 8, 9, 10};
68+
writer->Fill();
69+
}

types/unordered_set/nested/LinkDef.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include <cstdint>
2+
#include <unordered_set>
3+
4+
#ifdef __CLING__
5+
#pragma link C++ class std::unordered_set<std::unordered_set<std::int32_t>>+;
6+
#endif

types/unordered_set/nested/Makefile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
CXX=g++
2+
CXXFLAGS_ROOT=$(shell root-config --cflags)
3+
ifeq ($(CXXFLAGS_ROOT),)
4+
$(error cannot find root-config: make sure to source thisroot.sh)
5+
endif
6+
CXXFLAGS=-Wall $(CXXFLAGS_ROOT)
7+
LDFLAGS=$(shell root-config --libs)
8+
9+
.PHONY: all clean
10+
11+
all: NestedUnorderedSet.cxx libNestedUnorderedSet.so
12+
13+
NestedUnorderedSet.cxx: NestedUnorderedSet.hxx LinkDef.h
14+
rootcling -f $@ $^
15+
16+
libNestedUnorderedSet.so: NestedUnorderedSet.cxx
17+
$(CXX) -shared -fPIC -o $@ $^ $(CXXFLAGS) $(LDFLAGS)
18+
19+
clean:
20+
rm -f NestedUnorderedSet.cxx NestedUnorderedSet_rdict.pcm libNestedUnorderedSet.so
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
#include <unordered_set>
5+
6+
template <> struct std::hash<std::unordered_set<std::int32_t>> {
7+
std::size_t
8+
operator()(const std::unordered_set<std::int32_t> &s) const noexcept {
9+
std::size_t h = 0;
10+
for (const auto &el : s) {
11+
h ^= std::hash<std::int32_t>{}(el);
12+
}
13+
return h;
14+
}
15+
};

types/unordered_set/nested/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# `std::unordered_set<std::unordered_set<std::int32_t>>`
2+
3+
## Fields
4+
5+
* `[Split]Index{32,64}`
6+
7+
with the corresponding column type for the offset column of the two collection parent fields.
8+
All child fields use the default column encoding `Int32`.
9+
10+
## Entries
11+
12+
1. Single-element sets, with ascending values
13+
2. Empty sets
14+
3. Increasing number of elements in the outer set, with arbitrary lengths of the inner sets
15+
16+
## Dictionaries
17+
18+
These tests require ROOT dictionaries, which can be generated with the provided `Makefile` in this directory. This will create a `libNestedUnorderedSet` shared object.

types/unordered_set/nested/read.C

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#include <ROOT/REntry.hxx>
2+
#include <ROOT/RNTupleReader.hxx>
3+
4+
using ROOT::Experimental::REntry;
5+
using ROOT::Experimental::RNTupleReader;
6+
7+
#include <TSystem.h>
8+
9+
#include <cstdint>
10+
#include <filesystem>
11+
#include <fstream>
12+
#include <ostream>
13+
#include <string>
14+
#include <string_view>
15+
#include <unordered_set>
16+
17+
using UnorderedSet = std::unordered_set<std::unordered_set<std::int32_t>>;
18+
19+
static void PrintNestedUnorderedSetValue(const REntry &entry,
20+
std::string_view name,
21+
std::ostream &os, bool last = false) {
22+
UnorderedSet &value = *entry.GetPtr<UnorderedSet>(name);
23+
24+
std::vector<UnorderedSet::value_type> valueInnerSorted(
25+
value.begin(), value.end());
26+
std::vector<std::vector<UnorderedSet::value_type::value_type>> valueSorted;
27+
28+
for (auto inner : value) {
29+
std::vector innerSorted(inner.begin(), inner.end());
30+
std::sort(innerSorted.begin(), innerSorted.end());
31+
valueSorted.push_back(innerSorted);
32+
}
33+
34+
std::sort(valueSorted.begin(), valueSorted.end());
35+
36+
os << " \"" << name << "\": [";
37+
bool outerFirst = true;
38+
for (auto inner : valueSorted) {
39+
if (outerFirst) {
40+
outerFirst = false;
41+
} else {
42+
os << ",";
43+
}
44+
os << "\n [";
45+
bool innerFirst = true;
46+
for (auto element : inner) {
47+
if (innerFirst) {
48+
innerFirst = false;
49+
} else {
50+
os << ",";
51+
}
52+
os << "\n " << element;
53+
}
54+
if (!inner.empty()) {
55+
os << "\n ";
56+
}
57+
os << "]";
58+
}
59+
if (!valueSorted.empty()) {
60+
os << "\n ";
61+
}
62+
os << "]";
63+
if (!last) {
64+
os << ",";
65+
}
66+
os << "\n";
67+
}
68+
69+
void read(std::string_view input = "types.unordered_set.nested.root",
70+
std::string_view output = "types.unordered_set.nested.json") {
71+
if (!std::filesystem::exists("libNestedUnorderedSet.so")) {
72+
throw std::runtime_error("could not find the required ROOT dictionaries, "
73+
"please make sure to run `make` first");
74+
}
75+
gSystem->Load("libNestedUnorderedSet");
76+
77+
std::ofstream os(std::string{output});
78+
os << "[\n";
79+
80+
auto reader = RNTupleReader::Open("ntpl", input);
81+
auto &entry = reader->GetModel().GetDefaultEntry();
82+
bool first = true;
83+
for (auto index : *reader) {
84+
reader->LoadEntry(index);
85+
86+
if (first) {
87+
first = false;
88+
} else {
89+
os << ",\n";
90+
}
91+
os << " {\n";
92+
93+
PrintNestedUnorderedSetValue(entry, "Index32", os);
94+
PrintNestedUnorderedSetValue(entry, "Index64", os);
95+
PrintNestedUnorderedSetValue(entry, "SplitIndex32", os);
96+
PrintNestedUnorderedSetValue(entry, "SplitIndex64", os, /*last=*/true);
97+
98+
os << " }";
99+
// Newline is intentionally missing, may need to print a comma before the
100+
// next entry.
101+
}
102+
os << "\n";
103+
os << "]\n";
104+
}

0 commit comments

Comments
 (0)