Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 10:50:29

0001 #ifndef DataFormats_L1TrackTrigger_TTBV_h
0002 #define DataFormats_L1TrackTrigger_TTBV_h
0003 
0004 #include <bitset>
0005 #include <array>
0006 #include <string>
0007 #include <algorithm>
0008 #include <cmath>
0009 #include <utility>
0010 #include <vector>
0011 #include <iostream>
0012 
0013 /*! 
0014  * \class  TTBV
0015  * \brief  Bit vector used by Track Trigger emulators. Mainly used to convert
0016  *         integers into arbitrary (within margin) sized two's complement strings.
0017  * \author Thomas Schuh
0018  * \date   2020, Jan
0019  */
0020 class TTBV {
0021 public:
0022   static constexpr int S_ = 64;  // Frame width of emp infrastructure f/w, max number of bits a TTBV can handle
0023 
0024 private:
0025   bool twos_;           // Two's complement (true) or binary (false)
0026   int size_;            // number or bits
0027   std::bitset<S_> bs_;  // underlying storage
0028 
0029 public:
0030   // constructor: default
0031   TTBV() : twos_(false), size_(0), bs_() {}
0032 
0033   // constructor: double precision (IEEE 754); from most to least significant bit: 1 bit sign + 11 bit binary exponent + 52 bit binary mantisse
0034   TTBV(const double d) : twos_(false), size_(S_) {
0035     int index(0);
0036     const char* c = reinterpret_cast<const char*>(&d);
0037     for (int iByte = 0; iByte < (int)sizeof(d); iByte++) {
0038       const std::bitset<std::numeric_limits<unsigned char>::digits> byte(*(c + iByte));
0039       for (int bit = 0; bit < std::numeric_limits<unsigned char>::digits; bit++)
0040         bs_[index++] = byte[bit];
0041     }
0042   }
0043 
0044   // constructor: unsigned int value
0045   TTBV(unsigned long long int value, int size) : twos_(false), size_(size), bs_(value) {}
0046 
0047   // constructor: int value
0048   TTBV(int value, int size, bool twos = false)
0049       : twos_(twos), size_(size), bs_((!twos || value >= 0) ? value : value + iMax()) {}
0050 
0051   // constructor: double value + precision, biased (floor) representation
0052   TTBV(double value, double base, int size, bool twos = false) : TTBV((int)std::floor(value / base), size, twos) {}
0053 
0054   // constructor: string
0055   TTBV(const std::string& str, bool twos = false) : twos_(twos), size_(str.size()), bs_(str) {}
0056 
0057   // constructor: bitset
0058   TTBV(const std::bitset<S_>& bs, bool twos = false) : twos_(twos), size_(S_), bs_(bs) {}
0059 
0060   // constructor: slice reinterpret sign
0061   TTBV(const TTBV& ttBV, int begin, int end = 0, bool twos = false) : twos_(twos), size_(begin - end), bs_(ttBV.bs_) {
0062     bs_ <<= S_ - begin;
0063     bs_ >>= S_ - begin + end;
0064   }
0065 
0066   // Two's complement (true) or binary (false)
0067   bool twos() const { return twos_; }
0068   // number or bits
0069   int size() const { return size_; }
0070   // underlying storage
0071   const std::bitset<S_>& bs() const { return bs_; }
0072 
0073   // access: single bit
0074   bool operator[](int pos) const { return bs_[pos]; }
0075   std::bitset<S_>::reference operator[](int pos) { return bs_[pos]; }
0076 
0077   // access: most significant bit copy
0078   bool msb() const { return bs_[size_ - 1]; }
0079 
0080   // access: most significant bit reference
0081   std::bitset<S_>::reference msb() { return bs_[size_ - 1]; }
0082 
0083   // access: members of underlying bitset
0084 
0085   bool all() const { return bs_.all(); }
0086   bool any() const { return bs_.any(); }
0087   bool none() const { return bs_.none(); }
0088   int count() const { return bs_.count(); }
0089 
0090   // operator: comparisons equal
0091   bool operator==(const TTBV& rhs) const { return bs_ == rhs.bs_; }
0092 
0093   // operator: comparisons not equal
0094   bool operator!=(const TTBV& rhs) const { return bs_ != rhs.bs_; }
0095 
0096   // operator: boolean and
0097   TTBV& operator&=(const TTBV& rhs) {
0098     const int m(std::max(size_, rhs.size()));
0099     this->resize(m);
0100     TTBV bv(rhs);
0101     bv.resize(m);
0102     bs_ &= bv.bs_;
0103     return *this;
0104   }
0105 
0106   // operator: boolean or
0107   TTBV& operator|=(const TTBV& rhs) {
0108     const int m(std::max(size_, rhs.size()));
0109     this->resize(m);
0110     TTBV bv(rhs);
0111     bv.resize(m);
0112     bs_ |= bv.bs_;
0113     return *this;
0114   }
0115 
0116   // operator: boolean xor
0117   TTBV& operator^=(const TTBV& rhs) {
0118     const int m(std::max(size_, rhs.size()));
0119     this->resize(m);
0120     TTBV bv(rhs);
0121     bv.resize(m);
0122     bs_ ^= bv.bs_;
0123     return *this;
0124   }
0125 
0126   // operator: not
0127   TTBV operator~() const {
0128     TTBV bv(*this);
0129     return bv.flip();
0130   }
0131 
0132   // reference operator: bit remove right
0133   TTBV& operator>>=(int pos) {
0134     bs_ >>= pos;
0135     size_ -= pos;
0136     return *this;
0137   }
0138 
0139   // reference operator: bit remove left
0140   TTBV& operator<<=(int pos) {
0141     bs_ <<= S_ - size_ + pos;
0142     bs_ >>= S_ - size_ + pos;
0143     size_ -= pos;
0144     return *this;
0145   }
0146 
0147   // operator: bit remove left copy
0148   TTBV operator<<(int pos) const {
0149     TTBV bv(*this);
0150     return bv <<= pos;
0151   }
0152 
0153   // operator: bit remove right copy
0154   TTBV operator>>(int pos) const {
0155     TTBV bv(*this);
0156     return bv >>= pos;
0157   }
0158 
0159   // reference operator: concatenation
0160   TTBV& operator+=(const TTBV& rhs) {
0161     bs_ <<= rhs.size();
0162     bs_ |= rhs.bs_;
0163     size_ += rhs.size();
0164     return *this;
0165   }
0166 
0167   // operator: concatenation copy
0168   TTBV operator+(const TTBV& rhs) const {
0169     TTBV lhs(*this);
0170     return lhs += rhs;
0171   }
0172 
0173   // operator: value increment, overflow protected
0174   TTBV& operator++() {
0175     bs_ = std::bitset<S_>(bs_.to_ullong() + 1);
0176     this->resize(size_);
0177     return *this;
0178   }
0179 
0180   // manipulation: all bits set to 0
0181   TTBV& reset() {
0182     bs_.reset();
0183     return *this;
0184   }
0185 
0186   // manipulation: all bits set to 1
0187   TTBV& set() {
0188     for (int n = 0; n < size_; n++)
0189       bs_.set(n);
0190     return *this;
0191   }
0192 
0193   // manipulation: all bits flip 1 to 0 and vice versa
0194   TTBV& flip() {
0195     for (int n = 0; n < size_; n++)
0196       bs_.flip(n);
0197     return *this;
0198   }
0199 
0200   // manipulation: single bit set to 0
0201   TTBV& reset(int pos) {
0202     bs_.reset(pos);
0203     return *this;
0204   }
0205 
0206   // manipulation: single bit set to 1
0207   TTBV& set(int pos) {
0208     bs_.set(pos);
0209     return *this;
0210   }
0211 
0212   // manipulation: multiple bit set to 1
0213   TTBV& set(std::vector<int> vpos) {
0214     for (int pos : vpos)
0215       bs_.set(pos);
0216     return *this;
0217   }
0218 
0219   // manipulation: single bit flip 1 to 0 and vice versa
0220   TTBV& flip(int pos) {
0221     bs_.flip(pos);
0222     return *this;
0223   }
0224 
0225   // manipulation: absolute value of biased twos' complement. Converts twos' complenet into binary.
0226   TTBV& abs() {
0227     if (twos_) {
0228       twos_ = false;
0229       if (this->msb())
0230         this->flip();
0231       size_--;
0232     }
0233     return *this;
0234   }
0235 
0236   // manipulation: resize
0237   TTBV& resize(int size) {
0238     bool msb = this->msb();
0239     if (size > size_) {
0240       if (twos_)
0241         for (int n = size_; n < size; n++)
0242           bs_.set(n, msb);
0243       size_ = size;
0244     } else if (size < size_ && size > 0) {
0245       this->operator<<=(size - size_);
0246       if (twos_)
0247         this->msb() = msb;
0248     }
0249     return *this;
0250   }
0251 
0252   // conversion: to string
0253   std::string str() const { return bs_.to_string().substr(S_ - size_, S_); }
0254 
0255   // conversion: range based to string
0256   std::string str(int start, int end = 0) const { return this->str().substr(size_ - start, size_ - end); }
0257 
0258   // conversion: to int
0259   int val() const { return (twos_ && this->msb()) ? (int)bs_.to_ullong() - iMax() : bs_.to_ullong(); }
0260 
0261   // conversion: to int, reinterpret sign
0262   int val(bool twos) const { return (twos && this->msb()) ? (int)bs_.to_ullong() - iMax() : bs_.to_ullong(); }
0263 
0264   // conversion: range based to int, reinterpret sign
0265   int val(int start, int end = 0, bool twos = false) const { return TTBV(*this, start, end).val(twos); }
0266 
0267   // conversion: to double for given precision assuming biased (floor) representation
0268   double val(double base) const { return (this->val() + .5) * base; }
0269 
0270   // conversion: range based to double for given precision assuming biased (floor) representation, reinterpret sign
0271   double val(double base, int start, int end = 0, bool twos = false) const {
0272     return (this->val(start, end, twos) + .5) * base;
0273   }
0274 
0275   // maniplulation and conversion: extracts range based to double reinterpret sign and removes these bits
0276   double extract(double base, int size, bool twos = false) {
0277     double val = this->val(base, size, 0, twos);
0278     this->operator>>=(size);
0279     return val;
0280   }
0281 
0282   // maniplulation and conversion: extracts range based to int reinterpret sign and removes these bits
0283   int extract(int size, bool twos = false) {
0284     double val = this->val(size, 0, twos);
0285     this->operator>>=(size);
0286     return val;
0287   }
0288 
0289   // manipulation: extracts slice and removes these bits
0290   TTBV slice(int size, bool twos = false) {
0291     TTBV ttBV(*this, size, 0, twos);
0292     this->operator>>=(size);
0293     return ttBV;
0294   }
0295 
0296   // range based count of '1's or '0's
0297   int count(int begin, int end, bool b = true) const {
0298     int c(0);
0299     for (int i = begin; i < end; i++)
0300       if (bs_[i] == b)
0301         c++;
0302     return c;
0303   }
0304 
0305   // position of least significant '1' or '0'
0306   int plEncode(bool b = true) const {
0307     for (int e = 0; e < size_; e++)
0308       if (bs_[e] == b)
0309         return e;
0310     return size_;
0311   }
0312 
0313   // position of most significant '1' or '0'
0314   int pmEncode(bool b = true) const {
0315     for (int e = size_ - 1; e > -1; e--)
0316       if (bs_[e] == b)
0317         return e;
0318     return size_;
0319   }
0320 
0321   // position for n'th '1' or '0' counted from least to most significant bit
0322   int encode(int n, bool b = true) const {
0323     int sum(0);
0324     for (int e = 0; e < size_; e++) {
0325       if (bs_[e] == b) {
0326         sum++;
0327         if (sum == n)
0328           return e;
0329       }
0330     }
0331     return size_;
0332   }
0333 
0334   std::vector<int> ids(bool b = true, bool singed = false) const {
0335     std::vector<int> v;
0336     v.reserve(bs_.count());
0337     for (int i = 0; i < size_; i++)
0338       if (bs_[i] == b)
0339         v.push_back(singed ? i + size_ / 2 : i);
0340     return v;
0341   }
0342 
0343   friend std::ostream& operator<<(std::ostream& os, const TTBV& ttBV) { return os << ttBV.str(); }
0344 
0345 private:
0346   // look up table initializer for powers of 2
0347   constexpr std::array<unsigned long long int, S_> powersOfTwo() const {
0348     std::array<unsigned long long int, S_> lut = {};
0349     for (int i = 0; i < S_; i++)
0350       lut[i] = std::pow(2, i);
0351     return lut;
0352   }
0353 
0354   // returns 2 ** size_
0355   unsigned long long int iMax() const {
0356     static const std::array<unsigned long long int, S_> lut = powersOfTwo();
0357     return lut[size_];
0358   }
0359 };
0360 
0361 #endif