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  }