go-hep.org/x/hep@v0.38.1/groot/rtree/chain.go (about) 1 // Copyright ©2018 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package rtree 6 7 import ( 8 "fmt" 9 10 "go-hep.org/x/hep/groot/riofs" 11 "go-hep.org/x/hep/groot/root" 12 ) 13 14 type chain struct { 15 trees []Tree 16 offs []int64 // number of entries before this tree 17 tots []int64 // total number of entries up to this tree 18 19 cur int // index of current tree 20 tree Tree // current tree 21 off int64 // current offset 22 tot int64 // current number of entries 23 } 24 25 // Chain returns a Tree that is the concatenation of all the input Trees. 26 func Chain(trees ...Tree) Tree { 27 if len(trees) == 0 { 28 return &chain{} 29 } 30 n := len(trees) 31 ch := &chain{ 32 trees: make([]Tree, n), 33 offs: make([]int64, n), 34 tots: make([]int64, n), 35 cur: -1, 36 } 37 var ( 38 sum int64 39 off int64 40 ) 41 for i := range trees { 42 t := trees[i] 43 n := t.Entries() 44 sum += n 45 ch.trees[i] = t 46 ch.offs[i] = off 47 ch.tots[i] = sum 48 off += n 49 } 50 51 ch.loadTree(ch.cur + 1) 52 return ch 53 } 54 55 // ChainOf returns a Tree, a close function and an error if any. 56 // The tree is the logical concatenation of all the name trees 57 // located in the input named files. 58 // The close function allows to close all the open named files. 59 func ChainOf(name string, files ...string) (Tree, func() error, error) { 60 var ( 61 trees = make([]Tree, len(files)) 62 fs = make([]*riofs.File, len(files)) 63 ) 64 65 closef := func(fs []*riofs.File) { 66 for _, f := range fs { 67 if f == nil { 68 continue 69 } 70 f.Close() 71 } 72 } 73 74 for i, n := range files { 75 f, err := riofs.Open(n) 76 if err != nil { 77 closef(fs) 78 return nil, nil, err 79 } 80 fs[i] = f 81 obj, err := f.Get(name) 82 if err != nil { 83 closef(fs) 84 return nil, nil, err 85 } 86 t, ok := obj.(Tree) 87 if !ok { 88 closef(fs) 89 return nil, nil, fmt.Errorf("rtree: object %q in file %q is not a Tree", name, n) 90 } 91 92 trees[i] = t 93 } 94 95 ch := Chain(trees...) 96 close := func() error { 97 var err error 98 for _, f := range fs { 99 e := f.Close() 100 if e != nil && err == nil { 101 err = e 102 } 103 } 104 return err 105 } 106 107 return ch, close, nil 108 } 109 110 func (ch *chain) loadTree(i int) { 111 ch.cur = i 112 if ch.cur >= len(ch.trees) { 113 ch.tree = nil 114 return 115 } 116 ch.tree = ch.trees[ch.cur] 117 ch.off = ch.offs[ch.cur] 118 ch.tot = ch.tots[ch.cur] 119 } 120 121 // Class returns the ROOT class of the argument. 122 func (*chain) Class() string { 123 return "TChain" 124 } 125 126 // Name returns the name of the ROOT objet in the argument. 127 func (t *chain) Name() string { 128 if t.tree == nil { 129 return "" 130 } 131 return t.tree.Name() 132 } 133 134 // Title returns the title of the ROOT object in the argument. 135 func (t *chain) Title() string { 136 if t.tree == nil { 137 return "" 138 } 139 return t.tree.Title() 140 } 141 142 // Entries returns the total number of entries. 143 func (t *chain) Entries() int64 { 144 var v int64 145 for _, tree := range t.trees { 146 v += tree.Entries() 147 } 148 return v 149 } 150 151 // Branches returns the list of branches. 152 func (t *chain) Branches() []Branch { 153 if t.tree == nil { 154 return nil 155 } 156 return t.tree.Branches() 157 } 158 159 // Branch returns the branch whose name is the argument. 160 func (t *chain) Branch(name string) Branch { 161 if t.tree == nil { 162 return nil 163 } 164 return t.tree.Branch(name) 165 } 166 167 // Leaves returns direct pointers to individual branch leaves. 168 func (t *chain) Leaves() []Leaf { 169 if t.tree == nil { 170 return nil 171 } 172 return t.tree.Leaves() 173 } 174 175 // Leaf returns the leaf whose name is the argument. 176 func (t *chain) Leaf(name string) Leaf { 177 if t.tree == nil { 178 return nil 179 } 180 return t.tree.Leaf(name) 181 } 182 183 var ( 184 _ root.Object = (*chain)(nil) 185 _ root.Named = (*chain)(nil) 186 _ Tree = (*chain)(nil) 187 )