Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 10:26:00

0001 /// \file VecCore/BitSet.h
0002 /// \author Philippe Canal (pcanal@fnal.gov)
0003 /// \author Exported from the original version in ROOT (root.cern.ch).
0004 
0005 #ifndef VECGEOM_BITSET_H
0006 #define VECGEOM_BITSET_H
0007 
0008 // This file will eventually move in VecCore.
0009 #include "VecGeom/base/Global.h"
0010 
0011 #include "VariableSizeObj.h"
0012 
0013 // For memset and memcpy
0014 #include <string.h>
0015 
0016 // For operator new with placement
0017 #include <new>
0018 
0019 //
0020 // Fast bitset operations.
0021 //
0022 
0023 class TRootIOCtor;
0024 
0025 // gcc 4.8.2's -Wnon-virtual-dtor is broken and turned on by -Weffc++, we
0026 // need to disable it for SOA3D
0027 
0028 #if __GNUC__ < 3 || (__GNUC__ == 4 && __GNUC_MINOR__ <= 8)
0029 
0030 #pragma GCC diagnostic push
0031 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
0032 #pragma GCC diagnostic ignored "-Weffc++"
0033 #define GCC_DIAG_POP_NEEDED
0034 #endif
0035 
0036 namespace vecgeom {
0037 
0038 /**
0039  * @brief   Fast operation on a set of bit, all information stored contiguously in memory.
0040  * @details Resizing operations require explicit new creation and copy.
0041  *
0042  */
0043 
0044 class BitSet : protected VariableSizeObjectInterface<BitSet, unsigned char> {
0045 public:
0046   using Base_t = VariableSizeObjectInterface<BitSet, unsigned char>;
0047 
0048 private:
0049   friend Base_t;
0050   using VariableData_t = VariableSizeObj<unsigned char>;
0051 
0052   unsigned int fNbits; // Highest bit set + 1
0053   VariableData_t fData;
0054 
0055   // Required by VariableSizeObjectInterface
0056   VECCORE_ATT_HOST_DEVICE
0057   VariableData_t &GetVariableData() { return fData; }
0058 
0059   // Required by VariableSizeObjectInterface
0060   VECCORE_ATT_HOST_DEVICE
0061   VariableData_t const &GetVariableData() const { return fData; }
0062 
0063   static inline VECCORE_ATT_HOST_DEVICE size_t GetNbytes(size_t nbits) { return (((nbits ? nbits : 8) - 1) / 8) + 1; }
0064 
0065   VECCORE_ATT_HOST_DEVICE
0066   BitSet(const BitSet &other) : fNbits(other.fNbits), fData(other.fData)
0067   {
0068     // We assume that the memory allocated and use is large enough to
0069     // hold the full values (i.e. Sizeof(other.fData.fN) )
0070   }
0071 
0072   VECCORE_ATT_HOST_DEVICE
0073   BitSet(size_t new_size, const BitSet &other) : fNbits(other.fNbits), fData(new_size, other.fData)
0074   {
0075     // We assume that the memory allocated and use is large enough to
0076     // hold the full values (i.e. Sizeof(new_size) )
0077     // If new_size is smaller than the size of 'other' then the copy is truncated.
0078     // if new_size is greater than the size of 'other' the value are zero initialized.
0079 
0080     if (fNbits * 8 > new_size) {
0081       fNbits = 8 * new_size;
0082     }
0083     if (new_size > other.fData.fN) {
0084       memset(fData.GetValues() + other.fData.fN, 0, new_size - other.fData.fN);
0085     }
0086   }
0087 
0088   VECCORE_ATT_HOST_DEVICE
0089   BitSet(size_t nvalues, size_t nbits) : fNbits(nbits), fData(nvalues) { memset(fData.GetValues(), 0, GetNbytes()); }
0090 
0091   void DoAndEqual(const BitSet &rhs)
0092   {
0093     // Execute (*this) &= rhs;
0094     // Extra bits in rhs are ignored
0095     // Missing bits in rhs are assumed to be zero.
0096 
0097     size_t min = (GetNbytes() < rhs.GetNbytes()) ? GetNbytes() : rhs.GetNbytes();
0098     for (size_t i = 0; i < min; ++i) {
0099       fData[i] &= rhs.fData[i];
0100     }
0101     if (GetNbytes() > min) {
0102       memset(&(fData[min]), 0, GetNbytes() - min);
0103     }
0104   }
0105 
0106   void DoOrEqual(const BitSet &rhs)
0107   {
0108     // Execute (*this) &= rhs;
0109     // Extra bits in rhs are ignored
0110     // Missing bits in rhs are assumed to be zero.
0111 
0112     size_t min = (GetNbytes() < rhs.GetNbytes()) ? GetNbytes() : rhs.GetNbytes();
0113     for (size_t i = 0; i < min; ++i) {
0114       fData[i] |= rhs.fData[i];
0115     }
0116   }
0117 
0118   void DoXorEqual(const BitSet &rhs)
0119   {
0120     // Execute (*this) ^= rhs;
0121     // Extra bits in rhs are ignored
0122     // Missing bits in rhs are assumed to be zero.
0123 
0124     size_t min = (GetNbytes() < rhs.GetNbytes()) ? GetNbytes() : rhs.GetNbytes();
0125     for (size_t i = 0; i < min; ++i) {
0126       fData[i] ^= rhs.fData[i];
0127     }
0128   }
0129 
0130   void DoLeftShift(size_t shift)
0131   {
0132     // Execute the left shift operation.
0133 
0134     if (shift == 0) return;
0135     const size_t wordshift = shift / 8;
0136     const size_t offset    = shift % 8;
0137     if (offset == 0) {
0138       for (size_t n = GetNbytes() - 1; n >= wordshift; --n) {
0139         fData[n] = fData[n - wordshift];
0140       }
0141     } else {
0142       const size_t sub_offset = 8 - offset;
0143       for (size_t n = GetNbytes() - 1; n > wordshift; --n) {
0144         fData[n] = (fData[n - wordshift] << offset) | (fData[n - wordshift - 1] >> sub_offset);
0145       }
0146       fData[wordshift] = fData[0] << offset;
0147     }
0148     memset(fData.GetValues(), 0, wordshift);
0149   }
0150 
0151   void DoRightShift(size_t shift)
0152   {
0153     // Execute the left shift operation.
0154 
0155     if (shift == 0) return;
0156     const size_t wordshift = shift / 8;
0157     const size_t offset    = shift % 8;
0158     const size_t limit     = GetNbytes() - wordshift - 1;
0159 
0160     if (offset == 0)
0161       for (size_t n = 0; n <= limit; ++n)
0162         fData[n] = fData[n + wordshift];
0163     else {
0164       const size_t sub_offset = 8 - offset;
0165       for (size_t n = 0; n < limit; ++n)
0166         fData[n] = (fData[n + wordshift] >> offset) | (fData[n + wordshift + 1] << sub_offset);
0167       fData[limit] = fData[GetNbytes() - 1] >> offset;
0168     }
0169 
0170     memset(&(fData[limit + 1]), 0, GetNbytes() - limit - 1);
0171   }
0172 
0173   void DoFlip()
0174   {
0175     // Execute ~(*this)
0176 
0177     for (size_t i = 0; i < GetNbytes(); ++i) {
0178       fData[i] = ~fData[i];
0179     }
0180     // NOTE: out-of-bounds bit were also flipped!
0181   }
0182 
0183 public:
0184   class reference {
0185     friend class BitSet;
0186 
0187     unsigned char &fBit; //! reference to the data storage
0188     unsigned char fPos;  //! position (0 through 7)
0189 
0190     reference() : fBit(fPos), fPos(0)
0191     {
0192       // default constructor, default to all bits looking false.
0193       // assignment are ignored.
0194     }
0195 
0196   public:
0197     reference(unsigned char &bit, unsigned char pos) : fBit(bit), fPos(pos) {}
0198     ~reference() {}
0199 
0200     // For b[i] = val;
0201     reference &operator=(bool val)
0202     {
0203       if (val) {
0204         fBit |= val << fPos;
0205       } else {
0206         fBit &= (0xFF ^ (1 << fPos));
0207       }
0208       return *this;
0209     }
0210 
0211     // For b[i] = b[__j];
0212     reference &operator=(const reference &rhs)
0213     {
0214       *this = rhs.operator bool();
0215       return *this;
0216     }
0217 
0218     // Flips the bit
0219     bool operator~() const { return (fBit & (1 << fPos)) == 0; };
0220 
0221     // For val = b[i];
0222     operator bool() const { return (fBit & (1 << fPos)) != 0; };
0223   };
0224 
0225   // Enumerate the part of the private interface, we want to expose.
0226   using Base_t::MakeCopy;
0227   using Base_t::MakeCopyAt;
0228   using Base_t::ReleaseInstance;
0229   using Base_t::SizeOf;
0230 
0231   // This replaces the dummy constructor to make sure that I/O can be
0232   // performed while the user is only allowed to use the static maker
0233   BitSet(TRootIOCtor *marker) : fNbits(0), fData(marker) {}
0234 
0235   // Assignment allowed
0236   BitSet &operator=(const BitSet &rhs)
0237   {
0238     // BitSet assignment operator
0239 
0240     if (this != &rhs) {
0241       fNbits = rhs.fNbits;
0242       // Default operator= does memcpy.
0243       // Potential trucation if this is smaller than rhs.
0244       fData = rhs.fData;
0245     }
0246     return *this;
0247   }
0248 
0249   VECCORE_ATT_HOST_DEVICE
0250   static size_t SizeOfInstance(size_t nbits) { return SizeOf(GetNbytes(nbits)); }
0251 
0252   static BitSet *MakeInstance(size_t nbits)
0253   {
0254     size_t nvalues = GetNbytes(nbits);
0255     return Base_t::MakeInstance(nvalues, nbits);
0256   }
0257 
0258   VECCORE_ATT_HOST_DEVICE
0259   static BitSet *MakeInstanceAt(size_t nbits, void *addr)
0260   {
0261     size_t nvalues = GetNbytes(nbits);
0262     return Base_t::MakeInstanceAt(nvalues, addr, nbits);
0263   }
0264 
0265   static BitSet *MakeCompactCopy(BitSet &other)
0266   {
0267     // Make a copy of a the variable size array and its container with
0268     // a new_size of the content.
0269     // If no compact was needed, return the address of the original
0270 
0271     if (other.GetNbytes() <= 1) return &other;
0272 
0273     size_t needed;
0274     for (needed = other.GetNbytes() - 1; needed > 0 && other.fData[needed] == 0;) {
0275       needed--;
0276     };
0277     needed++;
0278 
0279     if (needed != other.GetNbytes()) {
0280       return MakeCopy(needed, other);
0281     } else {
0282       return &other;
0283     }
0284   }
0285 
0286   size_t SizeOf() const { return SizeOf(fData.fN); }
0287 
0288   //----- bit manipulation
0289   //----- (note the difference with TObject's bit manipulations)
0290   VECCORE_ATT_HOST_DEVICE
0291   void ResetAllBits(bool value = false)
0292   {
0293     // Reset all bits to 0 (false).
0294     // if value=1 set all bits to 1
0295 
0296     if (fData.GetValues()) memset(fData.GetValues(), value ? 1 : 0, GetNbytes());
0297   }
0298 
0299   VECCORE_ATT_HOST_DEVICE
0300   void ResetBitNumber(size_t bitnumber) { SetBitNumber(bitnumber, false); }
0301 
0302   VECCORE_ATT_HOST_DEVICE
0303   bool SetBitNumber(size_t bitnumber, bool value = true)
0304   {
0305     // Set bit number 'bitnumber' to be value
0306 
0307     if (bitnumber >= fNbits) {
0308       size_t new_size = (bitnumber / 8) + 1;
0309       if (new_size > GetNbytes()) {
0310         // too far, can not set
0311         return false;
0312       }
0313       fNbits = bitnumber + 1;
0314     }
0315     size_t loc        = bitnumber / 8;
0316     unsigned char bit = bitnumber % 8;
0317     if (value)
0318       fData[loc] |= (1 << bit);
0319     else
0320       fData[loc] &= (0xFF ^ (1 << bit));
0321     return true;
0322   }
0323 
0324   VECCORE_ATT_HOST_DEVICE
0325   bool TestBitNumber(size_t bitnumber) const
0326   {
0327     // Return the current value of the bit
0328 
0329     if (bitnumber >= fNbits) return false;
0330     size_t loc          = bitnumber / 8;
0331     unsigned char value = fData[loc];
0332     unsigned char bit   = bitnumber % 8;
0333     bool result         = (value & (1 << bit)) != 0;
0334     return result;
0335     // short: return 0 != (fAllBits[bitnumber/8] & (1<< (bitnumber%8)));
0336   }
0337 
0338   //----- Accessors and operator
0339   BitSet::reference operator[](size_t bitnumber)
0340   {
0341     if (bitnumber >= fNbits) return reference();
0342     size_t loc        = bitnumber / 8;
0343     unsigned char bit = bitnumber % 8;
0344     return reference(fData[loc], bit);
0345   }
0346   bool operator[](size_t bitnumber) const { return TestBitNumber(bitnumber); }
0347 
0348   BitSet &operator&=(const BitSet &rhs)
0349   {
0350     DoAndEqual(rhs);
0351     return *this;
0352   }
0353   BitSet &operator|=(const BitSet &rhs)
0354   {
0355     DoOrEqual(rhs);
0356     return *this;
0357   }
0358   BitSet &operator^=(const BitSet &rhs)
0359   {
0360     DoXorEqual(rhs);
0361     return *this;
0362   }
0363   BitSet &operator<<=(size_t rhs)
0364   {
0365     DoLeftShift(rhs);
0366     return *this;
0367   }
0368   BitSet &operator>>=(size_t rhs)
0369   {
0370     DoRightShift(rhs);
0371     return *this;
0372   }
0373   //      BitSet  operator<<(size_t rhs) { return BitSet(*this)<<= rhs; }
0374   //      BitSet  operator>>(size_t rhs) { return BitSet(*this)>>= rhs; }
0375   //      BitSet  operator~() { BitSet res(*this); res.DoFlip(); return res; }
0376 
0377   //----- Optimized setters
0378   // Each of these will replace the contents of the receiver with the bitvector
0379   // in the parameter array.  The number of bits is changed to nbits.  If nbits
0380   // is smaller than fNbits, the receiver will NOT be compacted.
0381   bool Set(size_t nbits, const char *array)
0382   {
0383     // Set all the bytes.
0384 
0385     size_t nbytes = (nbits + 7) >> 3;
0386 
0387     if (nbytes > GetNbytes()) return false;
0388 
0389     fNbits = nbits;
0390     memcpy(fData.GetValues(), array, nbytes);
0391     return true;
0392   }
0393   bool Set(size_t nbits, const unsigned char *array) { return Set(nbits, (const char *)array); }
0394   bool Set(size_t nbits, const unsigned short *array) { return Set(nbits, (const short *)array); }
0395   bool Set(size_t nbits, const unsigned int *array) { return Set(nbits, (const int *)array); }
0396   bool Set(size_t nbits, const unsigned long long *array) { return Set(nbits, (const long long *)array); }
0397 
0398 #ifdef R__BYTESWAP /* means we are on little endian */
0399 
0400   /*
0401   If we are on a little endian machine, a bitvector represented using
0402   any integer type is identical to a bitvector represented using bytes.
0403   -- FP.
0404   */
0405   bool Set(size_t nbits, const short *array) { return Set(nbits, (const char *)array); }
0406   bool Set(size_t nbits, const int *array) { return Set(nbits, (const char *)array); }
0407   bool Set(size_t nbits, const long long *array) { return Set(nbits, (const char *)array); }
0408 #else
0409   /*
0410   If we are on a big endian machine, some swapping around is required.
0411   */
0412 
0413   bool Set(size_t nbits, const short *array)
0414   {
0415     // make nbytes even so that the loop below is neat.
0416     size_t nbytes = ((nbits + 15) >> 3) & ~1;
0417 
0418     if (nbytes > GetNbytes()) return false;
0419 
0420     fNbits = nbits;
0421 
0422     const unsigned char *cArray = (const unsigned char *)array;
0423     for (size_t i = 0; i < nbytes; i += 2) {
0424       fData[i]     = cArray[i + 1];
0425       fData[i + 1] = cArray[i];
0426     }
0427     return true;
0428   }
0429 
0430   bool Set(size_t nbits, const int *array)
0431   {
0432     // make nbytes a multiple of 4 so that the loop below is neat.
0433     size_t nbytes = ((nbits + 31) >> 3) & ~3;
0434 
0435     if (nbytes > GetNbytes()) return false;
0436 
0437     fNbits = nbits;
0438 
0439     const unsigned char *cArray = (const unsigned char *)array;
0440     for (size_t i = 0; i < nbytes; i += 4) {
0441       fData[i]     = cArray[i + 3];
0442       fData[i + 1] = cArray[i + 2];
0443       fData[i + 2] = cArray[i + 1];
0444       fData[i + 3] = cArray[i];
0445     }
0446     return true;
0447   }
0448 
0449   bool Set(size_t nbits, const long long *array)
0450   {
0451     // make nbytes a multiple of 8 so that the loop below is neat.
0452     size_t nbytes = ((nbits + 63) >> 3) & ~7;
0453 
0454     if (nbytes > GetNbytes()) return false;
0455 
0456     fNbits = nbits;
0457 
0458     const unsigned char *cArray = (const unsigned char *)array;
0459     for (size_t i = 0; i < nbytes; i += 8) {
0460       fData[i]     = cArray[i + 7];
0461       fData[i + 1] = cArray[i + 6];
0462       fData[i + 2] = cArray[i + 5];
0463       fData[i + 3] = cArray[i + 4];
0464       fData[i + 4] = cArray[i + 3];
0465       fData[i + 5] = cArray[i + 2];
0466       fData[i + 6] = cArray[i + 1];
0467       fData[i + 7] = cArray[i];
0468     }
0469     return true;
0470   }
0471 
0472 #endif
0473 
0474   //----- Optimized getters
0475   // Each of these will replace the contents of the parameter array with the
0476   // bits in the receiver.  The parameter array must be large enough to hold
0477   // all of the bits in the receiver.
0478   // Note on semantics: any bits in the parameter array that go beyond the
0479   // number of the bits in the receiver will have an unspecified value.  For
0480   // example, if you call Get(Int*) with an array of one integer and the BitSet
0481   // object has less than 32 bits, then the remaining bits in the integer will
0482   // have an unspecified value.
0483   void Get(char *array) const
0484   {
0485     // Copy all the byes.
0486 
0487     memcpy(array, fData.GetValues(), (fNbits + 7) >> 3);
0488   }
0489   void Get(unsigned char *array) const { Get((char *)array); }
0490   void Get(unsigned short *array) const { Get((short *)array); }
0491   void Get(unsigned int *array) const { Get((int *)array); }
0492   void Get(unsigned long long *array) const { Get((long long *)array); }
0493 
0494 #ifdef R__BYTESWAP /* means we are on little endian */
0495 
0496   /*
0497   If we are on a little endian machine, a bitvector represented using
0498   any integer type is identical to a bitvector represented using bytes.
0499   -- FP.
0500   */
0501   void Get(short *array) const { Get((char *)array); }
0502   void Get(int *array) const { Get((char *)array); }
0503   void Get(long long *array) const { Get((char *)array); }
0504 
0505 #else
0506 
0507   void Get(short *array) const
0508   {
0509     // Get all the bytes.
0510 
0511     size_t nBytes     = (fNbits + 7) >> 3;
0512     size_t nSafeBytes = nBytes & ~1;
0513 
0514     unsigned char *cArray = (unsigned char *)array;
0515     for (size_t i = 0; i < nSafeBytes; i += 2) {
0516       cArray[i]     = fData[i + 1];
0517       cArray[i + 1] = fData[i];
0518     }
0519 
0520     if (nBytes > nSafeBytes) {
0521       cArray[nSafeBytes + 1] = fData[nSafeBytes];
0522     }
0523   }
0524 
0525   void Get(int *array) const
0526   {
0527     // Get all the bytes.
0528 
0529     size_t nBytes     = (fNbits + 7) >> 3;
0530     size_t nSafeBytes = nBytes & ~3;
0531 
0532     unsigned char *cArray = (unsigned char *)array;
0533     size_t i;
0534     for (i = 0; i < nSafeBytes; i += 4) {
0535       cArray[i]     = fData[i + 3];
0536       cArray[i + 1] = fData[i + 2];
0537       cArray[i + 2] = fData[i + 1];
0538       cArray[i + 3] = fData[i];
0539     }
0540 
0541     for (i = 0; i < nBytes - nSafeBytes; ++i) {
0542       cArray[nSafeBytes + (3 - i)] = fData[nSafeBytes + i];
0543     }
0544   }
0545 
0546   void Get(long long *array) const
0547   {
0548     // Get all the bytes.
0549 
0550     size_t nBytes     = (fNbits + 7) >> 3;
0551     size_t nSafeBytes = nBytes & ~7;
0552 
0553     unsigned char *cArray = (unsigned char *)array;
0554     size_t i;
0555     for (i = 0; i < nSafeBytes; i += 8) {
0556       cArray[i]     = fData[i + 7];
0557       cArray[i + 1] = fData[i + 6];
0558       cArray[i + 2] = fData[i + 5];
0559       cArray[i + 3] = fData[i + 4];
0560       cArray[i + 4] = fData[i + 3];
0561       cArray[i + 5] = fData[i + 2];
0562       cArray[i + 6] = fData[i + 1];
0563       cArray[i + 7] = fData[i];
0564     }
0565 
0566     for (i = 0; i < nBytes - nSafeBytes; ++i) {
0567       cArray[nSafeBytes + (7 - i)] = fData[nSafeBytes + i];
0568     }
0569   }
0570 
0571 #endif
0572 
0573   //----- Utilities
0574   void Clear()
0575   {
0576     fNbits = 0;
0577     memset(&(fData[0]), 0, GetNbytes());
0578   }
0579 
0580   size_t CountBits(size_t startBit = 0) const
0581   {
0582     // Return number of bits set to 1 starting at bit startBit
0583 
0584     // Keep array initiation hand-formatted
0585     // clang-format off
0586     constexpr unsigned char nbits[256] = {
0587             0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
0588             1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
0589             1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
0590             2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
0591             1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
0592             2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
0593             2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
0594             3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
0595             1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
0596             2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
0597             2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
0598             3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
0599             2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
0600             3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
0601             3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
0602             4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};
0603     // clang-format on
0604 
0605     size_t i, count = 0;
0606     if (startBit == 0) {
0607       for (i = 0; i < GetNbytes(); i++) {
0608         count += nbits[fData[i]];
0609       }
0610       return count;
0611     }
0612     if (startBit >= fNbits) return count;
0613     size_t startByte = startBit / 8;
0614     size_t ibit      = startBit % 8;
0615     if (ibit) {
0616       for (i = ibit; i < 8; i++) {
0617         if (fData[startByte] & (1 << ibit)) count++;
0618       }
0619       startByte++;
0620     }
0621     for (i = startByte; i < GetNbytes(); i++) {
0622       count += nbits[fData[i]];
0623     }
0624     return count;
0625   }
0626 
0627   VECCORE_ATT_HOST_DEVICE
0628   size_t FirstNullBit(size_t startBit = 0) const
0629   {
0630     // Return position of first null bit (starting from position 0 and up)
0631 
0632     // Keep array initiation hand-formatted
0633     // clang-format off
0634     constexpr unsigned char bitsPattern[256] = {
0635              0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
0636              0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
0637              0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
0638              0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,
0639              0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
0640              0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
0641              0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
0642              0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,
0643              0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
0644              0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
0645              0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
0646              0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,
0647              0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
0648              0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
0649              0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
0650              0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8};
0651     // clang-format on
0652 
0653     size_t i;
0654     if (startBit == 0) {
0655       for (i = 0; i < GetNbytes(); i++) {
0656         if (fData[i] != 255) return 8 * i + bitsPattern[fData[i]];
0657       }
0658       return fNbits;
0659     }
0660     if (startBit >= fNbits) return fNbits;
0661     size_t startByte = startBit / 8;
0662     size_t ibit      = startBit % 8;
0663     if (ibit) {
0664       for (i = ibit; i < 8; i++) {
0665         if ((fData[startByte] & (1 << i)) == 0) return 8 * startByte + i;
0666       }
0667       startByte++;
0668     }
0669     for (i = startByte; i < GetNbytes(); i++) {
0670       if (fData[i] != 255) return 8 * i + bitsPattern[fData[i]];
0671     }
0672     return fNbits;
0673   }
0674 
0675   VECCORE_ATT_HOST_DEVICE
0676   size_t FirstSetBit(size_t startBit = 0) const
0677   {
0678     // Return position of first non null bit (starting from position 0 and up)
0679 
0680     // Keep array initiation hand-formatted
0681     // clang-format off
0682 
0683     constexpr unsigned char bitsPattern[256] =  {
0684              8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
0685              4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
0686              5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
0687              4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
0688              6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
0689              4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
0690              5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
0691              4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
0692              7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
0693              4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
0694              5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
0695              4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
0696              6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
0697              4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
0698              5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
0699              4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0};
0700     // clang-format on
0701 
0702     size_t i;
0703     if (startBit == 0) {
0704       for (i = 0; i < GetNbytes(); i++) {
0705         if (fData[i] != 0) return 8 * i + bitsPattern[fData[i]];
0706       }
0707       return fNbits;
0708     }
0709     if (startBit >= fNbits) return fNbits;
0710     size_t startByte = startBit / 8;
0711     size_t ibit      = startBit % 8;
0712     if (ibit) {
0713       for (i = ibit; i < 8; i++) {
0714         if ((fData[startByte] & (1 << i)) != 0) return 8 * startByte + i;
0715       }
0716       startByte++;
0717     }
0718     for (i = startByte; i < GetNbytes(); i++) {
0719       if (fData[i] != 0) return 8 * i + bitsPattern[fData[i]];
0720     }
0721     return fNbits;
0722   }
0723 
0724   size_t LastNullBit() const { return LastNullBit(fNbits - 1); }
0725 
0726   size_t LastNullBit(size_t startBit) const
0727   {
0728     // Return position of first null bit (starting from position startBit and down)
0729 
0730     // Keep array initiation hand-formatted
0731     // clang-format off
0732     constexpr unsigned char bitsPattern[256] = {
0733             7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
0734             7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
0735             7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
0736             7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
0737             7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
0738             7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
0739             7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
0740             7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
0741             6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
0742             6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
0743             6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
0744             6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
0745             5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
0746             5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
0747             4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
0748             3,3,3,3,3,3,3,3,2,2,2,2,1,1,0,8};
0749     // clang-format on
0750 
0751     size_t i;
0752     if (startBit >= fNbits) startBit = fNbits - 1;
0753     size_t startByte = startBit / 8;
0754     size_t ibit      = startBit % 8;
0755     if (ibit < 7) {
0756       for (i = ibit + 1; i > 0; i--) {
0757         if ((fData[startByte] & (1 << (i - 1))) == 0) return 8 * startByte + i - 1;
0758       }
0759       startByte--;
0760     }
0761     for (i = startByte + 1; i > 0; i--) {
0762       if (fData[i - 1] != 255) return 8 * (i - 1) + bitsPattern[fData[i - 1]];
0763     }
0764     return fNbits;
0765   }
0766 
0767   VECCORE_ATT_HOST_DEVICE
0768   size_t LastSetBit() const { return LastSetBit(fNbits - 1); }
0769 
0770   VECCORE_ATT_HOST_DEVICE
0771   size_t LastSetBit(size_t startBit) const
0772   {
0773     // Return position of first non null bit (starting from position fNbits and down)
0774 
0775     // Keep array initiation hand-formatted
0776     // clang-format off
0777     constexpr unsigned char bitsPattern[256] = {
0778              8,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
0779              4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
0780              5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
0781              5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
0782              6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
0783              6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
0784              6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
0785              6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
0786              7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
0787              7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
0788              7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
0789              7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
0790              7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
0791              7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
0792              7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
0793              7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
0794     // clang-format on
0795 
0796     if (startBit >= fNbits) startBit = fNbits - 1;
0797 
0798     size_t startByte = startBit / 8;
0799     size_t ibit      = startBit % 8;
0800 
0801     size_t i;
0802     if (ibit < 7) {
0803       for (i = ibit + 1; i > 0; i--) {
0804         if ((fData[startByte] & (1 << (i - 1))) != 0) return 8 * startByte + i - 1;
0805       }
0806       startByte--;
0807     }
0808     for (i = startByte + 1; i > 0; i--) {
0809       if (fData[i - 1] != 0) return 8 * (i - 1) + bitsPattern[fData[i - 1]];
0810     }
0811     return fNbits;
0812   }
0813 
0814   VECCORE_ATT_HOST_DEVICE
0815   size_t GetNbits() const { return fNbits; }
0816 
0817   VECCORE_ATT_HOST_DEVICE
0818   size_t GetNbytes() const { return fData.fN; }
0819 
0820   bool operator==(const BitSet &other) const
0821   {
0822     // Compare object.
0823 
0824     if (fNbits == other.fNbits) {
0825       return !memcmp(fData.GetValues(), other.fData.GetValues(), (fNbits + 7) >> 3);
0826     } else if (fNbits < other.fNbits) {
0827       return !memcmp(fData.GetValues(), other.fData.GetValues(), (fNbits + 7) >> 3) &&
0828              other.FirstSetBit(fNbits) == other.fNbits;
0829     } else {
0830       return !memcmp(fData.GetValues(), other.fData.GetValues(), (other.fNbits + 7) >> 3) &&
0831              FirstSetBit(other.fNbits) == fNbits;
0832     }
0833   }
0834 
0835   bool operator!=(const BitSet &other) const { return !(*this == other); }
0836 };
0837 
0838 inline bool operator&(const BitSet::reference &lhs, const BitSet::reference &rhs)
0839 {
0840   return (bool)lhs && (bool)rhs;
0841 }
0842 
0843 inline bool operator|(const BitSet::reference &lhs, const BitSet::reference &rhs)
0844 {
0845   return (bool)lhs || (bool)rhs;
0846 }
0847 
0848 inline bool operator^(const BitSet::reference &lhs, const BitSet::reference &rhs)
0849 {
0850   return (bool)lhs ^ (bool)rhs;
0851 }
0852 } // namespace vecgeom
0853 
0854 #if defined(GCC_DIAG_POP_NEEDED)
0855 
0856 #pragma GCC diagnostic pop
0857 #undef GCC_DIAG_POP_NEEDED
0858 
0859 #endif
0860 
0861 #endif // VECGEOM_BITSET_H