diff --git a/DDCore/include/DD4hep/BitField64.h b/DDCore/include/DD4hep/BitField64.h new file mode 100644 index 0000000000000000000000000000000000000000..36fb91b70d33cb523fb222bc4fd8cc82f76156cc --- /dev/null +++ b/DDCore/include/DD4hep/BitField64.h @@ -0,0 +1,292 @@ +#ifndef DD4hep_BitField64_H +#define DD4hep_BitField64_H 1 + +#include <iostream> + +#include <string> +#include <vector> +#include <map> +#include <sstream> + + +namespace DD4hep { + + //fixme: do need to do this also for 32 bit machines ? + typedef long long64 ; + typedef unsigned long ulong64 ; + + + class BitFieldValue ; + class StringTokenizer ; + + + /** A bit field of 64bits that allows convenient declaration and + * manipulation of sub fields of various widths.<br> + * Example:<br> + * BitField64 b("layer:7,system:-3,barrel:3,theta:32:11,phi:11" ) ; <br> + * b[ "layer" ] = 123 ; <br> + * b[ "system" ] = -4 ; <br> + * b[ "barrel" ] = 7 ; <br> + * b[ "theta" ] = 180 ; <br> + * b[ "phi" ] = 270 ; <br> + * ... <br> + * int theta = b["theta"] ; <br> + * ... <br> + * unsigned phiIndex = b.index("phi) ; <br> + * int phi = b[ phiIndex ] ; <br> + * + * @author F.Gaede, DESY + * @version $Id:$ + * @date 2013-06 + */ + class BitField64{ + + friend std::ostream& operator<<(std::ostream& os, const BitField64& b) ; + + public : + + typedef std::map<std::string, unsigned int> IndexMap ; + + + ~BitField64() { // clean up + for(unsigned i=0;i<_fields.size();i++){ + delete _fields[i] ; + } + } + + /** The c'tor takes an initialization string of the form:<br> + * <fieldDesc>[,<fieldDesc>...]<br> + * fieldDesc = name:[start]:[-]length<br> + * where:<br> + * name: The name of the field<br> + * start: The start bit of the field. If omitted assumed to start + * immediately following previous field, or at the least significant + * bit if the first field.<br> + * length: The number of bits in the field. If preceeded by '-' + * the field is signed, otherwise unsigned.<br> + * Bit numbering is from the least significant bit (bit 0) to the most + * significant (bit 63). <br> + * Example: "layer:7,system:-3,barrel:3,theta:32:11,phi:11" + */ + BitField64( const std::string& initString ) : _value(0), _joined(0){ + + init( initString ) ; + } + + /** Returns the current 64bit value + */ + long64 getValue() const { return _value ; } + + /** Set a new 64bit value + */ + void setValue(long64 value ) { _value = value ; } + + /** Reset - same as setValue(0) - useful if the same encoder is used for many objects. + */ + void reset() { _value = 0 ; } + + /** Acces to field through index + */ + BitFieldValue& operator[](size_t index) { + return *_fields.at( index ) ; + } + + /** Const acces to field through index + */ + const BitFieldValue& operator[](size_t index) const { + return *_fields.at( index ) ; + } + + /** Highest bit used in fields [0-63] + */ + unsigned highestBit() const ; + + /** Number of values */ + size_t size() const { return _fields.size() ; } + + /** Index for field named 'name' + */ + size_t index( const std::string& name) const ; + + /** Access to field through name . + */ + BitFieldValue& operator[](const std::string& name) { + + return *_fields[ index( name ) ] ; + } + /** Const Access to field through name . + */ + const BitFieldValue& operator[](const std::string& name) const { + + return *_fields[ index( name ) ] ; + } + + + /** The low word, bits 0-31 + */ + unsigned lowWord() const { return unsigned( _value & 0xffffFFFF ) ; } + + /** The high word, bits 32-63 + */ + unsigned highWord() const { return unsigned( _value >> 32 ) ; } + + + /** Return a valid description string of all fields + */ + std::string fieldDescription() const ; + + /** Return a string with a comma separated list of the current sub field values + */ + std::string valueString() const ; + + protected: + + /** Add an additional field to the list + */ + void addField( const std::string& name, unsigned offset, int width ); + + /** Decode the initialization string as described in the constructor. + * @see BitField64( const std::string& initString ) + */ + void init( const std::string& initString) ; + + /** No default c'tor */ + BitField64() : _value(0) , _joined(0) { } + + + // -------------- data members:-------------- + + std::vector<BitFieldValue*> _fields ; + long64 _value ; + IndexMap _map ; + long64 _joined ; + + + }; + + + + /** Operator for dumping BitField64 to streams + */ + std::ostream& operator<<(std::ostream& os, const BitField64& b) ; + + + + /** Helper class for string tokenization. Usage:<br> + * std::vector<std::string> tokens ; <br> + * StringTokenizer t( tokens ,',') ; <br> + * std::for_each( aString.begin(), aString.end(), t ) ; <br> + * + * @author F.Gaede, DESY + * @date 2013-06 + */ + class StringTokenizer{ + + std::vector< std::string >& _tokens ; + char _del ; + char _last ; + + public: + + /** Only c'tor, give (empty) token vector and delimeter character */ + StringTokenizer( std::vector< std::string >& tokens, char del ) + : _tokens(tokens) + , _del(del), + _last(del) { + } + + /** Operator for use with algorithms, e.g. for_each */ + void operator()(const char& c) { + + if( c != _del ) { + + if( _last == _del ) { + _tokens.push_back("") ; + } + _tokens.back() += c ; + } + _last = c ; + } + + }; + + + /** Helper class for BitField64 that corresponds to one field value. + * @author F.Gaede, DESY + * @date 2013-06 + */ + + class BitFieldValue{ + + public : + virtual ~BitFieldValue() {} + + /** The default c'tor. + * @param bitfield reference to the 64bit bitfield + * @param offset offset of field + * @param signedWidth width of field, negative if field is signed + */ + BitFieldValue( long64& bitfield, const std::string& name, + unsigned offset, int signedWidth ) ; + + + /** Returns the current field value + */ + long64 value() const ; + + /** Assignment operator for user convenience + */ + BitFieldValue& operator=(long64 in) ; + + /** Conversion operator for long64 - allows to write:<br> + * long64 index = myBitFieldValue ; + */ + operator long64() const { return value() ; } + + /** fg: removed because it causes ambiguities with operator long64(). + * Conversion operator for int - allows to write:<br> + * int index = myBitFieldValue ; + */ + // operator int() const { return (int) value() ; } + + /** The field's name */ + const std::string& name() const { return _name ; } + + /** The field's offset */ + unsigned offset() const { return _offset ; } + + /** The field's width */ + unsigned width() const { return _width ; } + + /** True if field is interpreted as signed */ + bool isSigned() const { return _isSigned ; } + + /** The field's mask */ + ulong64 mask() const { return _mask ; } + + + protected: + + long64& _b ; + ulong64 _mask ; + std::string _name ; + unsigned _offset ; + unsigned _width ; + int _minVal ; + int _maxVal ; + bool _isSigned ; + + }; + + + + + + +} // end namespace + +#endif + + + + diff --git a/DDCore/src/BitField64.cpp b/DDCore/src/BitField64.cpp new file mode 100644 index 0000000000000000000000000000000000000000..515450ab69cb4d3e957f1512fa0d468e9b58d6a7 --- /dev/null +++ b/DDCore/src/BitField64.cpp @@ -0,0 +1,275 @@ +#include "DD4hep/BitField64.h" + +#include <cmath> +#include <algorithm> +#include <stdexcept> + +namespace DD4hep{ + + + BitFieldValue::BitFieldValue( long64& bitfield, const std::string& name, + unsigned offset, int signedWidth ) : + _b(bitfield), + _mask(0), + _name( name ), + _offset( offset ), + _width( abs( signedWidth ) ), + _minVal(0), + _maxVal(0), + _isSigned( signedWidth < 0 ) { + + // sanity check + if( offset > 63 || offset+_width > 64 ) { + + std::stringstream s ; + s << " BitFieldValue '" << _name << "': out of range - offset : " + << offset << " width " << _width ; + + throw( std::runtime_error( s.str() ) ) ; + } + + _mask = ( ( 0x0001LL << _width ) - 1 ) << offset ; + + + // compute extreme values for later checks + if( _isSigned ){ + + _minVal = ( 1LL << ( _width - 1 ) ) - ( 1LL << _width ) ; + _maxVal = ( 1LL << ( _width - 1 ) ) - 1 ; + + } else { + + _maxVal = 0x0001<<_width ; + } + + // std::cout << " _mask :" << std::hex << _mask + // << std::dec << std::endl ; + // std::cout << " min " << _minVal + // << " max " << _maxVal + // << " width " << _width + // << std::endl ; + + } + + + long64 BitFieldValue::value() const { + + if( _isSigned ) { + + long64 val = ( _b & _mask ) >> _offset ; + + if( ( val & ( 1LL << ( _width - 1 ) ) ) != 0 ) { // negative value + + val -= ( 1LL << _width ); + } + + return val ; + + } else { + + return ( _b & _mask ) >> _offset ; + } + } + + BitFieldValue& BitFieldValue::operator=(long64 in) { + + // check range + if( in < _minVal || in > _maxVal ) { + + std::stringstream s ; + s << " BitFieldValue '" << _name << "': out of range : " << in + << " for width " << _width ; + + throw( std::runtime_error( s.str() ) ); + } + + _b &= ~_mask ; // zero out the field's range + + _b |= ( ( in << _offset ) & _mask ) ; + + return *this ; + } + + + + + size_t BitField64::index( const std::string& name) const { + + IndexMap::const_iterator it = _map.find( name ) ; + + if( it != _map.end() ) + + return it->second ; + + else + throw std::runtime_error(" BitFieldValue: unknown name: " + name ) ; + } + + unsigned BitField64::highestBit() const { + + unsigned hb(0) ; + + for(unsigned i=0;i<_fields.size();i++){ + + if( hb < ( _fields[i]->offset() + _fields[i]->width() ) ) + hb = _fields[i]->offset() + _fields[i]->width() ; + } + return hb ; + } + + + std::string BitField64::valueString() const { + + std::stringstream os ; + + for(unsigned i=0;i<_fields.size();i++){ + + if( i != 0 ) os << "," ; + + os << _fields[i]->name() << ":" << _fields[i]->value() ; + + } + return os.str() ; + } + + std::string BitField64::fieldDescription() const { + + std::stringstream os ; + + for(unsigned i=0;i<_fields.size();i++){ + + if( i != 0 ) os << "," ; + + os << _fields[i]->name() << ":" + << _fields[i]->offset() << ":" ; + + if( _fields[i]->isSigned() ) + os << "-" ; + + os << _fields[i]->width() ; + + } +// for( IndexMap::const_iterator it = _map.begin() ; +// it != _map.end() ; ++it ){ + +// if( it != _map.begin() ) +// os << "," ; + +// os << it->first << ":" +// << _fields[ it->second ]->offset() << ":" ; + +// if( _fields[ it->second ]->isSigned() ) +// os << "-" ; + +// os << _fields[ it->second ]->width() ; + +// } + + return os.str() ; + } + + void BitField64::addField( const std::string& name, unsigned offset, int width ){ + + + BitFieldValue* bfv = new BitFieldValue( _value, name, offset, width ) ; + + _fields.push_back( bfv ) ; + + _map[ name ] = _fields.size()-1 ; + + if( _joined & bfv->mask() ) { + + std::stringstream s ; + s << " BitFieldValue::addField(" << name << "): bits already used " << std::hex << _joined + << " for mask " << bfv->mask() ; + + throw( std::runtime_error( s.str() ) ) ; + + } + + _joined |= _fields.back()->mask() ; + + } + + void BitField64::init( const std::string& initString) { + + unsigned offset = 0 ; + + // need to compute bit field masks and offsets ... + std::vector<std::string> fieldDescriptors ; + StringTokenizer t( fieldDescriptors ,',') ; + + std::for_each( initString.begin(), initString.end(), t ) ; + + for(unsigned i=0; i< fieldDescriptors.size() ; i++ ){ + + std::vector<std::string> subfields ; + StringTokenizer ts( subfields ,':') ; + + std::for_each( fieldDescriptors[i].begin(), fieldDescriptors[i].end(), ts ); + + std::string name ; + int width ; + unsigned thisOffset ; + + switch( subfields.size() ){ + + case 2: + + name = subfields[0] ; + width = atol( subfields[1].c_str() ) ; + thisOffset = offset ; + + offset += abs( width ) ; + + break ; + + case 3: + name = subfields[0] ; + thisOffset = atol( subfields[1].c_str() ) ; + width = atol( subfields[2].c_str() ) ; + + offset = thisOffset + abs( width ) ; + + break ; + + default: + + std::stringstream s ; + s << " BitField64: invalid number of subfields " + << fieldDescriptors[i] ; + + throw( std::runtime_error( s.str() ) ) ; + } + + addField( name , thisOffset, width ) ; + } + } + + + + std::ostream& operator<<(std::ostream& os, const BitField64& b){ + + os << " bitfield: 0x" << std::hex // << std::ios::width(16) << std::ios::fill('0') << + << b._value << std::dec << std::endl ; + + for( BitField64::IndexMap::const_iterator it = b._map.begin() ; + it != b._map.end() ; ++it ){ + + os << " " << it->first << " [" << b[ it->second ].offset() << ":" ; + + if( b[ it->second ].isSigned() ) os << "-" ; + + os << b[ it->second ].width() << "] : " ; + + + os << b[ it->second ].value() + << std::endl ; + + } + + return os ; + } + +} // namespace +