go-hep.org/x/hep@v0.38.1/groot/rcont/clonesarray.go (about) 1 // Copyright ©2019 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 rcont 6 7 import ( 8 "fmt" 9 "reflect" 10 "strconv" 11 "strings" 12 13 "go-hep.org/x/hep/groot/rbytes" 14 "go-hep.org/x/hep/groot/root" 15 "go-hep.org/x/hep/groot/rtypes" 16 "go-hep.org/x/hep/groot/rvers" 17 ) 18 19 // ClonesArray implements a ROOT TClonesArray. 20 type ClonesArray struct { 21 arr ObjArray 22 cls string 23 } 24 25 func NewClonesArray() *ClonesArray { 26 arr := &ClonesArray{ 27 arr: *NewObjArray(), 28 } 29 arr.BypassStreamer(false) 30 arr.arr.obj.SetBits(rbytes.CannotHandleMemberWiseStreaming) 31 return arr 32 } 33 34 func (*ClonesArray) RVersion() int16 { 35 return rvers.ClonesArray 36 } 37 38 func (arr *ClonesArray) Class() string { 39 return "TClonesArray" 40 } 41 42 func (arr *ClonesArray) UID() uint32 { 43 return arr.arr.UID() 44 } 45 46 func (arr *ClonesArray) Name() string { 47 n := arr.arr.name 48 if n == "" { 49 return "TClonesArray" 50 } 51 return n 52 } 53 54 func (arr *ClonesArray) Title() string { 55 return "object title" 56 } 57 58 func (arr *ClonesArray) At(i int) root.Object { 59 return arr.arr.At(i) 60 } 61 62 func (arr *ClonesArray) Last() int { 63 return arr.arr.Last() 64 } 65 66 func (arr *ClonesArray) Len() int { 67 return arr.arr.Len() 68 } 69 70 func (arr *ClonesArray) LowerBound() int { 71 return arr.arr.LowerBound() 72 } 73 74 func (arr *ClonesArray) SetElems(v []root.Object) { 75 if arr.cls == "" { 76 arr.cls = v[0].Class() 77 } 78 arr.arr.SetElems(v) 79 } 80 81 func (arr *ClonesArray) TestBits(bits uint32) bool { 82 return arr.arr.TestBits(bits) 83 } 84 85 func (arr *ClonesArray) BypassStreamer(bypass bool) { 86 switch bypass { 87 case true: 88 arr.arr.obj.SetBit(rbytes.BypassStreamer) 89 default: 90 arr.arr.obj.ResetBit(rbytes.BypassStreamer) 91 } 92 } 93 94 func (arr *ClonesArray) CanBypassStreamer() bool { 95 return arr.TestBits(rbytes.BypassStreamer) 96 } 97 98 // ROOTMarshaler is the interface implemented by an object that can 99 // marshal itself to a ROOT buffer 100 func (arr *ClonesArray) MarshalROOT(w *rbytes.WBuffer) (int, error) { 101 if w.Err() != nil { 102 return 0, w.Err() 103 } 104 105 bypass := false 106 // make sure the status of bypass-streamer is part of the buffer. 107 if arr.TestBits(rbytes.CannotHandleMemberWiseStreaming) { 108 bypass = arr.CanBypassStreamer() 109 arr.BypassStreamer(false) 110 } 111 112 si, err := w.StreamerInfo(arr.cls, -1) 113 if err != nil { 114 w.SetErr(fmt.Errorf("rcont: could not find streamer for TClonesArray element %q: %w", arr.cls, err)) 115 return 0, w.Err() 116 } 117 clsv := si.ClassVersion() 118 119 hdr := w.WriteHeader(arr.Class(), arr.RVersion()) 120 121 w.WriteObject(&arr.arr.obj) 122 w.WriteString(arr.arr.name) 123 w.WriteString(fmt.Sprintf("%s;%d", arr.cls, clsv)) 124 125 w.WriteI32(int32(len(arr.arr.objs))) 126 w.WriteI32(arr.arr.low) 127 128 switch { 129 case arr.CanBypassStreamer(): 130 panic("rcont: writing TClonesArray with streamer by-pass not implemented") 131 default: 132 for i, obj := range arr.arr.objs { 133 switch obj { 134 case nil: 135 w.WriteI8(0) 136 default: 137 w.WriteI8(1) 138 w.WriteObject(obj.(rbytes.Marshaler)) 139 if err := w.Err(); err != nil { 140 return 0, fmt.Errorf("rcont: could not marshal TClonesArray element [%d/%d] (%T): %w", i+1, len(arr.arr.objs), obj, err) 141 } 142 } 143 } 144 } 145 146 if bypass { 147 arr.BypassStreamer(true) 148 } 149 150 return w.SetHeader(hdr) 151 } 152 153 // ROOTUnmarshaler is the interface implemented by an object that can 154 // unmarshal itself from a ROOT buffer 155 func (arr *ClonesArray) UnmarshalROOT(r *rbytes.RBuffer) error { 156 if r.Err() != nil { 157 return r.Err() 158 } 159 160 hdr := r.ReadHeader(arr.Class(), arr.RVersion()) 161 if hdr.Vers > 2 { 162 r.ReadObject(&arr.arr.obj) 163 } 164 if hdr.Vers > 1 { 165 arr.arr.name = r.ReadString() 166 } 167 clsv := r.ReadString() 168 toks := strings.Split(clsv, ";") 169 arr.cls = toks[0] 170 clv, err := strconv.Atoi(toks[1]) 171 if err != nil { 172 if r.Err() == nil { 173 r.SetErr(fmt.Errorf("rcont: could not extract TClonesArray element version: %w", err)) 174 } 175 return r.Err() 176 } 177 178 nobjs := int(r.ReadI32()) 179 if nobjs < 0 { 180 nobjs = -nobjs 181 } 182 arr.arr.low = r.ReadI32() 183 184 arr.arr.objs = make([]root.Object, nobjs) 185 arr.arr.last = nobjs - 1 186 si, err := r.StreamerInfo(arr.cls, clv) 187 if err != nil { 188 if r.Err() == nil { 189 r.SetErr(fmt.Errorf("rcont: could not find TClonesArray's element streamer %q and version=%d: %w", arr.cls, clv, err)) 190 } 191 return r.Err() 192 } 193 fct := rtypes.Factory.Get(si.Name()) 194 195 switch { 196 case arr.TestBits(rbytes.BypassStreamer) && !arr.TestBits(rbytes.CannotHandleMemberWiseStreaming): 197 for i := range arr.arr.objs { 198 obj := fct().Interface().(root.Object) 199 arr.arr.objs[i] = obj 200 } 201 panic("rcont: TClonesArray with BypassStreamer not supported") 202 default: 203 for i := range arr.arr.objs { 204 nch := r.ReadI8() 205 if nch != 0 { 206 obj := fct().Interface().(root.Object) 207 r.ReadObject(obj.(rbytes.Unmarshaler)) 208 if r.Err() != nil { 209 return r.Err() 210 } 211 arr.arr.objs[i] = obj 212 } 213 } 214 } 215 216 r.CheckHeader(hdr) 217 return r.Err() 218 } 219 220 func init() { 221 f := func() reflect.Value { 222 o := NewClonesArray() 223 return reflect.ValueOf(o) 224 } 225 rtypes.Factory.Add("TClonesArray", f) 226 } 227 228 var ( 229 _ root.Object = (*ClonesArray)(nil) 230 _ root.UIDer = (*ClonesArray)(nil) 231 _ root.Named = (*ClonesArray)(nil) 232 _ root.ObjArray = (*ClonesArray)(nil) 233 _ rbytes.Marshaler = (*ClonesArray)(nil) 234 _ rbytes.Unmarshaler = (*ClonesArray)(nil) 235 )