go-hep.org/x/hep@v0.38.1/groot/rdict/visit.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 rdict 6 7 import ( 8 "fmt" 9 "strings" 10 11 "go-hep.org/x/hep/groot/rbytes" 12 "go-hep.org/x/hep/groot/rmeta" 13 ) 14 15 // Visit inspects a streamer info and visits all its elements, once. 16 func Visit(ctx rbytes.StreamerInfoContext, si rbytes.StreamerInfo, f func(depth int, se rbytes.StreamerElement) error) error { 17 v := newVisitor(ctx, f) 18 return v.run(0, si) 19 } 20 21 type visitor struct { 22 ctx rbytes.StreamerInfoContext 23 set map[rbytes.StreamerElement]struct{} 24 f func(depth int, se rbytes.StreamerElement) error 25 } 26 27 func newVisitor(ctx rbytes.StreamerInfoContext, f func(depth int, se rbytes.StreamerElement) error) *visitor { 28 if ctx == nil { 29 ctx = StreamerInfos 30 } 31 return &visitor{ 32 ctx: ctx, 33 set: make(map[rbytes.StreamerElement]struct{}), 34 f: f, 35 } 36 } 37 38 func (v *visitor) seen(se rbytes.StreamerElement) bool { 39 if _, seen := v.set[se]; seen { 40 return true 41 } 42 v.set[se] = struct{}{} 43 return false 44 } 45 46 func (v *visitor) run(depth int, si rbytes.StreamerInfo) error { 47 for _, se := range si.Elements() { 48 err := v.visitSE(depth, se) 49 if err != nil { 50 return err 51 } 52 } 53 return nil 54 } 55 56 func (v *visitor) visitSE(depth int, se rbytes.StreamerElement) error { 57 if v.seen(se) { 58 return nil 59 } 60 61 err := v.f(depth, se) 62 if err != nil { 63 return err 64 } 65 66 switch se.TypeName() { 67 case "TVirtualIndex", "TVirtualIndex*": 68 return nil 69 } 70 71 switch se := se.(type) { 72 case *StreamerBasicType: 73 // no-op 74 case *StreamerBasicPointer: 75 // no-op 76 77 case *StreamerBase: 78 base, err := v.ctx.StreamerInfo(se.Name(), -1) 79 if err != nil { 80 return fmt.Errorf("could not find base %q: %w", se.Name(), err) 81 } 82 return v.run(depth+1, base) 83 case *StreamerObject: 84 si, err := v.ctx.StreamerInfo(se.TypeName(), -1) 85 if err != nil { 86 return fmt.Errorf("could not find object %q: %w", se.TypeName(), err) 87 } 88 return v.run(depth+1, si) 89 90 case *StreamerObjectPointer: 91 tname := strings.TrimRight(se.TypeName(), "*") 92 si, err := v.ctx.StreamerInfo(tname, -1) 93 if err != nil { 94 return fmt.Errorf("could not find object-pointer %q: %w", tname, err) 95 } 96 return v.run(depth+1, si) 97 98 case *StreamerObjectAny: 99 tname := se.TypeName() 100 si, err := v.ctx.StreamerInfo(tname, -1) 101 if err != nil { 102 return fmt.Errorf("could not find object-any %q: %w", tname, err) 103 } 104 return v.run(depth+1, si) 105 106 case *StreamerObjectAnyPointer: 107 tname := strings.TrimRight(se.TypeName(), "*") 108 si, err := v.ctx.StreamerInfo(tname, -1) 109 if err != nil { 110 return fmt.Errorf("could not find object-any-pointer %q: %w", tname, err) 111 } 112 return v.run(depth+1, si) 113 114 case *StreamerString, *StreamerSTLstring: 115 // no-op 116 117 case *StreamerSTL: 118 switch se.STLType() { 119 case rmeta.STLdeque, rmeta.STLforwardlist, rmeta.STLlist, 120 rmeta.STLset, rmeta.STLunorderedset, rmeta.STLunorderedmultiset, 121 rmeta.STLvector: 122 123 etn := se.ElemTypeName() 124 tname := strings.TrimRight(etn[0], "*") 125 if _, ok := rmeta.CxxBuiltins[tname]; ok { 126 // no-op: C++ builtin. 127 return nil 128 } 129 si, err := v.ctx.StreamerInfo(tname, -1) 130 if err != nil { 131 return fmt.Errorf("could not find std::container<T> element %q: %w", tname, err) 132 } 133 return v.run(depth+1, si) 134 135 default: 136 return fmt.Errorf("rdict: cant visit non-vector-like STL streamers %#v", se) 137 } 138 139 case *StreamerLoop: 140 tname := strings.TrimRight(se.TypeName(), "*") 141 if _, ok := rmeta.CxxBuiltins[tname]; ok { 142 // no-op: C++ builtin. 143 return nil 144 } 145 si, err := v.ctx.StreamerInfo(tname, -1) 146 if err != nil { 147 return fmt.Errorf("could not find looper %q: %w", tname, err) 148 } 149 return v.run(depth+1, si) 150 151 default: 152 panic(fmt.Errorf("rdict: unknown visit streamer %T", se)) 153 } 154 155 return nil 156 }