go-hep.org/x/hep@v0.38.1/lcio/cellid.go (about) 1 // Copyright ©2017 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 lcio 6 7 import ( 8 "fmt" 9 "strconv" 10 "strings" 11 ) 12 13 const ( 14 cellIDEncoding = "CellIDEncoding" 15 ) 16 17 // CellIDDecoder decodes cell IDs from a Hit cell-ID 18 type CellIDDecoder struct { 19 bits *bitField64 20 codec string 21 } 22 23 func NewCellIDDecoder(codec string) *CellIDDecoder { 24 return &CellIDDecoder{ 25 codec: codec, 26 bits: newBitField64(codec), 27 } 28 } 29 30 func NewCellIDDecoderFrom(params Params) *CellIDDecoder { 31 codec, ok := params.Strings[cellIDEncoding] 32 if !ok { 33 return nil 34 } 35 return NewCellIDDecoder(codec[0]) 36 } 37 38 func (dec *CellIDDecoder) Get(hit Hit, name string) int64 { 39 i := dec.bits.index[name] 40 dec.bits.value = dec.value(hit) 41 return dec.bits.fields[i].value() 42 } 43 44 func (dec *CellIDDecoder) Value(hit Hit) int64 { 45 dec.bits.value = dec.value(hit) 46 return dec.bits.value 47 } 48 func (dec *CellIDDecoder) ValueString(hit Hit) string { 49 dec.bits.value = dec.value(hit) 50 return dec.bits.valueString() 51 } 52 53 func (dec *CellIDDecoder) value(hit Hit) int64 { 54 return int64(hit.GetCellID0())&0xffffffff | int64(hit.GetCellID1())<<32 55 } 56 57 type bitField64 struct { 58 fields []bitFieldValue 59 value int64 60 index map[string]int 61 } 62 63 func newBitField64(codec string) *bitField64 { 64 var bf bitField64 65 toks := strings.Split(codec, ",") 66 cur := 0 67 for _, tok := range toks { 68 subfields := strings.Split(tok, ":") 69 var ( 70 field = bitFieldValue{bits: &bf.value} 71 err error 72 ) 73 switch len(subfields) { 74 case 2: 75 field.name = subfields[0] 76 field.width, err = strconv.Atoi(subfields[1]) 77 if err != nil { 78 panic(err) 79 } 80 field.offset = cur 81 cur += iabs(field.width) 82 case 3: 83 field.name = subfields[0] 84 field.offset, err = strconv.Atoi(subfields[1]) 85 if err != nil { 86 panic(err) 87 } 88 field.width, err = strconv.Atoi(subfields[2]) 89 if err != nil { 90 panic(err) 91 } 92 cur = field.offset + iabs(field.width) 93 default: 94 panic(fmt.Errorf("lcio: invalid number of subfields: %q", tok)) 95 } 96 field.signed = field.width < 0 97 field.width = iabs(field.width) 98 field.mask = ((0x0001 << uint64(field.width)) - 1) << uint64(field.offset) 99 bf.fields = append(bf.fields, field) 100 } 101 102 bf.index = make(map[string]int, len(bf.fields)) 103 for i, v := range bf.fields { 104 bf.index[v.name] = i 105 } 106 return &bf 107 } 108 109 func (bf *bitField64) Description() string { 110 o := new(strings.Builder) 111 for i, v := range bf.fields { 112 format := "%s:%d:%d" 113 if i != 0 { 114 format = "," + format 115 } 116 width := v.width 117 if v.signed { 118 width = -v.width 119 } 120 fmt.Fprintf(o, format, v.name, v.offset, width) 121 } 122 return o.String() 123 } 124 125 func (bf *bitField64) valueString() string { 126 o := new(strings.Builder) 127 for i, v := range bf.fields { 128 format := "%s:%d" 129 if i != 0 { 130 format = "," + format 131 } 132 fmt.Fprintf(o, format, v.name, v.value()) 133 } 134 return o.String() 135 } 136 137 type bitFieldValue struct { 138 bits *int64 139 mask int64 140 name string 141 offset int 142 width int 143 signed bool 144 } 145 146 func (bfv *bitFieldValue) value() int64 { 147 bits := *bfv.bits 148 val := bits & bfv.mask >> uint64(bfv.offset) 149 150 if bfv.signed { 151 if val&(1<<uint64(bfv.width-1)) != 0 { // negative value 152 val -= 1 << uint64(bfv.width) 153 } 154 } 155 return val 156 } 157 158 func iabs(v int) int { 159 if v < 0 { 160 return -v 161 } 162 return v 163 }