Skip to content

Commit d23b905

Browse files
ferdymercurypcanal
andauthored
[tree] major and minor indices to long64, it was forgotten to change from 32bit of old interfaces (#14967)
Fixes https://its.cern.ch/jira/browse/ROOT-9028 [treeindex] print error when requesting out of bonds combination 31bit restriction was old, now they have separate 64-bit registers better document old2new [roottest] adapt to new 64bit interface [test] disable tests reaching the limits of ulong64_t since the implicit conversion to long double later leads to platform-dependent test failures [treeindex][nfc] mention that warning is printed at runtime when overflow detected --------- Co-authored-by: Philippe Canal <[email protected]>
1 parent b0868f3 commit d23b905

File tree

7 files changed

+61
-35
lines changed

7 files changed

+61
-35
lines changed
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11

22
Processing runindex64.C...
33
Tree BuildIndex returns 9
4-
Entry should be 3: 3
5-
Entry should be 6: 6
64
Entries in chain: 9
75
BuildIndex returns 9
8-
Try to get value that is not in the chain, this should return a -1:
6+
Try to find the position of run=0, event=500 in the chain, as it does not exist, this should return a -1:
97
-1
10-
3
8+
Try to find the position of run=5, event=bigval in the chain, which was inserted in position 4:
9+
4
1110
Entries in chain: 9
1211
BuildIndex returns 1
13-
Try to get value that is not in the chain, this should return a -1:
12+
Try to find the position of run=0, event=500 in the chain, as it does not exist, this should return a -1:
1413
-1
15-
3
14+
Try to find the position of run=5, event=bigval in the chain, which was inserted in position 4:
15+
4
1616
(int) 0

roottest/root/tree/index/runindex64.C

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@ const char* fname = "index64.root";
88
// Apple M1 has long double == double; these values exceed its range
99
// and cannot be represented as (even temporary) expression results.
1010
// There would be a warning if you'd try.
11-
static constexpr bool shortlongdouble = sizeof(long double) < 16; // was true for __APPLE__ and __arm64__
12-
const Long64_t bigval = shortlongdouble ? 0xFFFFFFFFFFFF : 0xFFFFFFFFFFFFFFF; // still positive number
13-
const ULong64_t biguval = shortlongdouble ? 0xFFFFFFFFFFFF0 : 0xFFFFFFFFFFFFFFF0; // "negative" number
11+
// More info: https://github.com/root-project/roottest/commit/f3c97809c9064feccaed3844007de9e7c6a5980d and https://github.com/root-project/roottest/commit/9e3843d4bf50bc34e6e15dfe7c027f029417d6c0
12+
// static constexpr bool shortlongdouble = sizeof(long double) < 16; // was true for __APPLE__ and __arm64__
13+
// const Long64_t bigval = shortlongdouble ? 0x0FFFFFFFFFFFF : 0x0FFFFFFFFFFFFFFF; // still positive number
14+
// const ULong64_t biguval = shortlongdouble ? 0xFFFFFFFFFFFF0 : 0xFFFFFFFFFFFFFFF0; // "negative" number
15+
const Long64_t bigval = 0xFFFFFFFFFFFF0; // larger values fail on __APPLE__ / __arm64__ because the long double is less than 16 bytes.
16+
// const ULong64_t biguval = bigval;
1417

1518
int runindex64(){
1619

@@ -25,20 +28,30 @@ int runindex64(){
2528
tree->Branch("run", &run, "run/l");
2629
tree->Branch("event", &event, "event/l");
2730

28-
ULong64_t events[] = { 1,2,3, bigval, biguval, 5 };
29-
run = 5;
30-
for(int i=0; i<sizeof(events)/sizeof(*events); i++){
31+
ULong64_t runs[] = { 8,5,5,5, 5, 0, 4, 6, bigval};
32+
ULong64_t events[] = { 0,1,3,2, bigval, 5, bigval, 3, bigval};
33+
for(size_t i=0; i<sizeof(events)/sizeof(*events); i++){
34+
run = runs[i];
3135
event = events[i];
3236
tree->Fill();
3337
}
34-
run = 4; event = bigval; tree->Fill();
35-
run = 6; event = 3; tree->Fill();
36-
run = biguval; event = bigval; tree->Fill();
3738
tree->Write();
38-
39+
40+
bool pass = true;
3941
cout<<"Tree BuildIndex returns "<<tree->BuildIndex("run", "event")<<endl;
40-
cout << "Entry should be 3: " << tree->GetEntryNumberWithIndex(5,bigval) << endl;
41-
cout << "Entry should be 6: " << tree->GetEntryNumberWithIndex(4,bigval) << endl;
42+
for (size_t i=0; i<sizeof(events)/sizeof(*events); i++) {
43+
run = runs[i];
44+
event = events[i];
45+
pass &= (tree->GetEntryNumberWithIndex(run, event) == i);
46+
}
47+
if (!pass) {
48+
tree->Scan("run:event","","colsize=30");
49+
for (size_t i=0; i<sizeof(events)/sizeof(*events); i++) {
50+
run = runs[i];
51+
event = events[i];
52+
cout << i << ": Run " << run << ", Event " << event << " found at entry number: " << tree->GetEntryNumberWithIndex(run, event) << endl;
53+
}
54+
}
4255

4356
test(tree);
4457
file.Close();
@@ -60,8 +73,9 @@ bool test(TTree *chain)
6073
{
6174
cout<<"Entries in chain: "<<chain->GetEntries()<<endl;
6275
cout<<"BuildIndex returns "<<chain->BuildIndex("run", "event")<<endl;
63-
cout<<"Try to get value that is not in the chain, this should return a -1:"<<endl;
76+
cout<<"Try to find the position of run=0, event=500 in the chain, as it does not exist, this should return a -1:"<<endl;
6477
cout<<chain->GetEntryWithIndex(500)<<endl;
65-
cout<<(int)chain->GetEntryNumberWithIndex(5, bigval)<<endl;
66-
return (chain->GetEntryNumberWithIndex(500)==-1);
78+
cout<<"Try to find the position of run=5, event=bigval in the chain, which was inserted in position 4:"<<endl;
79+
cout<<chain->GetEntryNumberWithIndex(5, bigval)<<endl;
80+
return (chain->GetEntryNumberWithIndex(500)==-1) && (chain->GetEntryNumberWithIndex(5, bigval) == 4);
6781
}

tree/tree/inc/TChain.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class TChain : public TTree {
104104
Long64_t GetEntries(const char *sel) override { return TTree::GetEntries(sel); }
105105
Int_t GetEntry(Long64_t entry=0, Int_t getall=0) override;
106106
Long64_t GetEntryNumber(Long64_t entry) const override;
107-
Int_t GetEntryWithIndex(Int_t major, Int_t minor=0) override;
107+
Int_t GetEntryWithIndex(Long64_t major, Long64_t minor=0) override;
108108
TFile *GetFile() const;
109109
TLeaf *GetLeaf(const char* branchname, const char* leafname) override;
110110
TLeaf *GetLeaf(const char* name) override;

tree/tree/inc/TTree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ class TTree : public TNamed, public TAttLine, public TAttFill, public TAttMarker
541541
virtual Long64_t GetEstimate() const { return fEstimate; }
542542
virtual Int_t GetEntry(Long64_t entry, Int_t getall = 0);
543543
Int_t GetEvent(Long64_t entry, Int_t getall = 0) { return GetEntry(entry, getall); }
544-
virtual Int_t GetEntryWithIndex(Int_t major, Int_t minor = 0);
544+
virtual Int_t GetEntryWithIndex(Long64_t major, Long64_t minor = 0);
545545
virtual Long64_t GetEntryNumberWithBestIndex(Long64_t major, Long64_t minor = 0) const;
546546
virtual Long64_t GetEntryNumberWithIndex(Long64_t major, Long64_t minor = 0) const;
547547
TEventList *GetEventList() const { return fEventList; }

tree/tree/src/TChain.cxx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -972,13 +972,14 @@ Long64_t TChain::GetEntryNumber(Long64_t entry) const
972972
////////////////////////////////////////////////////////////////////////////////
973973
/// Return entry corresponding to major and minor number.
974974
///
975-
/// The function returns the total number of bytes read.
975+
/// The function returns the total number of bytes read; -1 if entry not found.
976976
/// If the Tree has friend trees, the corresponding entry with
977977
/// the index values (major,minor) is read. Note that the master Tree
978978
/// and its friend may have different entry serial numbers corresponding
979979
/// to (major,minor).
980+
/// \note See TTreeIndex::GetEntryNumberWithIndex for information about the maximum values accepted for major and minor
980981

981-
Int_t TChain::GetEntryWithIndex(Int_t major, Int_t minor)
982+
Int_t TChain::GetEntryWithIndex(Long64_t major, Long64_t minor)
982983
{
983984
Long64_t serial = GetEntryNumberWithIndex(major, minor);
984985
if (serial < 0) return -1;

tree/tree/src/TTree.cxx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5998,13 +5998,14 @@ Long64_t TTree::GetEntryNumberWithIndex(Long64_t major, Long64_t minor) const
59985998
////////////////////////////////////////////////////////////////////////////////
59995999
/// Read entry corresponding to major and minor number.
60006000
///
6001-
/// The function returns the total number of bytes read.
6001+
/// The function returns the total number of bytes read; -1 if entry not found.
60026002
/// If the Tree has friend trees, the corresponding entry with
60036003
/// the index values (major,minor) is read. Note that the master Tree
60046004
/// and its friend may have different entry serial numbers corresponding
60056005
/// to (major,minor).
6006+
/// \note See TTreeIndex::GetEntryNumberWithIndex for information about the maximum values accepted for major and minor
60066007

6007-
Int_t TTree::GetEntryWithIndex(Int_t major, Int_t minor)
6008+
Int_t TTree::GetEntryWithIndex(Long64_t major, Long64_t minor)
60086009
{
60096010
// We already have been visited while recursively looking
60106011
// through the friends tree, let's return.

tree/treeplayer/src/TTreeIndex.cxx

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,11 @@ void TTreeIndex::Append(const TVirtualIndex *add, bool delaySort )
329329

330330

331331
////////////////////////////////////////////////////////////////////////////////
332-
/// conversion from old 64bit indexes
333-
/// return true if index was converted
332+
/// Conversion from old 64bit indexes.
333+
/// Before, major and minor were stored as a single 64-bit register, with
334+
/// bits [0,30] for minor and bits [31,64] for major.
335+
/// Now, both minor and major have their own 64-bit register.
336+
/// \return true if index was converted
334337

335338
bool TTreeIndex::ConvertOldToNew()
336339
{
@@ -353,6 +356,7 @@ bool TTreeIndex::ConvertOldToNew()
353356
/// In case this (friend) Tree and 'master' do not share an index with the same
354357
/// major and minor name, the entry serial number in the (friend) tree
355358
/// and in the master Tree are assumed to be the same
359+
/// \note An internal (intermediate) cast to double before storage as Long64_t
356360

357361
Long64_t TTreeIndex::GetEntryNumberFriend(const TTree *parent)
358362
{
@@ -415,11 +419,16 @@ Long64_t TTreeIndex::FindValues(Long64_t major, Long64_t minor) const
415419
/// Return entry number corresponding to major and minor number.
416420
/// Note that this function returns only the entry number, not the data
417421
/// To read the data corresponding to an entry number, use TTree::GetEntryWithIndex
418-
/// the BuildIndex function has created a table of Double_t* of sorted values
419-
/// corresponding to val = major<<31 + minor;
422+
/// the BuildIndex function has created two tables of Long64_t sorted values
423+
/// (with an internal intermediate cast to LongDouble)
420424
/// The function performs binary search in this sorted table.
421425
/// If it finds a pair that maches val, it returns directly the
422-
/// index in the table.
426+
/// index in the table, otherwise it returns -1.
427+
/// \warning Due to internal architecture details, the maximum value for `(major, minor)`
428+
/// for which the function works correctly and consistently in all platforms is `0xFFFFFFFFFFFF0`, which is less than `kMaxLong64`.
429+
/// A runtime-warning will be printed if values above this range are detected to lead to a corresponding precision loss in your current architecture:
430+
/// `Warning in <TTreeIndex::TTreeIndex>: In tree entry, value event possibly out of range for internal long double`
431+
///
423432
/// If an entry corresponding to major and minor is not found, the function
424433
/// returns the index of the major,minor pair immediately lower than the
425434
/// requested value, ie it will return -1 if the pair is lower than
@@ -430,7 +439,6 @@ Long64_t TTreeIndex::FindValues(Long64_t major, Long64_t minor) const
430439
Long64_t TTreeIndex::GetEntryNumberWithBestIndex(Long64_t major, Long64_t minor) const
431440
{
432441
if (fN == 0) return -1;
433-
434442
Long64_t pos = FindValues(major, minor);
435443
if( pos < fN && fIndexValues[pos] == major && fIndexValuesMinor[pos] == minor )
436444
return fIndex[pos];
@@ -444,11 +452,13 @@ Long64_t TTreeIndex::GetEntryNumberWithBestIndex(Long64_t major, Long64_t minor)
444452
/// Return entry number corresponding to major and minor number.
445453
/// Note that this function returns only the entry number, not the data
446454
/// To read the data corresponding to an entry number, use TTree::GetEntryWithIndex
447-
/// the BuildIndex function has created a table of Double_t* of sorted values
448-
/// corresponding to val = major<<31 + minor;
455+
/// the BuildIndex function has created two tables of Long64_t sorted values
456+
/// (with an internal intermediate cast to LongDouble)
449457
/// The function performs binary search in this sorted table.
450458
/// If it finds a pair that maches val, it returns directly the
451459
/// index in the table, otherwise it returns -1.
460+
/// \warning Due to internal architecture details, the maximum value for `(major, minor)`
461+
/// for which the function works correctly and consistently in all platforms is `0xFFFFFFFFFFFF0`, which is less than `kMaxLong64`.
452462
///
453463
/// See also GetEntryNumberWithBestIndex
454464

0 commit comments

Comments
 (0)