1313// we need this to be true for GMP
1414static_assert (sizeof (long unsigned int ) == sizeof (long long unsigned int ));
1515
16+ // we make this assumption frequently
17+ static_assert (sizeof (1ull ) == 8 );
18+
1619namespace udb
1720{
1821
@@ -54,6 +57,9 @@ namespace udb
5457 static_assert (N > 0 );
5558
5659 public:
60+ // used for template concept resolution
61+ constexpr static bool IsABits = true ;
62+
5763 // value of N that represents unknown precision (happens when there is a left shift by unknown value)
5864 constexpr static unsigned InfinitePrecision = BitsInfinitePrecision;
5965
@@ -64,6 +70,8 @@ namespace udb
6470 // advertise the width
6571 constexpr static unsigned Width = N;
6672
73+ constexpr static unsigned width () { return N; }
74+
6775 using StorageType = typename BitsStorageType<N>::type;
6876 using SignedStorageType = typename BitsSignedStorageType<N>::type;
6977
@@ -78,9 +86,7 @@ namespace udb
7886 {
7987 using _StorageType = typename BitsStorageType<_N>::type;
8088
81- if constexpr (_N == InfinitePrecision)
82- {
83- // infinite bits, so there is no masking
89+ if constexpr (_N == InfinitePrecision) {
8490 return false ;
8591 }
8692 else if constexpr (_N > MaxNativePrecision)
@@ -996,6 +1002,8 @@ namespace udb
9961002
9971003 static_assert ((0x0_b).Width == 1 );
9981004 static_assert ((0x1_b).Width == 1 );
1005+ static_assert ((0_b).Width == 1 );
1006+ static_assert ((1_b).Width == 1 );
9991007 static_assert ((0x2_b).Width == 2 );
10001008 static_assert ((0x7_b).Width == 3 );
10011009 static_assert ((0x8_b).Width == 4 );
@@ -1247,3 +1255,49 @@ namespace udb {
12471255
12481256 using PossiblyUndefinedBits = Bits<66 >;
12491257}
1258+
1259+ namespace udb {
1260+ // Bits where the width is only known at runtime (usually because the width is parameter-dependent)
1261+ template <bool Signed>
1262+ class _RuntimeBits {
1263+ public:
1264+ template <unsigned N, bool _Signed>
1265+ _RuntimeBits (const _Bits<N, _Signed>& initial_value)
1266+ : m_value(initial_value), m_width(N)
1267+ {}
1268+
1269+ template <typename T>
1270+ _RuntimeBits (const T& initial_value, unsigned initial_width)
1271+ : m_value(initial_value), m_width(initial_width)
1272+ {}
1273+
1274+ unsigned width () const { return m_width; }
1275+ auto value () const { return m_value; }
1276+
1277+ template <typename T>
1278+ _RuntimeBits operator <<(const T& shamt) {
1279+ return {m_value << shamt, m_width + shamt};
1280+ }
1281+
1282+ template <unsigned N, bool _Signed>
1283+ _RuntimeBits operator |(const _Bits<N, _Signed>& other) {
1284+ return {m_value | other, std::max (N, m_width)};
1285+ }
1286+
1287+ _RuntimeBits operator |(const _RuntimeBits& other) {
1288+ return {m_value | other.m_value , std::max (other.m_width , m_width)};
1289+ }
1290+
1291+ private:
1292+ _Bits<BitsInfinitePrecision, Signed> m_value;
1293+ unsigned m_width;
1294+ };
1295+
1296+ template <unsigned N, bool ASigned, bool BSigned>
1297+ bool operator ==(const _Bits<N, ASigned>& a, const _RuntimeBits<BSigned>& b)
1298+ {
1299+ return a == b.value ();
1300+ }
1301+
1302+ using RuntimeBits = _RuntimeBits<false >;
1303+ }
0 commit comments