Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:49:31

0001 #pragma once
0002 /**
0003 SBitSet.h
0004 =============
0005 
0006 Used for example from CSGFoundry::Load to implement dynamic prim selection.
0007 
0008 For example with ELV the num_bits_ would be the number of unique solid shapes in the geometry,
0009 with is around 140 for JUNO.  So the bitset provides a way to represent a selection
0010 over those shapes.
0011 
0012 Note that at this level, there are no geometry specifics like names etc... its
0013 just a collection of booleans.
0014 
0015 **/
0016 
0017 #include <vector>
0018 #include <string>
0019 #include <cstring>
0020 #include <cstdint>
0021 #include <sstream>
0022 #include <iomanip>
0023 
0024 #include "sstr.h"
0025 #include "ssys.h"
0026 #include "SName.h"
0027 
0028 
0029 struct SBitSet
0030 {
0031     static std::string Brief( const SBitSet* elv, const SName* id );
0032 
0033     template<typename T>
0034     static T          Value( unsigned num_bits, const char* ekey, const char* fallback );
0035 
0036     template<typename T>
0037     static T          Value( unsigned num_bits, const char* spec );
0038 
0039 
0040     static SBitSet*   Create( unsigned num_bits, const char* ekey, const char* fallback );
0041     static SBitSet*   Create( unsigned num_bits, const char* spec);
0042 
0043 
0044     template<typename T>
0045     static  SBitSet* Create(T value);
0046 
0047 
0048     static int ParseSpec( unsigned num_bits, bool* bits      , const char* spec, bool dump );
0049 
0050     template<typename T>
0051     static void        ParseValue( unsigned num_bits, bool* bits      , T value );
0052 
0053     template<typename T>
0054     static bool IsSet( T value, int ibit );
0055 
0056 
0057     static std::string Desc(  unsigned num_bits, const bool* bits, bool reverse );
0058 
0059     template<typename T>
0060     static std::string DescValue( T val    );
0061 
0062 
0063     static constexpr const char* __level = "SBitSet__level" ;
0064     int         level ;
0065     unsigned    num_bits ;
0066     bool*       bits ;
0067 
0068     // metadata
0069     const char* label ;
0070     const char* spec ;
0071 
0072 
0073     SBitSet( unsigned num_bits);
0074     virtual ~SBitSet();
0075 
0076     void        set_label(const char* label);
0077     void        set_spec( const char* spec);
0078 
0079     void        set(bool all);
0080     void        parse_spec( const char* spec);
0081 
0082 
0083 
0084     template<typename T>
0085     void        parse_value( T value);
0086 
0087     bool        is_set(unsigned pos) const ;
0088 
0089     unsigned    count() const ;
0090     bool        is_all_set() const ;
0091     bool        all() const ;
0092     bool        any() const ;
0093     bool        none() const ;
0094 
0095 
0096     void get_pos( std::vector<unsigned>& pos, bool value ) const ;
0097 
0098     std::string desc() const ;
0099 
0100     template<typename T>
0101     T  value() const ;  // HMM: little or big endian option ?
0102 
0103 
0104     void serialize(std::vector<unsigned char>& buf) const ;
0105     static SBitSet* CreateFromBytes(const std::vector<unsigned char>& bytes);
0106     int compare(const SBitSet* other) const ; // zero when same bits
0107 
0108 };
0109 
0110 
0111 inline std::string SBitSet::Brief( const SBitSet* elv, const SName* id )
0112 {
0113     std::stringstream ss ;
0114     ss << "SBitSet::Brief" ;
0115     std::string str = ss.str();
0116     return str ;
0117 }
0118 
0119 
0120 
0121 template<typename T>
0122 inline T SBitSet::Value( unsigned num_bits, const char* ekey, const char* fallback )
0123 {
0124     SBitSet* bs = Create(num_bits, ekey, fallback);
0125     T val = bs->value<T>() ;
0126     delete bs ;
0127     return val ;
0128 }
0129 
0130 template<typename T>
0131 inline T SBitSet::Value( unsigned num_bits, const char* spec )
0132 {
0133     SBitSet* bs = Create(num_bits, spec);
0134     T val = bs->value<T>() ;
0135     delete bs ;
0136     return val ;
0137 }
0138 
0139 
0140 
0141 
0142 
0143 
0144 /**
0145 SBitSet::Create
0146 -----------------
0147 
0148 1. reads spec from ekey envvar eg:"ELV" with fallback eg:"t"
0149 2.
0150 
0151 **/
0152 
0153 
0154 inline SBitSet* SBitSet::Create(unsigned num_bits, const char* ekey, const char* fallback )
0155 {
0156     const char* spec = ssys::getenvvar(ekey, fallback) ;
0157     SBitSet* bs = Create(num_bits, spec );
0158     if(bs) bs->set_label(ekey);
0159     return bs ;
0160 }
0161 
0162 inline SBitSet* SBitSet::Create(unsigned num_bits, const char* spec )
0163 {
0164     SBitSet* bs = nullptr ;
0165     if(spec)
0166     {
0167         bs = new SBitSet(num_bits);
0168         bs->parse_spec(spec);
0169     }
0170     return bs ;
0171 }
0172 
0173 
0174 template<typename T>
0175 inline SBitSet* SBitSet::Create(T value)
0176 {
0177     unsigned _num_bits = 8*sizeof(T);
0178     SBitSet* bs = new SBitSet(_num_bits);
0179     bs->parse_value(value);
0180     return bs ;
0181 }
0182 
0183 
0184 
0185 
0186 
0187 
0188 
0189 /**
0190 SBitSet::ParseSpec
0191 --------------------
0192 
0193 Interpret spec string into a array of bool indicating positions where bits are set
0194 
0195 with_complement:true
0196     when the first char of spec is '~' or 't' indicating that
0197     all bits are first set *true* and the comma delimited bit positions
0198     provided are set to *false*.
0199 
0200 with_complement:false
0201     without complement token in first char all bit positions are first set *false*
0202     and the bit positions provided are set to *true*.
0203 
0204 Examples with num_bits:8 for brevity:
0205 
0206 * NB : think of the bitset as a sequence, not as a number
0207 
0208 +-------+--------------------+---------------------------------+
0209 | spec  | bits (num_bits:8)  |  notes                          |
0210 +=======+====================+=================================+
0211 |  t    |  11111111          | num_bits all set                |
0212 +-------+--------------------+---------------------------------+
0213 |       |  00000000          | blank string spec               |
0214 +-------+--------------------+---------------------------------+
0215 |  t0   |  01111111          |                                 |
0216 +-------+--------------------+---------------------------------+
0217 |  0    |  10000000          |                                 |
0218 +-------+--------------------+---------------------------------+
0219 |  1    |  01000000          |                                 |
0220 +-------+--------------------+---------------------------------+
0221 |  0,2  |  10100000          |                                 |
0222 +-------+--------------------+---------------------------------+
0223 |  t0,2 |  01011111          |                                 |
0224 +-------+--------------------+---------------------------------+
0225 
0226 * see SBitSetTest for more examples
0227 
0228 TODO: unify the spec approach used by ELV and EMM (EMM uses
0229 a similar but different approach that will cause confusion)
0230 
0231 **/
0232 
0233 inline int SBitSet::ParseSpec( unsigned num_bits, bool* bits,  const char* spec, bool dump )
0234 {
0235     bool with_complement = strlen(spec) > 0 && ( spec[0] == '~' || spec[0] == 't' ) ; // str_ starts with ~ or t
0236     for(unsigned i=0 ; i < num_bits ; i++) bits[i] = with_complement ? true : false ;
0237 
0238     bool with_colon = strlen(spec) >= 2 && spec[1] == ':' ;
0239 
0240     int post_complement =  with_complement ? 1 : 0 ;  // offset to skip the complement first character
0241     int post_colon =  with_colon ? 1 : 0 ;
0242     const char* spec_ = spec + post_complement + post_colon ;
0243 
0244     // HUH: with_colon not used
0245 
0246     if(dump) std::cout
0247         << "[SBitSet::ParseSpec\n"
0248         << " dump " << ( dump ? "YES" : "NO " )
0249         << " num_bits " << num_bits << "\n"
0250         << " spec [" <<  ( spec  ? spec  : "-" ) << "]" << "\n"
0251         << " spec_[" <<  ( spec_ ? spec_ : "-" ) << "]" << "\n"
0252         << " with_complement " << (  with_complement ? "YES" : "NO " ) << "\n"
0253         << " with_colon " << (  with_colon ? "YES" : "NO " ) << "\n"
0254         << "\n"
0255         ;
0256 
0257     std::vector<int> pos ;
0258     char delim = ',' ;
0259     sstr::split<int>( pos,  spec_ , delim );
0260 
0261     int rc = 0;
0262 
0263     for(unsigned i=0 ; i < pos.size() ; i++)
0264     {
0265         int ipos = pos[i] ;
0266         int upos_ = ipos < 0 ? ipos + num_bits : ipos ;
0267 
0268         assert( upos_ > -1 );
0269 
0270         unsigned upos = upos_ ;
0271         bool in_range = upos < num_bits ;
0272         if(!in_range) std::cerr
0273             << "-SBitSet::ParseSpec"
0274             << " i " << i
0275             << " pos.size " << pos.size()
0276             << " ipos " << ipos
0277             << " upos_ " << upos_
0278             << " upos " << upos
0279             << " num_bits " << num_bits
0280             << " in_range " << ( in_range ? "YES" : "NO " )
0281             << "\n"
0282             ;
0283 
0284 
0285         if(!in_range) rc += 1 ;
0286         //assert( expect );
0287 
0288         if(upos < num_bits) bits[upos] = with_complement ? false : true ;
0289     }
0290 
0291     if(dump) std::cout
0292         << " rc " << rc
0293         << "]SBitSet::ParseSpec\n"
0294         ;
0295 
0296     return rc;
0297 
0298 }
0299 
0300 
0301 
0302 
0303 
0304 template<typename T>
0305 inline void SBitSet::ParseValue( unsigned num_bits, bool* bits,  T value )
0306 {
0307     assert( sizeof(T)*8 == num_bits );
0308     for(unsigned i=0 ; i < num_bits ; i++ ) bits[i] = IsSet(value, i) ;
0309 }
0310 
0311 template<typename T>
0312 inline bool SBitSet::IsSet( T value, int _ibit )  // static
0313 {
0314     unsigned num_bits = sizeof(T)*8 ;
0315     T ibit = _ibit < 0 ? _ibit + num_bits : _ibit ;
0316     T mask = 0x1 << ibit ;
0317     bool is_set = ( value & mask ) != 0 ;
0318     return is_set ;
0319 }
0320 
0321 
0322 
0323 inline std::string SBitSet::Desc( unsigned num_bits, const bool* bits, bool reverse )
0324 {
0325     std::stringstream ss ;
0326     ss << std::setw(4) << num_bits << " : " ;
0327     for(unsigned i=0 ; i < num_bits ; i++)  ss << ( bits[reverse ? num_bits - 1 - i : i ] ? "1" : "0" ) ;
0328     std::string str = ss.str();
0329     return str ;
0330 }
0331 
0332 template<typename T>
0333 inline std::string SBitSet::DescValue( T val  )
0334 {
0335     std::stringstream ss ;
0336     ss << "bs.0x" << std::hex << val << std::dec ;
0337     std::string str = ss.str();
0338     return str ;
0339 }
0340 
0341 
0342 
0343 inline bool SBitSet::is_set(unsigned pos) const
0344 {
0345     assert( pos < num_bits );
0346     return bits[pos] ;
0347 }
0348 
0349 inline unsigned SBitSet::count() const
0350 {
0351     unsigned num = 0 ;
0352     for(unsigned i=0 ; i < num_bits ; i++ ) if(bits[i]) num += 1 ;
0353     return num ;
0354 }
0355 
0356 inline bool SBitSet::is_all_set() const { return all() ; }
0357 inline bool SBitSet::all() const { return count() == num_bits ; }
0358 inline bool SBitSet::any() const { return count() > 0  ; }
0359 inline bool SBitSet::none() const { return count() == 0  ; }
0360 
0361 /**
0362 SBitSet::get_pos
0363 -----------------
0364 
0365 Append to *pos* vector bit indices that are set OR notset
0366 depending on *value* bool.
0367 
0368 **/
0369 inline void SBitSet::get_pos( std::vector<unsigned>& pos, bool value) const
0370 {
0371     for(unsigned i=0 ; i < num_bits ; i++ ) if(bits[i] == value) pos.push_back(i) ;
0372 }
0373 
0374 inline SBitSet::SBitSet( unsigned num_bits_ )
0375     :
0376     level(ssys::getenvint(__level,0)),
0377     num_bits(num_bits_),
0378     bits(new bool[num_bits]),
0379     label(nullptr),
0380     spec(nullptr)
0381 {
0382     set(false);
0383 }
0384 
0385 inline void SBitSet::set_label(const char* label_) // eg ELV or EMM
0386 {
0387     label = strdup(label_);
0388 }
0389 inline void SBitSet::set_spec( const char* spec_)  // eg t or t0 t1 t0,1,2
0390 {
0391     spec = strdup(spec_);
0392 }
0393 
0394 
0395 inline void SBitSet::set(bool all)
0396 {
0397     for(unsigned i=0 ; i < num_bits ; i++ )  bits[i] = all ;
0398 }
0399 
0400 
0401 inline void SBitSet::parse_spec(const char* spec)
0402 {
0403     bool dump = level > 0 ;
0404     ParseSpec(num_bits, bits, spec, dump);
0405     set_spec(spec);
0406 }
0407 
0408 template<typename T>
0409 inline void SBitSet::parse_value(T value)
0410 {
0411     ParseValue(num_bits, bits, value);
0412 }
0413 
0414 
0415 
0416 
0417 inline SBitSet::~SBitSet()
0418 {
0419     delete [] bits ;
0420 }
0421 
0422 inline std::string SBitSet::desc() const
0423 {
0424     std::stringstream ss ;
0425     ss
0426         << std::setw(4) << ( label ? label : "-" )
0427         << std::setw(10) << ( spec ? spec : "-" )
0428         << Desc(num_bits, bits, false)
0429         ;
0430 
0431     std::string s = ss.str();
0432     return s ;
0433 }
0434 
0435 
0436 template<typename T>
0437 inline T SBitSet::value() const   // HMM: little or big endian option ?
0438 {
0439     T val = 0 ;
0440     for(unsigned i=0 ; i < num_bits ; i++ )
0441     {
0442        if(bits[i]) val |= ( 0x1 << i )  ;
0443     }
0444     return val ;
0445 }
0446 
0447 
0448 inline void SBitSet::serialize(std::vector<unsigned char>& bytes) const
0449 {
0450     int num_bytes = (num_bits + 7)/8 ;
0451     bytes.resize(num_bytes, 0);
0452     for (size_t i = 0; i < num_bits; ++i) if(bits[i]) bytes[i/8] |= (1 << (i % 8));
0453 }
0454 
0455 inline SBitSet* SBitSet::CreateFromBytes(const std::vector<unsigned char>& bytes) // static
0456 {
0457     int num_bits = 8*bytes.size() ;
0458     SBitSet* bs = new SBitSet(num_bits);
0459     for (int i = 0; i < num_bits; ++i)
0460     {
0461         unsigned mask = 0x1 << (i % 8) ;
0462         unsigned char byte = bytes[i/8] ;
0463         bs->bits[i] = byte & mask ;
0464     }
0465     return bs ;
0466 }
0467 
0468 inline int SBitSet::compare(const SBitSet* other) const
0469 {
0470     if(!other) return -1 ;
0471     if(num_bits != other->num_bits) return -2 ;
0472     int diff = 0 ;
0473     for(unsigned i=0 ; i < num_bits ; i++) diff += ( bits[i] == other->bits[i] ? 0 : 1 ) ;
0474     return diff ;
0475 }
0476 
0477