Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion tree/tree/inc/TLeafD32.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class TLeafD32 : public TLeaf {
void ReadValue(std::istream &s, Char_t delim = ' ') override;
void SetAddress(void *add = nullptr) override;

ClassDefOverride(TLeafD32, 1); // A TLeaf for a 24 bit truncated floating point data type.
ClassDefOverride(TLeafD32, 2); // A TLeaf for a 24 bit truncated floating point data type.
Comment thread
pcanal marked this conversation as resolved.
};

// if leaf is a simple type, i must be set to 0
Expand Down
2 changes: 1 addition & 1 deletion tree/tree/inc/TLeafF16.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class TLeafF16 : public TLeaf {
void ReadValue(std::istream &s, Char_t delim = ' ') override;
void SetAddress(void *add = nullptr) override;

ClassDefOverride(TLeafF16, 1); // A TLeaf for a 24 bit truncated floating point data type.
ClassDefOverride(TLeafF16, 2); // A TLeaf for a 24 bit truncated floating point data type.
};

// if leaf is a simple type, i must be set to 0
Expand Down
4 changes: 3 additions & 1 deletion tree/tree/src/TLeaf.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,9 @@ TString TLeaf::GetFullName() const
TLeaf* TLeaf::GetLeafCounter(Int_t& countval) const
{
countval = 1;
const char* name = GetTitle();
Comment thread
ferdymercury marked this conversation as resolved.
auto slash = fTitle.First("/"); // for truncated types D32 F16
TString sname = (slash == TString::kNPOS) ? fTitle : TString(fTitle(0, slash));
const char *name = sname.Data();
char* bleft = (char*) strchr(name, '[');
if (!bleft) {
return nullptr;
Expand Down
25 changes: 18 additions & 7 deletions tree/tree/src/TLeafD32.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,12 @@ TLeafD32::TLeafD32(TBranch *parent, const char *name, const char *type) : TLeaf(
fValue = nullptr;
fPointer = nullptr;
fElement = nullptr;
fTitle = type;
Comment thread
ferdymercury marked this conversation as resolved.

if (strchr(type, '['))
fElement = new TStreamerElement(Form("%s_Element", name), type, 0, 0, "Double32_t");
auto bracket = strchr(type, '[');
if (bracket) {
fTitle.Append('/').Append(type);
fElement = new TStreamerElement(Form("%s_Element", name), bracket, 0, 0, "Double32_t");
}
}

////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -203,10 +205,19 @@ void TLeafD32::SetAddress(void *add)
void TLeafD32::Streamer(TBuffer &R__b)
{
if (R__b.IsReading()) {
R__b.ReadClassBuffer(TLeafD32::Class(), this);

if (fTitle.Contains("["))
fElement = new TStreamerElement(Form("%s_Element", fName.Data()), fTitle.Data(), 0, 0, "Double32_t");
delete fElement;
fElement = nullptr;
UInt_t R__s, R__c;
Comment thread
ferdymercury marked this conversation as resolved.
Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
R__b.ReadClassBuffer(TLeafD32::Class(), this, R__v, R__s, R__c);
if (R__v < 2 && fTitle.BeginsWith("d[")) {
fTitle.Prepend('/');
}
if (fTitle.Contains("/d[")) {
auto slash = fTitle.First("/");
Comment thread
ferdymercury marked this conversation as resolved.
TString bracket = fTitle(slash + 2, fTitle.Length() - slash - 2);
fElement = new TStreamerElement(Form("%s_Element", fName.Data()), bracket.Data(), 0, 0, "Double32_t");
}
} else {
R__b.WriteClassBuffer(TLeafD32::Class(), this);
}
Expand Down
25 changes: 18 additions & 7 deletions tree/tree/src/TLeafF16.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,12 @@ TLeafF16::TLeafF16(TBranch *parent, const char *name, const char *type) : TLeaf(
fValue = nullptr;
fPointer = nullptr;
fElement = nullptr;
fTitle = type;

if (strchr(type, '['))
fElement = new TStreamerElement(Form("%s_Element", name), type, 0, 0, "Float16_t");
auto bracket = strchr(type, '[');
if (bracket) {
fTitle.Append('/').Append(type);
fElement = new TStreamerElement(Form("%s_Element", name), bracket, 0, 0, "Float16_t");
}
}

////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -216,10 +218,19 @@ void TLeafF16::SetAddress(void *add)
void TLeafF16::Streamer(TBuffer &R__b)
{
if (R__b.IsReading()) {
R__b.ReadClassBuffer(TLeafF16::Class(), this);

if (fTitle.Contains("["))
fElement = new TStreamerElement(Form("%s_Element", fName.Data()), fTitle.Data(), 0, 0, "Float16_t");
delete fElement;
fElement = nullptr;
UInt_t R__s, R__c;
Comment thread
ferdymercury marked this conversation as resolved.
Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
R__b.ReadClassBuffer(TLeafF16::Class(), this, R__v, R__s, R__c);
if (R__v < 2 && fTitle.BeginsWith("f[")) {
fTitle.Prepend('/');
}
if (fTitle.Contains("/f[")) {
auto slash = fTitle.First("/");
TString bracket = fTitle(slash + 2, fTitle.Length() - slash - 2);
fElement = new TStreamerElement(Form("%s_Element", fName.Data()), bracket.Data(), 0, 0, "Float16_t");
}
} else {
R__b.WriteClassBuffer(TLeafF16::Class(), this);
}
Expand Down
40 changes: 37 additions & 3 deletions tree/tree/src/TTree.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ It is strongly recommended to persistify those as objects rather than lists of l
- `I` : a 32 bit signed integer (`Int_t`)
- `i` : a 32 bit unsigned integer (`UInt_t`)
- `F` : a 32 bit floating point (`Float_t`)
- `f` : a 21 bit floating point with truncated mantissa (`Float16_t`): 1 for the sign, 8 for the exponent and 12 for the mantissa.
- `f` : a 21 bit floating point with truncated mantissa (`Float16_t`): 1 for the sign, 8 for the exponent and 12 for the mantissa. Can be customized with suffix `[min,max(,nbits)]`.
- `D` : a 64 bit floating point (`Double_t`)
- `d` : a 32 bit truncated floating point (`Double32_t`): 1 for the sign, 8 for the exponent and 23 for the mantissa.
- `d` : a 32 bit truncated floating point (`Double32_t`): 1 for the sign, 8 for the exponent and 23 for the mantissa. Can be customized with suffix `[min,max(,nbits)]`.
- `L` : a 64 bit signed integer (`Long64_t`)
- `l` : a 64 bit unsigned integer (`ULong64_t`)
- `G` : a long signed integer, stored as 64 bit (`Long_t`)
Expand Down Expand Up @@ -133,7 +133,41 @@ It is strongly recommended to persistify those as objects rather than lists of l
in an `Int_t` (/I) branch called `myArrSize`, the syntax for the `leaflist` string would
be: `myArr[myArrSize]/d[0,twopi]`. Of course the number of bits could be specified,
the standard rules of opaque typedefs annotation are valid. For example, if only
18 bits were sufficient, the syntax would become: `myArr[myArrSize]/d[0,twopi,18]`
18 bits were sufficient, the syntax would become: `myArr[myArrSize]/d[0,twopi,18]`.
See TStreamerElement::GetRange for further details.

Examples of writing/reading plain C arrays with fixed or variable length into/from TTrees:

~~~ {.cpp}
TTree *t = new TTree("t", "t");
int n;
Double32_t arr[64];
// Double32_t* arr = new Double32_t[64]; // equivalent, later just remember delete[]
t->Branch("n", &n);
t->Branch("arr", arr, "arr[n]/d[0,1,32]");
t->Branch("arr_def", arr, "arr_def[n]/d");
t->Branch("arr_fix", arr, "arr_fix[64]/d[0,1,32]");
t->Branch("arr_fix_def", arr, "arr_fix_def[64]/d");
t->Branch("single", arr, "single/d[0,1,32]");
t->Branch("single_def", arr, "single_def/d");
for (int j = 0; j < 64; ++j) {
arr[j] = 0.01 * j;
}
n = 3;
t->Fill();
// Reading now:
const auto nEntries = t->GetEntries();
t->Scan();
for (auto name : {"arr", "arr_def", "arr_fix", "arr_fix_def", "single", "single_def"}) {
t->ResetBranchAddresses();
t->SetBranchAddress("n", &n);
t->SetBranchAddress(name, arr);
for (Long64_t i = 0; i < nEntries; ++i) {
t->GetEntry(i);
// Work with arr
}
}
~~~

\anchor addingacolumnofstl
## Adding a column holding STL collection instances (e.g. std::vector or std::list)
Expand Down
95 changes: 95 additions & 0 deletions tree/tree/test/TTreeTruncatedDatatypes.cxx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "TFile.h"
#include "TSystem.h"
#include "TTree.h"
#include "TLeaf.h"
#include "TBranch.h"

#include "gtest/gtest.h"

Expand Down Expand Up @@ -57,3 +59,96 @@ TEST(TTreeTruncatedDatatypes, float16double32leaves)
f.Close();
gSystem->Unlink(ofileName);
}

// https://its.cern.ch/jira/browse/ROOT-10149
TEST(TTreeTruncatedDatatypes, LeafCounter)
{
const auto ofileName = "leafcounter10149.root";
Long64_t nEntries = 10; // must be < 63
{
TFile f(ofileName, "RECREATE");
TTree *t = new TTree("t", "t");
int n;
Double32_t arr[64];
t->Branch("n", &n);
t->Branch("arr", arr, "arr[n]/d[0,100,32]");
t->Branch("arr_def", arr, "arr_def[n]/d");
t->Branch("arr_fix", arr, "arr_fix[64]/d[0,100,32]");
t->Branch("arr_fix_def", arr, "arr_fix_def[64]/d");
t->Branch("single", arr, "single/d[0,100,32]");
t->Branch("single_def", arr, "single_def/d");
for (auto name : {"arr", "arr_def", "arr_fix", "arr_fix_def", "single", "single_def"}) {
auto b = t->GetBranch(name);
EXPECT_NE(b, nullptr);
auto l = b->GetLeaf(name);
EXPECT_NE(l, nullptr);
int len;
auto b_c = l->GetLeafCounter(len);
if (strcmp(name, "arr") == 0 || strcmp(name, "arr_def") == 0) {
EXPECT_NE(b_c, nullptr);
EXPECT_STREQ(b_c->GetName(), "n");
} else if (strcmp(name, "arr_fix") == 0 || strcmp(name, "arr_fix_def") == 0) {
EXPECT_EQ(b_c, nullptr);
EXPECT_EQ(len, 64);
} else if (strcmp(name, "single") == 0 || strcmp(name, "single_def") == 0) {
EXPECT_EQ(b_c, nullptr);
EXPECT_EQ(len, 1);
}
}
// Fill tree
for (Long64_t i = 0; i < nEntries; ++i) {
n = i;
for (int j = 0; j < 64; ++j) {
arr[j] = i + 0.01 * j;
}
t->Fill();
}
t->Write();
Comment thread
ferdymercury marked this conversation as resolved.
f.Close();
}
{
TFile f(ofileName, "READ");
TTree *t = f.Get<TTree>("t");
for (auto name : {"arr", "arr_def", "arr_fix", "arr_fix_def", "single", "single_def"}) {
auto b = t->GetBranch(name);
EXPECT_NE(b, nullptr);
auto l = b->GetLeaf(name);
EXPECT_NE(l, nullptr);
int len;
auto b_c = l->GetLeafCounter(len);
if (strcmp(name, "arr") == 0 || strcmp(name, "arr_def") == 0) {
EXPECT_NE(b_c, nullptr);
EXPECT_STREQ(b_c->GetName(), "n");
} else if (strcmp(name, "arr_fix") == 0 || strcmp(name, "arr_fix_def") == 0) {
EXPECT_EQ(b_c, nullptr);
EXPECT_EQ(len, 64);
} else if (strcmp(name, "single") == 0 || strcmp(name, "single_def") == 0) {
EXPECT_EQ(b_c, nullptr);
EXPECT_EQ(len, 1);
}
int n;
Double32_t arr[64];
t->SetBranchAddress("n", &n);
t->SetBranchAddress(name, arr);
Comment thread
ferdymercury marked this conversation as resolved.
const auto tol = 0.001;
for (Long64_t i = 0; i < nEntries; ++i) {
t->GetEntry(i);
EXPECT_EQ(n, i);
if (strcmp(name, "arr") == 0 || strcmp(name, "arr_def") == 0) {
for (int j = 0; j < n; ++j) {
EXPECT_NEAR(i + 0.01 * j, arr[j], tol);
}
} else if (strcmp(name, "arr_fix") == 0 || strcmp(name, "arr_fix_def") == 0) {
for (int j = 0; j < 64; ++j) {
EXPECT_NEAR(i + 0.01 * j, arr[j], tol);
}
} else if (strcmp(name, "single") == 0 || strcmp(name, "single_def") == 0) {
EXPECT_NEAR(i, arr[0], tol);
}
}
t->ResetBranchAddresses();
}
f.Close();
}
gSystem->Unlink(ofileName);
}
9 changes: 6 additions & 3 deletions tree/treeplayer/src/TTreeFormula.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -597,9 +597,12 @@ Int_t TTreeFormula::RegisterDimensions(Int_t code, TLeaf *leaf) {
Int_t numberOfVarDim = 0;

// Let see if we can understand the structure of this branch.
// Usually we have: leafname[fixed_array] leaftitle[var_array]\type
// (with fixed_array that can be a multi-dimension array.
const char *tname = leaf->GetTitle();
// Usually we have: leafname[fixed_array], leaftitle[var_array]/type, leaftitle[n]/d[0,10,32]
// (with fixed_array that can be a multi-dimensional array).
TString sname = leaf->GetTitle();
auto slash = sname.First("/");
sname = (slash == TString::kNPOS) ? sname : sname(0, slash);
const char *tname = sname.Data();
char *leaf_dim = (char*)strstr( tname, "[" );

const char *bname = leaf->GetBranch()->GetName();
Expand Down
Loading