/// @file dpf/bitstring.hpp /// @brief defines `dpf::bitstring` and associated helpers /// @details A `dpf::bitstring` represents a fixed-length string of bits that does /// not semantically stand for a numerical value. It is implemented /// as a simple subclass of a `dpf::bit_array_base`, but contains /// helper functions for common tasks like performing lexicographic /// comparisons or converting to and from regular C-strings. This type /// is intended for use as an [input type](@ref input_types) for a DPF and, as such, /// specializes `dpf::utils::bitlength_of`, `dpf::utils::msb_of`, and /// `dpf::utils::countl_zero_symmetric_difference`. It also defines an /// efficient `dpf::bitstring::bit_mask` facade to simulate the behavior that the /// evaluation functions expect of `dpf::utils::msb_of`. /// /// The `dpf::bitstring` class defines a default constructor that /// initializes the bitstring with all bits set to `0`, /// alongside compiler-generated copy and move constructors, and a /// value constructor that initializes the first `M` bit positions with /// the bits of the given value, where `M` is the smaller of `Nbits` and /// `64`. It also defines the user-defined numeric literal /// `dpf::literals::operator "" _bitstring()` for creating `dpf::bitstring` objects /// at compile time, where `Nbits` is the length of the numeric literal /// (i.e., minus the ``"_bitstring"`` suffix). For example, the expression /// \code{.cpp} /// auto x = 10101001_bitstring /// \endcode /// yields a `dpf::bitstring<8>` with the bits `10101001`, and is /// therefore equivalent to invoking /// \code{.cpp} /// dpf::bitstring<8> x(0b10101001); /// \endcode /// @author Ryan Henry /// @copyright Copyright (c) 2019-2024 Ryan Henry and [others](@ref authors) /// @license Released under a GNU General Public v2.0 (GPLv2) license; /// see [LICENSE.md](@ref license) for details. #ifndef LIBDPF_INCLUDE_DPF_BITSTRING_HPP__ #define LIBDPF_INCLUDE_DPF_BITSTRING_HPP__ #include "hedley/hedley.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "portable-snippets/exact-int/exact-int.h" #include "dpf/bit.hpp" #include "dpf/bit_array.hpp" #include "dpf/utils.hpp" #include "dpf/literals.hpp" namespace dpf { /// @brief a fixed-length string of bits /// @details The `dpf::bitstring` class template represents a fixed-length /// string of bits that does not semantically stand for a /// numerical value. It is implemented as a subclass of /// `dpf::bit_array_base` and is parametrized on `Nbits`, which is /// the length of the bitstring. /// @tparam Nbits the bitlength of the string template > class bitstring : public bit_array_base, WordT> { private: using base = bit_array_base, WordT>; public: using word_pointer = typename base::word_pointer; using const_word_pointer = typename base::const_word_pointer; using word_type = typename base::word_type; using const_pointer = typename base::const_pointer; using size_type = typename base::size_type; static constexpr auto bits_per_word = base::bits_per_word; private: /// @brief the number of `word_type`s are being used to represent the /// `num_bits_` bits static constexpr size_type data_length_ = utils::quotient_ceiling(Nbits, bits_per_word); public: /// @brief the primitive integral type used to represent the string, /// note this should be based on Nbits and not WordT using integral_type = utils::integral_type_from_bitlength_t; /// @name C'tors /// @brief Constructs the default allocator. Since the default allocator /// is stateless, the constructors have no visible effect. /// @{ /// @brief Default c'tor /// @details Constructs an instance of `dpf::bitstring` with all bits set /// to `0`. HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW constexpr bitstring() noexcept = default; /// @brief Copy c'tor /// @details Constructs an instance of `dpf::bitstring` from another /// using copy semantics. /// @param other another `dpf::bitstring` to construct with HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW constexpr bitstring(const bitstring & other) noexcept = default; /// @brief Move c'tor /// @details Constructs an instance of `dpf::bitstring` from another /// using move semantics. /// @param other another `dpf::bitstring` to construct with HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW constexpr bitstring(bitstring && other) noexcept = default; /// @brief Value c'tor /// @details Constructs an instance of `dpf::bitstring` while initializing /// the first (rightmost, least significant) `M` bit positions to /// the corresponding bit values of `val`, where `M` is the /// smaller of `Nbits` and `bits_per_word`. /// @param val the number used to initialize the `dpf::bitstring` HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW constexpr explicit bitstring(word_type val) noexcept : data_{Nbits < bits_per_word ? static_cast(val & (static_cast(~word_type{0}) >> utils::bitlength_of_v - Nbits)) : val} { } /// @brief Constructs a `dpf::bitstring` using the characters in the /// `std::basic_string` `str`. An optional starting position `pos` /// and length `len` can be provided, as well as characters /// denoting alternate values for set (`one`) and unset (`zero`) /// bits. /// @param str `string` used to initialize the `dpf::bitstring` /// @param pos a starting offset into `str` /// @param len number of characters to use from `str` /// @param zero character used to represent `0` (default: `CharT('0')`) /// @param one character used to represent `1` (default: `CharT('1')`) template explicit bitstring( const std::basic_string & str, typename std::basic_string::size_type pos = 0, typename std::basic_string::size_type len = std::basic_string::npos, CharT zero = CharT('0'), CharT one = CharT('1')) { if (pos > str.size()) { std::stringstream ss; ss << "dpf::bitstring: pos (which is " << pos << ") > str.size() (which is " << str.size() << ")"; throw std::out_of_range(ss.str()); } len = std::min(len, str.size() - pos); assign_msb_string(str.data() + pos, len, zero, one); } /// @brief Constructs a `dpf::bitstring` using the characters in the /// `CharT *` `str`. An optional starting position `pos` and length /// `len` can be provided, as well as characters denoting alternate /// values for set (`one`) and unset (`zero`) bits. /// @param str string used to initialize the `dpf::bitstring` /// @param len number of characters to use from `str` /// @param zero character used to represent `false`/`0` (default: ``CharT('0')``) /// @param one character used to represent `true`/`1` (default: ``CharT('1')``) template explicit bitstring(const CharT * str, typename std::basic_string::size_type len = std::basic_string::npos, CharT zero = CharT('0'), CharT one = CharT('1')) { if (str == nullptr) { throw std::invalid_argument("dpf::bitstring: null string"); } len = std::min(len, strnlen(str, len)); assign_msb_string(str, len, zero, one); } /// @} HEDLEY_NO_THROW bitstring & operator=(const bitstring &) noexcept = default; HEDLEY_NO_THROW bitstring & operator=(bitstring &&) noexcept = default; ~bitstring() = default; // template , bool> = false> // bitstring & operator=(integral_type value) // { // *data_ = (Nbits < bits_per_word) // ? static_cast(value & (static_cast(~word_type{0}) >> utils::bitlength_of_v - Nbits)) : value; // return *this; // } /// @brief facade for masking out individual bits of a `dpf::bitstring` /// @details A `dpf::bitstring::bit_mask` struct is a facade that simulates /// the behaviour of a 1-bit mask for us in the `dpf::eval_*` /// family of functions. Specifically, it can be used in loops /// such as /// \code{c++} /// auto x = dpf::bitstring = ...; /// auto mask = dpf::msb_of(x); /// for (auto i = 0; i < Nbits; ++i, mask>>=1) /// { /// bool bit = !!(mask & x); /// // ... /// } /// \endcode /// to iterate iver the individual bits of a `dpf::bitstring` /// efficiently. struct bit_mask { /// @brief constructs a `dpf::bitstring::bit_mask` object that masks /// the bit at the given position /// @param which_bit the ordinal position of the bit to mask HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW constexpr explicit bit_mask(std::size_t which_bit) noexcept : which_bit_{which_bit} { } /// @brief shifts the bit mask to the right by the given number of /// bits /// @param shift_by number of bits to shift the mask to the right /// @return a reference to the modified `dpf::bitstring::bit_mask` HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW constexpr bit_mask & operator>>=(int shift_by) noexcept { if (shift_by <= 0) { if (shift_by < 0) which_bit_ += static_cast(-shift_by); return *this; } const auto by = static_cast(shift_by); which_bit_ = by > which_bit_ ? static_cast(-1) : which_bit_ - by; return *this; } /// @brief shifts the bit mask to the left by the given number of /// bits /// @param shift_by number of bits to shift the mask to the left /// @return a reference to the modified `dpf::bitstring::bit_mask` HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW constexpr bit_mask & operator<<=(int shift_by) noexcept { which_bit_ += shift_by; return *this; } HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW constexpr bool operator&(const bitstring & rhs) const noexcept { if (which_bit_ >= Nbits) return false; return rhs[which_bit_]; } /// @brief returns `true` if and only if the bit mask corresponds to a /// valid bit position in a `dpf::bitstring` /// @return `(0 <= which_bit()) && (which_bit() < Nbits)` HEDLEY_ALWAYS_INLINE HEDLEY_PURE HEDLEY_NO_THROW constexpr operator bool() const noexcept { return which_bit_ < Nbits; } /// @brief returns the ordinal position of the bit being masked out by /// this `dpf::bitstring::big_mask` /// @return HEDLEY_ALWAYS_INLINE HEDLEY_PURE HEDLEY_NO_THROW constexpr std::size_t which_bit() const noexcept { return which_bit_; } /// @brief shifts the bit mask to the right by the given number of /// bits /// @param shift_by number of bits to shift the mask to the right /// @return a reference to the modified `dpf::bitstring::bit_mask` HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW friend constexpr bit_mask operator>>(const bit_mask & mask, std::size_t shift_by) noexcept { if (shift_by > mask.which_bit_) return bit_mask{static_cast(-1)}; return bit_mask{mask.which_bit_ - shift_by}; } /// @brief shifts the bit mask to the left by the given number of /// bits /// @param shift_by number of bits to shift the mask to the right /// @return a reference to the modified `dpf::bitstring::bit_mask` HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW friend constexpr bit_mask operator<<(const bit_mask & mask, std::size_t shift_by) noexcept { return bit_mask{mask.which_bit_ + shift_by}; } private: std::size_t which_bit_; // ordinal position of the referenced bit }; // struct dpf::bitstring::bit_mask /// @brief extract the bit of `dpf::bitstring` that using a /// `dpf::bitstring::bit_mask` /// @param rhs the `dpf::bitstring::bit_mask` indicating which bit to /// extract /// @return `true` if the referenced bit is set, and `false` otherwise HEDLEY_ALWAYS_INLINE HEDLEY_PURE bool operator&(const bitstring::bit_mask & rhs) const { if (rhs.which_bit() >= Nbits) return false; return this->operator[](rhs.which_bit()); } /// @brief lexicographically compares two `dpf::bitstring`s /// @{ /// @brief Equality of the defined bits. Unused bits above `Nbits` are ignored. HEDLEY_ALWAYS_INLINE constexpr bool operator==(const bitstring & rhs) const { return compare(rhs) == 0; } /// @brief Inequality of the defined bits. HEDLEY_ALWAYS_INLINE constexpr bool operator!=(const bitstring & rhs) const { return compare(rhs) != 0; } /// @brief Less than, most-significant bit first. HEDLEY_ALWAYS_INLINE constexpr bool operator<(const bitstring & rhs) const { return compare(rhs) < 0; } /// @brief Less than or equal, most-significant bit first. HEDLEY_ALWAYS_INLINE constexpr bool operator<=(const bitstring & rhs) const { return compare(rhs) <= 0; } /// @brief Greater than, most-significant bit first. HEDLEY_ALWAYS_INLINE constexpr bool operator>(const bitstring & rhs) const { return compare(rhs) > 0; } /// @brief Greater than or equal, most-significant bit first. HEDLEY_ALWAYS_INLINE constexpr bool operator>=(const bitstring & rhs) const { return compare(rhs) >= 0; } HEDLEY_PURE HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE constexpr bitstring operator~() const noexcept { bitstring ret = *this; ret.flip(); return ret; } using base::flip; /// @brief Flips every defined bit and clears bits above `Nbits`. HEDLEY_NO_THROW constexpr void flip() noexcept { base::flip(); } HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE constexpr bitstring & operator++() noexcept { if constexpr (data_length_ == 0) return *this; data_[0] += 1; word_type carry = (data_[0] == word_type{0}) ? 1 : 0; for (std::size_t i = 1; i < data_.size() && carry == 1; ++i) { data_[i] += carry; carry = (data_[i] == word_type{0}) ? 1 : 0; } clear_unused(); return *this; } HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE constexpr bitstring operator++(int) noexcept { auto ret = *this; this->operator++(); return ret; } HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE constexpr bitstring & operator--() noexcept { if constexpr (data_length_ == 0) return *this; data_[0] -= 1; word_type borrow = (data_[0] == ~word_type{0}) ? 1 : 0; for (std::size_t i = 1; i < data_.size() && borrow == 1; ++i) { data_[i] -= borrow; borrow = (data_[i] == ~word_type{0}) ? 1 : 0; } clear_unused(); return *this; } HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE constexpr bitstring operator--(int) noexcept { auto ret = *this; this->operator--(); return ret; } /// @} /// @brief direct access to the underlying data array /// @return a pointer to the start of the data array HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW constexpr word_pointer data() noexcept { return std::data(data_); } /// @brief direct access to the underlying data array /// @return a pointer to the start of the data array HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW constexpr const_word_pointer data() const noexcept { return std::data(data_); } /// @brief direct access into the underlying data array (w/o bounds /// checking) /// @param pos the array element to access /// @note Does not perform bounds checking; behaviour is undefined if /// `pos` is out of bounds /// @return `data()[pos]` HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE constexpr word_type data(size_type pos) const noexcept { return data()[pos]; } /// @brief direct access into the underlying data array (w/o bounds /// checking) /// @param pos the array element to access /// @note Does not perform bounds checking; behaviour is undefined if /// `pos` is out of bounds /// @return `data()[pos]` HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE constexpr word_type & data(size_type pos) noexcept { return data()[pos]; } /// @brief length of the underlying data array /// @return the number of elements in the underlying array HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE constexpr size_type data_length() const noexcept { return data_length_; } /// @brief returns the number of bits /// @returns number of bits that the `bitstring` holds /// @complexity `O(1)` HEDLEY_NO_THROW HEDLEY_PURE HEDLEY_ALWAYS_INLINE constexpr size_type size() const noexcept { return Nbits; } private: //alignas(utils::max_align_v) // memory here cannot be aligned if we wish // to remain trivially copyable std::array data_{}; /// @brief Mask of the bits that belong to this string in the high word. HEDLEY_NO_THROW static constexpr word_type defined_high_mask() noexcept { constexpr auto rem = Nbits % bits_per_word; if constexpr (rem == 0) return static_cast(~word_type{0}); else return static_cast((word_type{1} << rem) - word_type{1}); } HEDLEY_NO_THROW constexpr void clear_unused() noexcept { if constexpr (Nbits % bits_per_word != 0) data_[data_length_ - 1] &= defined_high_mask(); } /// @brief Most-significant word first. Unused high bits are ignored. /// Every limb is visited, so the time does not depend on where /// the strings differ. constexpr int compare(const bitstring & rhs) const { if constexpr (data_length_ == 0) return 0; constexpr auto mask = defined_high_mask(); constexpr auto last = data_length_ - 1; int result = 0; unsigned decided = 0; auto consider = [&](word_type a, word_type b) { const int c = (a > b) - (a < b); result += static_cast(decided == 0) * c; decided |= static_cast(a != b); }; consider(static_cast(data_[last] & mask), static_cast(rhs.data_[last] & mask)); for (std::size_t i = last; i-- > 0; ) consider(data_[i], rhs.data_[i]); return result; } /// @brief Last character is bit 0. `len` must be at most `Nbits`. template void assign_msb_string(const CharT * str, std::size_t len, CharT zero, CharT one) { if (len > Nbits) { throw std::out_of_range("dpf::bitstring: string longer than Nbits"); } for (std::size_t i = 0; i < len; ++i) (void)dpf::to_bit(str[i], zero, one); for (std::size_t i = 0; i < len; ++i) this->set(len - 1 - i, dpf::to_bit(str[i], zero, one)); } HEDLEY_ALWAYS_INLINE HEDLEY_PURE friend bitstring operator^(const bitstring & lhs, const bitstring & rhs) { bitstring ret; for (std::size_t i = 0; i < ret.data_length(); ++i) { ret.data(i) = lhs.data(i) ^ rhs.data(i); } ret.clear_unused(); return ret; } HEDLEY_ALWAYS_INLINE HEDLEY_PURE friend bitstring operator+(const bitstring & lhs, const bitstring & rhs) { return operator^(lhs, rhs); } HEDLEY_ALWAYS_INLINE HEDLEY_PURE friend bitstring operator-(const bitstring & lhs, const bitstring & rhs) { return operator^(lhs, rhs); } friend struct utils::countl_zero_symmetric_difference; friend struct utils::to_integral_type; friend struct utils::make_from_integral_value; friend struct utils::mod_pow_2; }; // class dpf::bitstring template inline std::ostream & operator<<(std::ostream & os, bitstring b) { return os << b.to_string(); } namespace utils { /// @brief specializes `dpf::utils::bitlength_of` for `dpf::bitstring` template struct bitlength_of> : public std::integral_constant { }; /// @brief specializes `dpf::utils::msb_of` for `dpf::bitstring` template struct msb_of> { constexpr static auto value = typename dpf::bitstring::bit_mask( bitlength_of_v>-1ul); }; /// @brief specializes `dpf::utils::countl_zero_symmetric_difference` for /// `dpf::bitstring` template struct countl_zero_symmetric_difference> { using T = dpf::bitstring; HEDLEY_NO_THROW HEDLEY_PURE HEDLEY_ALWAYS_INLINE constexpr std::size_t operator()(const T & lhs, const T & rhs) const noexcept { using word_type = typename T::word_type; constexpr auto xor_op = std::bit_xor{}; auto adjust = lhs.data_length()*bitlength_of_v - Nbits; std::size_t prefix_len = 0; for (auto i = lhs.data_length(); i > 0; --i, prefix_len += bitlength_of_v) { word_type limb = xor_op(lhs.data(i-1), rhs.data(i-1)); if (i == lhs.data_length()) limb = static_cast(limb & T::defined_high_mask()); if (limb) { const auto zeros = utils::clz(limb); return prefix_len + zeros - adjust; } } return prefix_len - adjust; } }; template struct to_integral_type> : public to_integral_type_base> { using parent = to_integral_type_base>; using typename parent::integral_type; static constexpr auto bits_per_word = dpf::bitstring::bits_per_word; static constexpr integral_type modulo_mask = static_cast(~integral_type{0}) >> utils::bitlength_of_v - ((Nbits-1) % bits_per_word + 1); HEDLEY_PURE HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE constexpr integral_type operator()(const dpf::bitstring & input) const noexcept { if constexpr(Nbits <= bits_per_word) { return integral_type(input.data_[0] & modulo_mask); } else { integral_type ret = input.data_[(Nbits-1)/bits_per_word] & modulo_mask; for (std::size_t i = (Nbits-1)/bits_per_word; i > 0; --i) { ret <<= bits_per_word; ret += input.data_[i-1]; } return ret; } } HEDLEY_PURE HEDLEY_NO_THROW HEDLEY_ALWAYS_INLINE constexpr integral_type operator()(const typename dpf::bitstring::bit_mask & input) const noexcept { return integral_type(1) << input.which_bit(); } }; template struct make_from_integral_value> { using T = dpf::bitstring; using T_integral_type = typename T::integral_type; using integral_type = std::conditional_t, simde_uint128, T_integral_type>; static constexpr auto mod = utils::mod_pow_2{}; static constexpr auto bits_per_last_word = Nbits % T::bits_per_word; HEDLEY_NO_THROW constexpr dpf::bitstring operator()(integral_type val) const noexcept { dpf::bitstring ret; std::size_t i = 0; HEDLEY_PRAGMA(GCC diagnostic push) HEDLEY_PRAGMA(GCC diagnostic ignored "-Wshift-count-overflow") for (; i < T::data_length_-1; ++i, val >>= T::bits_per_word) HEDLEY_PRAGMA(GCC diagnostic pop) { ret.data_[i] = static_cast(val); } ret.data_[i] = (bits_per_last_word == 0) ? static_cast(val) : mod(val, bits_per_last_word); return ret; } }; template struct mod_pow_2> { using T = dpf::bitstring; static constexpr auto to_int = to_integral_type{}; static constexpr auto mod = mod_pow_2{}; HEDLEY_NO_THROW std::size_t operator()(T val, std::size_t n) const noexcept { return mod(to_int(val), n); } }; } // namespace utils namespace bitstrings { // 1--9 using bit1_t = dpf::bitstring<1>; using bit2_t = dpf::bitstring<2>; using bit3_t = dpf::bitstring<3>; using bit4_t = dpf::bitstring<4>; using bit5_t = dpf::bitstring<5>; using bit6_t = dpf::bitstring<6>; using bit7_t = dpf::bitstring<7>; using bit8_t = dpf::bitstring<8>; using bit9_t = dpf::bitstring<9>; // 10--19 using bit10_t = dpf::bitstring<10>; using bit11_t = dpf::bitstring<11>; using bit12_t = dpf::bitstring<12>; using bit13_t = dpf::bitstring<13>; using bit14_t = dpf::bitstring<14>; using bit15_t = dpf::bitstring<15>; using bit16_t = dpf::bitstring<16>; using bit17_t = dpf::bitstring<17>; using bit18_t = dpf::bitstring<18>; using bit19_t = dpf::bitstring<19>; // 20--29 using bit20_t = dpf::bitstring<20>; using bit21_t = dpf::bitstring<21>; using bit22_t = dpf::bitstring<22>; using bit23_t = dpf::bitstring<23>; using bit24_t = dpf::bitstring<24>; using bit25_t = dpf::bitstring<25>; using bit26_t = dpf::bitstring<26>; using bit27_t = dpf::bitstring<27>; using bit28_t = dpf::bitstring<28>; using bit29_t = dpf::bitstring<29>; // 30-39 using bit30_t = dpf::bitstring<30>; using bit31_t = dpf::bitstring<31>; using bit32_t = dpf::bitstring<32>; using bit33_t = dpf::bitstring<33>; using bit34_t = dpf::bitstring<34>; using bit35_t = dpf::bitstring<35>; using bit36_t = dpf::bitstring<36>; using bit37_t = dpf::bitstring<37>; using bit38_t = dpf::bitstring<38>; using bit39_t = dpf::bitstring<39>; // 40--49 using bit40_t = dpf::bitstring<40>; using bit41_t = dpf::bitstring<41>; using bit42_t = dpf::bitstring<42>; using bit43_t = dpf::bitstring<43>; using bit44_t = dpf::bitstring<44>; using bit45_t = dpf::bitstring<45>; using bit46_t = dpf::bitstring<46>; using bit47_t = dpf::bitstring<47>; using bit48_t = dpf::bitstring<48>; using bit49_t = dpf::bitstring<49>; // 50--59 using bit50_t = dpf::bitstring<50>; using bit51_t = dpf::bitstring<51>; using bit52_t = dpf::bitstring<52>; using bit53_t = dpf::bitstring<53>; using bit54_t = dpf::bitstring<54>; using bit55_t = dpf::bitstring<55>; using bit56_t = dpf::bitstring<56>; using bit57_t = dpf::bitstring<57>; using bit58_t = dpf::bitstring<58>; using bit59_t = dpf::bitstring<59>; // 60--69 using bit60_t = dpf::bitstring<60>; using bit61_t = dpf::bitstring<61>; using bit62_t = dpf::bitstring<62>; using bit63_t = dpf::bitstring<63>; using bit64_t = dpf::bitstring<64>; using bit65_t = dpf::bitstring<65>; using bit66_t = dpf::bitstring<66>; using bit67_t = dpf::bitstring<67>; using bit68_t = dpf::bitstring<68>; using bit69_t = dpf::bitstring<69>; // 70--79 using bit70_t = dpf::bitstring<70>; using bit71_t = dpf::bitstring<71>; using bit72_t = dpf::bitstring<72>; using bit73_t = dpf::bitstring<73>; using bit74_t = dpf::bitstring<74>; using bit75_t = dpf::bitstring<75>; using bit76_t = dpf::bitstring<76>; using bit77_t = dpf::bitstring<77>; using bit78_t = dpf::bitstring<78>; using bit79_t = dpf::bitstring<79>; // 80--89 using bit80_t = dpf::bitstring<80>; using bit81_t = dpf::bitstring<81>; using bit82_t = dpf::bitstring<82>; using bit83_t = dpf::bitstring<83>; using bit84_t = dpf::bitstring<84>; using bit85_t = dpf::bitstring<85>; using bit86_t = dpf::bitstring<86>; using bit87_t = dpf::bitstring<87>; using bit88_t = dpf::bitstring<88>; using bit89_t = dpf::bitstring<89>; // 90--99 using bit90_t = dpf::bitstring<90>; using bit91_t = dpf::bitstring<91>; using bit92_t = dpf::bitstring<92>; using bit93_t = dpf::bitstring<93>; using bit94_t = dpf::bitstring<94>; using bit95_t = dpf::bitstring<95>; using bit96_t = dpf::bitstring<96>; using bit97_t = dpf::bitstring<97>; using bit98_t = dpf::bitstring<98>; using bit99_t = dpf::bitstring<99>; // 100--109 using bit100_t = dpf::bitstring<100>; using bit101_t = dpf::bitstring<101>; using bit102_t = dpf::bitstring<102>; using bit103_t = dpf::bitstring<103>; using bit104_t = dpf::bitstring<104>; using bit105_t = dpf::bitstring<105>; using bit106_t = dpf::bitstring<106>; using bit107_t = dpf::bitstring<107>; using bit108_t = dpf::bitstring<108>; using bit109_t = dpf::bitstring<109>; // 110--119 using bit110_t = dpf::bitstring<110>; using bit111_t = dpf::bitstring<111>; using bit112_t = dpf::bitstring<112>; using bit113_t = dpf::bitstring<113>; using bit114_t = dpf::bitstring<114>; using bit115_t = dpf::bitstring<115>; using bit116_t = dpf::bitstring<116>; using bit117_t = dpf::bitstring<117>; using bit118_t = dpf::bitstring<118>; using bit119_t = dpf::bitstring<119>; // 120--128 using bit120_t = dpf::bitstring<120>; using bit121_t = dpf::bitstring<121>; using bit122_t = dpf::bitstring<122>; using bit123_t = dpf::bitstring<123>; using bit124_t = dpf::bitstring<124>; using bit125_t = dpf::bitstring<125>; using bit126_t = dpf::bitstring<126>; using bit127_t = dpf::bitstring<127>; using bit128_t = dpf::bitstring<128>; namespace literals = dpf::literals::bitstrings; } // namespace bitstrings namespace literals { namespace bitstrings { /// @brief Build a bitstring from characters. The first character is the /// most significant bit of the digit string (same order as `0b...`). /// Digits shorter than `Bitstring::size()` occupy the low bits. template constexpr Bitstring bitstring_literal() { static_assert(sizeof...(bits) <= Bitstring{}.size(), "bit literal is longer than the bitstring"); Bitstring bs{}; constexpr std::size_t n = sizeof...(bits); std::size_t pos = n; ((bs.set(--pos, dpf::to_bit(bits))), ...); return bs; } /// @brief user-defined numeric literal for creating `dpf::bitstring` objects /// @details The leftmost character is the most significant bit, matching /// `0b` integer literals. `10101001_bitstring` equals /// `dpf::bitstring<8>(0b10101001)`. template constexpr static auto operator "" _bitstring() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _bitstring_u8() { return bitstring_literal, bits...>(); } /// Alias used by the test suite: word type `uint8_t`, not length 8. template constexpr static auto operator "" _bitstring_8() { return operator ""_bitstring_u8(); } template constexpr static auto operator "" _bitstring_u16() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _bitstring_u32() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _bitstring_u64() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _bitstring_u128() { return bitstring_literal, bits...>(); } // 1--9 template constexpr static auto operator "" _b1() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b2() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b3() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b4() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b5() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b6() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b7() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b8() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b9() { return bitstring_literal, bits...>(); } // 10--19 template constexpr static auto operator "" _b10() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b11() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b12() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b13() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b14() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b15() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b16() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b17() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b18() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b19() { return bitstring_literal, bits...>(); } // 20--29 template constexpr static auto operator "" _b20() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b21() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b22() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b23() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b24() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b25() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b26() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b27() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b28() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b29() { return bitstring_literal, bits...>(); } // 30--39 template constexpr static auto operator "" _b30() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b31() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b32() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b33() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b34() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b35() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b36() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b37() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b38() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b39() { return bitstring_literal, bits...>(); } // 40--49 template constexpr static auto operator "" _b40() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b41() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b42() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b43() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b44() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b45() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b46() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b47() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b48() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b49() { return bitstring_literal, bits...>(); } // 50--59 template constexpr static auto operator "" _b50() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b51() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b52() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b53() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b54() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b55() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b56() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b57() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b58() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b59() { return bitstring_literal, bits...>(); } // 60--69 template constexpr static auto operator "" _b60() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b61() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b62() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b63() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b64() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b65() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b66() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b67() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b68() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b69() { return bitstring_literal, bits...>(); } // 70--79 template constexpr static auto operator "" _b70() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b71() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b72() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b73() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b74() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b75() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b76() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b77() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b78() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b79() { return bitstring_literal, bits...>(); } // 80--89 template constexpr static auto operator "" _b80() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b81() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b82() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b83() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b84() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b85() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b86() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b87() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b88() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b89() { return bitstring_literal, bits...>(); } // 90--99 template constexpr static auto operator "" _b90() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b91() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b92() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b93() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b94() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b95() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b96() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b97() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b98() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b99() { return bitstring_literal, bits...>(); } // 100--109 template constexpr static auto operator "" _b100() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b101() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b102() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b103() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b104() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b105() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b106() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b107() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b108() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b109() { return bitstring_literal, bits...>(); } // 110--119 template constexpr static auto operator "" _b110() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b111() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b112() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b113() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b114() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b115() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b116() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b117() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b118() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b119() { return bitstring_literal, bits...>(); } // 120--128 template constexpr static auto operator "" _b120() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b121() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b122() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b123() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b124() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b125() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b126() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b127() { return bitstring_literal, bits...>(); } template constexpr static auto operator "" _b128() { return bitstring_literal, bits...>(); } } // namespace bitstrings } // namespace literals } // namespace dpf namespace std { /// @brief specializes `std::numeric_limits` for CV-qualified `dpf::bitstring`s /// @{ /// @details specializes `std::numeric_limits` for `dpf::bitstring` template class numeric_limits> { public: static constexpr bool is_specialized = true; static constexpr bool is_signed = false; static constexpr bool is_integer = false; static constexpr bool is_exact = true; static constexpr bool has_infinity = false; static constexpr bool has_quiet_NaN = false; static constexpr bool has_signaling_NaN = false; static constexpr std::float_denorm_style has_denorm = std::denorm_absent; static constexpr bool has_denorm_loss = false; static constexpr std::float_round_style round_style = std::round_toward_zero; static constexpr bool is_iec559 = false; static constexpr bool is_bounded = true; static constexpr bool is_modulo = true; static constexpr int digits = Nbits; static constexpr int digits10 = static_cast((static_cast(Nbits) * 30103ull) / 100000ull); static constexpr int max_digits10 = 0; static constexpr int radix = 2; static constexpr int min_exponent = 0; static constexpr int max_exponent = 0; static constexpr int min_exponent10 = 0; static constexpr int max_exponent10 = 0; static constexpr bool traps = std::numeric_limits::integral_type>::traps; static constexpr bool tinyness_before = false; HEDLEY_NO_THROW static constexpr dpf::bitstring min() noexcept { return dpf::bitstring{}; } HEDLEY_NO_THROW static constexpr dpf::bitstring lowest() noexcept { return dpf::bitstring{}; } HEDLEY_NO_THROW static constexpr dpf::bitstring max() noexcept { return ~dpf::bitstring{}; } HEDLEY_NO_THROW static constexpr dpf::bitstring epsilon() noexcept { return 0; } HEDLEY_NO_THROW static constexpr dpf::bitstring round_error() noexcept { return 0; } HEDLEY_NO_THROW static constexpr dpf::bitstring infinity() noexcept { return 0; } HEDLEY_NO_THROW static constexpr dpf::bitstring quiet_NaN() noexcept { return 0; } HEDLEY_NO_THROW static constexpr dpf::bitstring signaling_NaN() noexcept { return 0; } HEDLEY_NO_THROW static constexpr dpf::bitstring denorm_min() noexcept { return 0; } }; /// @details specializes `std::numeric_limits` for `dpf::bitstring const` template class numeric_limits const> : public numeric_limits> {}; /// @details specializes `std::numeric_limits` for /// `dpf::bitstring volatile` template class numeric_limits volatile> : public numeric_limits> {}; /// @details specializes `std::numeric_limits` for /// `dpf::bitstring const volatile` template class numeric_limits const volatile> : public numeric_limits> {}; /// @} } // namespace std #endif // LIBDPF_INCLUDE_DPF_BITSTRING_HPP__