libdpf/include/dpf/bitstring.hpp

1248 lines
54 KiB
C++

/// @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<Nbits>` 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 <ryan.henry@ucalgary.ca>
/// @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 <cstddef>
#include <cstring>
#include <type_traits>
#include <stdexcept>
#include <functional>
#include <algorithm>
#include <iterator>
#include <limits>
#include <string>
#include <array>
#include <ostream>
#include <sstream>
#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
/// @tparam WordT word used to pack bits
template <std::size_t Nbits,
typename WordT = utils::integral_type_from_bitlength_t<Nbits, 8, 64>>
class bitstring : public bit_array_base<bitstring<Nbits, WordT>, WordT>
{
private:
using base = bit_array_base<bitstring<Nbits, WordT>, 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;
static constexpr bool dpf_bitstring = true;
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<Nbits>;
/// @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<word_type>(val & (static_cast<word_type>(~word_type{0}) >> utils::bitlength_of_v<word_type> - 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.
/// @tparam CharT character type
/// @tparam Traits character traits
/// @tparam Alloc allocator type
/// @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')`)
/// @throws std::out_of_range
template <typename CharT,
typename Traits,
typename Alloc>
explicit bitstring(
const std::basic_string<CharT, Traits, Alloc> & str,
typename std::basic_string<CharT, Traits, Alloc>::size_type pos = 0,
typename std::basic_string<CharT, Traits, Alloc>::size_type len
= std::basic_string<CharT, Traits, Alloc>::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.
/// @tparam CharT character type
/// @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')``)
/// @throws std::invalid_argument if `null string`
template <typename CharT>
explicit bitstring(const CharT * str,
typename std::basic_string<CharT>::size_type len
= std::basic_string<CharT>::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 <std::enable_if_t<std::is_same_v<word_type, integral_type>, bool> = false>
// bitstring & operator=(integral_type value)
// {
// *data_ = (Nbits < bits_per_word)
// ? static_cast<word_type>(value & (static_cast<word_type>(~word_type{0}) >> utils::bitlength_of_v<word_type> - 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<Nbits, WordT> = ...;
/// 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<std::size_t>(-shift_by);
return *this;
}
const auto by = static_cast<std::size_t>(shift_by);
which_bit_ = by > which_bit_
? static_cast<std::size_t>(-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<Nbits, WordT>`
/// @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
/// @param mask the bit mask
/// @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<std::size_t>(-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
/// @param mask the bit mask
/// @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.
/// @param rhs the right-hand operand
/// @return 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.
/// @param rhs the right-hand operand
/// @return 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.
/// @param rhs the right-hand operand
/// @return 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.
/// @param rhs the right-hand operand
/// @return 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
/// @return 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<word_type, data_length_> data_{};
/// @brief Mask of the bits that belong to this string in the high word.
/// @return the returned `word_type`
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>(~word_type{0});
else
return static_cast<word_type>((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.
/// @param rhs the right-hand operand
/// @return Most-significant word first
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<int>(decided == 0) * c;
decided |= static_cast<unsigned>(a != b);
};
consider(static_cast<word_type>(data_[last] & mask),
static_cast<word_type>(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`.
/// @tparam CharT character type
/// @param str the source string
/// @param len the number of bytes
/// @param zero the character used for 0
/// @param one the character used for 1
/// @throws std::out_of_range if `string longer than Nbits`
template <typename CharT>
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<bitstring>;
friend struct utils::to_integral_type<bitstring>;
friend struct utils::make_from_integral_value<bitstring>;
friend struct utils::mod_pow_2<bitstring>;
}; // class dpf::bitstring
template <std::size_t Nbits,
typename WordT>
inline std::ostream & operator<<(std::ostream & os, bitstring<Nbits, WordT> b)
{
return os << b.to_string();
}
namespace utils
{
/// @brief specializes `dpf::utils::bitlength_of` for `dpf::bitstring`
/// @tparam Nbits width in bits
/// @tparam WordT word used to pack bits
template <std::size_t Nbits,
typename WordT>
struct bitlength_of<dpf::bitstring<Nbits, WordT>>
: public std::integral_constant<std::size_t, Nbits>
{ };
/// @brief specializes `dpf::utils::msb_of` for `dpf::bitstring`
/// @tparam Nbits width in bits
/// @tparam WordT word used to pack bits
template <std::size_t Nbits,
typename WordT>
struct msb_of<dpf::bitstring<Nbits, WordT>>
{
constexpr static auto value
= typename dpf::bitstring<Nbits, WordT>::bit_mask(
bitlength_of_v<dpf::bitstring<Nbits, WordT>>-1ul);
};
/// @brief specializes `dpf::utils::countl_zero_symmetric_difference` for
/// `dpf::bitstring`
/// @tparam Nbits width in bits
/// @tparam WordT word used to pack bits
template <std::size_t Nbits,
typename WordT>
struct countl_zero_symmetric_difference<dpf::bitstring<Nbits, WordT>>
{
using T = dpf::bitstring<Nbits, WordT>;
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<word_type>{};
auto adjust = lhs.data_length()*bitlength_of_v<word_type> - Nbits;
std::size_t prefix_len = 0;
for (auto i = lhs.data_length(); i > 0; --i,
prefix_len += bitlength_of_v<word_type>)
{
word_type limb = xor_op(lhs.data(i-1), rhs.data(i-1));
if (i == lhs.data_length())
limb = static_cast<word_type>(limb & T::defined_high_mask());
if (limb)
{
const auto zeros = utils::clz(limb);
return prefix_len + zeros - adjust;
}
}
return prefix_len - adjust;
}
};
template <std::size_t Nbits,
typename WordT>
struct to_integral_type<dpf::bitstring<Nbits, WordT>>
: public to_integral_type_base<dpf::bitstring<Nbits, WordT>>
{
using parent = to_integral_type_base<dpf::bitstring<Nbits, WordT>>;
using typename parent::integral_type;
static constexpr auto bits_per_word = dpf::bitstring<Nbits, WordT>::bits_per_word;
static constexpr integral_type modulo_mask = static_cast<integral_type>(~integral_type{0}) >> utils::bitlength_of_v<integral_type> - ((Nbits-1) % bits_per_word + 1);
HEDLEY_PURE
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
constexpr integral_type operator()(const dpf::bitstring<Nbits, WordT> & 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<Nbits, WordT>::bit_mask & input) const noexcept
{
return integral_type(1) << input.which_bit();
}
};
template <std::size_t Nbits,
typename WordT>
struct make_from_integral_value<dpf::bitstring<Nbits, WordT>>
{
using T = dpf::bitstring<Nbits, WordT>;
using T_integral_type = typename T::integral_type;
using integral_type = std::conditional_t<std::is_void_v<T_integral_type>, simde_uint128, T_integral_type>;
static constexpr auto mod = utils::mod_pow_2<integral_type>{};
static constexpr auto bits_per_last_word = Nbits % T::bits_per_word;
HEDLEY_NO_THROW
constexpr dpf::bitstring<Nbits, WordT> operator()(integral_type val) const noexcept
{
dpf::bitstring<Nbits, WordT> 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<typename T::word_type>(val);
}
ret.data_[i] = (bits_per_last_word == 0)
? static_cast<typename T::word_type>(val)
: mod(val, bits_per_last_word);
return ret;
}
};
template <std::size_t Nbits,
typename WordT>
struct mod_pow_2<dpf::bitstring<Nbits, WordT>>
{
using T = dpf::bitstring<Nbits, WordT>;
static constexpr auto to_int = to_integral_type<T>{};
static constexpr auto mod = mod_pow_2<typename T::integral_type>{};
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.
/// @tparam Bitstring bitstring
/// @tparam bits bits
/// @return the returned `Bitstring`
template <typename Bitstring, char... bits>
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)`.
/// @tparam bits bits
/// @return user-defined numeric literal for creating `dpf::bitstring` objects
template <char ...bits>
constexpr static auto operator "" _bitstring()
{
return bitstring_literal<dpf::bitstring<sizeof...(bits)>, bits...>();
}
template <char ...bits>
constexpr static auto operator "" _bitstring_u8()
{
return bitstring_literal<dpf::bitstring<sizeof...(bits), psnip_uint8_t>, bits...>();
}
/// @brief Alias used by the test suite: word type `uint8_t`, not length 8.
/// @tparam bits bits
/// @return Alias used by the test suite: word type `uint8_t`, not length 8
template <char ...bits>
constexpr static auto operator "" _bitstring_8()
{
return operator ""_bitstring_u8<bits...>();
}
template <char ...bits>
constexpr static auto operator "" _bitstring_u16()
{
return bitstring_literal<dpf::bitstring<sizeof...(bits), psnip_uint16_t>, bits...>();
}
template <char ...bits>
constexpr static auto operator "" _bitstring_u32()
{
return bitstring_literal<dpf::bitstring<sizeof...(bits), psnip_uint32_t>, bits...>();
}
template <char ...bits>
constexpr static auto operator "" _bitstring_u64()
{
return bitstring_literal<dpf::bitstring<sizeof...(bits), psnip_uint64_t>, bits...>();
}
template <char ...bits>
constexpr static auto operator "" _bitstring_u128()
{
return bitstring_literal<dpf::bitstring<sizeof...(bits), simde_uint128>, bits...>();
}
// 1--9
template <char ...bits> constexpr static auto operator "" _b1() { return bitstring_literal<dpf::bitstring<1>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b2() { return bitstring_literal<dpf::bitstring<2>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b3() { return bitstring_literal<dpf::bitstring<3>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b4() { return bitstring_literal<dpf::bitstring<4>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b5() { return bitstring_literal<dpf::bitstring<5>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b6() { return bitstring_literal<dpf::bitstring<6>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b7() { return bitstring_literal<dpf::bitstring<7>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b8() { return bitstring_literal<dpf::bitstring<8>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b9() { return bitstring_literal<dpf::bitstring<9>, bits...>(); }
// 10--19
template <char ...bits> constexpr static auto operator "" _b10() { return bitstring_literal<dpf::bitstring<10>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b11() { return bitstring_literal<dpf::bitstring<11>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b12() { return bitstring_literal<dpf::bitstring<12>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b13() { return bitstring_literal<dpf::bitstring<13>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b14() { return bitstring_literal<dpf::bitstring<14>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b15() { return bitstring_literal<dpf::bitstring<15>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b16() { return bitstring_literal<dpf::bitstring<16>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b17() { return bitstring_literal<dpf::bitstring<17>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b18() { return bitstring_literal<dpf::bitstring<18>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b19() { return bitstring_literal<dpf::bitstring<19>, bits...>(); }
// 20--29
template <char ...bits> constexpr static auto operator "" _b20() { return bitstring_literal<dpf::bitstring<20>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b21() { return bitstring_literal<dpf::bitstring<21>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b22() { return bitstring_literal<dpf::bitstring<22>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b23() { return bitstring_literal<dpf::bitstring<23>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b24() { return bitstring_literal<dpf::bitstring<24>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b25() { return bitstring_literal<dpf::bitstring<25>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b26() { return bitstring_literal<dpf::bitstring<26>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b27() { return bitstring_literal<dpf::bitstring<27>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b28() { return bitstring_literal<dpf::bitstring<28>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b29() { return bitstring_literal<dpf::bitstring<29>, bits...>(); }
// 30--39
template <char ...bits> constexpr static auto operator "" _b30() { return bitstring_literal<dpf::bitstring<30>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b31() { return bitstring_literal<dpf::bitstring<31>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b32() { return bitstring_literal<dpf::bitstring<32>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b33() { return bitstring_literal<dpf::bitstring<33>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b34() { return bitstring_literal<dpf::bitstring<34>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b35() { return bitstring_literal<dpf::bitstring<35>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b36() { return bitstring_literal<dpf::bitstring<36>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b37() { return bitstring_literal<dpf::bitstring<37>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b38() { return bitstring_literal<dpf::bitstring<38>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b39() { return bitstring_literal<dpf::bitstring<39>, bits...>(); }
// 40--49
template <char ...bits> constexpr static auto operator "" _b40() { return bitstring_literal<dpf::bitstring<40>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b41() { return bitstring_literal<dpf::bitstring<41>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b42() { return bitstring_literal<dpf::bitstring<42>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b43() { return bitstring_literal<dpf::bitstring<43>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b44() { return bitstring_literal<dpf::bitstring<44>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b45() { return bitstring_literal<dpf::bitstring<45>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b46() { return bitstring_literal<dpf::bitstring<46>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b47() { return bitstring_literal<dpf::bitstring<47>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b48() { return bitstring_literal<dpf::bitstring<48>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b49() { return bitstring_literal<dpf::bitstring<49>, bits...>(); }
// 50--59
template <char ...bits> constexpr static auto operator "" _b50() { return bitstring_literal<dpf::bitstring<50>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b51() { return bitstring_literal<dpf::bitstring<51>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b52() { return bitstring_literal<dpf::bitstring<52>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b53() { return bitstring_literal<dpf::bitstring<53>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b54() { return bitstring_literal<dpf::bitstring<54>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b55() { return bitstring_literal<dpf::bitstring<55>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b56() { return bitstring_literal<dpf::bitstring<56>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b57() { return bitstring_literal<dpf::bitstring<57>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b58() { return bitstring_literal<dpf::bitstring<58>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b59() { return bitstring_literal<dpf::bitstring<59>, bits...>(); }
// 60--69
template <char ...bits> constexpr static auto operator "" _b60() { return bitstring_literal<dpf::bitstring<60>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b61() { return bitstring_literal<dpf::bitstring<61>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b62() { return bitstring_literal<dpf::bitstring<62>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b63() { return bitstring_literal<dpf::bitstring<63>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b64() { return bitstring_literal<dpf::bitstring<64>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b65() { return bitstring_literal<dpf::bitstring<65>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b66() { return bitstring_literal<dpf::bitstring<66>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b67() { return bitstring_literal<dpf::bitstring<67>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b68() { return bitstring_literal<dpf::bitstring<68>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b69() { return bitstring_literal<dpf::bitstring<69>, bits...>(); }
// 70--79
template <char ...bits> constexpr static auto operator "" _b70() { return bitstring_literal<dpf::bitstring<70>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b71() { return bitstring_literal<dpf::bitstring<71>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b72() { return bitstring_literal<dpf::bitstring<72>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b73() { return bitstring_literal<dpf::bitstring<73>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b74() { return bitstring_literal<dpf::bitstring<74>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b75() { return bitstring_literal<dpf::bitstring<75>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b76() { return bitstring_literal<dpf::bitstring<76>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b77() { return bitstring_literal<dpf::bitstring<77>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b78() { return bitstring_literal<dpf::bitstring<78>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b79() { return bitstring_literal<dpf::bitstring<79>, bits...>(); }
// 80--89
template <char ...bits> constexpr static auto operator "" _b80() { return bitstring_literal<dpf::bitstring<80>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b81() { return bitstring_literal<dpf::bitstring<81>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b82() { return bitstring_literal<dpf::bitstring<82>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b83() { return bitstring_literal<dpf::bitstring<83>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b84() { return bitstring_literal<dpf::bitstring<84>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b85() { return bitstring_literal<dpf::bitstring<85>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b86() { return bitstring_literal<dpf::bitstring<86>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b87() { return bitstring_literal<dpf::bitstring<87>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b88() { return bitstring_literal<dpf::bitstring<88>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b89() { return bitstring_literal<dpf::bitstring<89>, bits...>(); }
// 90--99
template <char ...bits> constexpr static auto operator "" _b90() { return bitstring_literal<dpf::bitstring<90>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b91() { return bitstring_literal<dpf::bitstring<91>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b92() { return bitstring_literal<dpf::bitstring<92>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b93() { return bitstring_literal<dpf::bitstring<93>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b94() { return bitstring_literal<dpf::bitstring<94>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b95() { return bitstring_literal<dpf::bitstring<95>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b96() { return bitstring_literal<dpf::bitstring<96>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b97() { return bitstring_literal<dpf::bitstring<97>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b98() { return bitstring_literal<dpf::bitstring<98>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b99() { return bitstring_literal<dpf::bitstring<99>, bits...>(); }
// 100--109
template <char ...bits> constexpr static auto operator "" _b100() { return bitstring_literal<dpf::bitstring<100>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b101() { return bitstring_literal<dpf::bitstring<101>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b102() { return bitstring_literal<dpf::bitstring<102>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b103() { return bitstring_literal<dpf::bitstring<103>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b104() { return bitstring_literal<dpf::bitstring<104>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b105() { return bitstring_literal<dpf::bitstring<105>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b106() { return bitstring_literal<dpf::bitstring<106>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b107() { return bitstring_literal<dpf::bitstring<107>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b108() { return bitstring_literal<dpf::bitstring<108>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b109() { return bitstring_literal<dpf::bitstring<109>, bits...>(); }
// 110--119
template <char ...bits> constexpr static auto operator "" _b110() { return bitstring_literal<dpf::bitstring<110>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b111() { return bitstring_literal<dpf::bitstring<111>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b112() { return bitstring_literal<dpf::bitstring<112>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b113() { return bitstring_literal<dpf::bitstring<113>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b114() { return bitstring_literal<dpf::bitstring<114>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b115() { return bitstring_literal<dpf::bitstring<115>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b116() { return bitstring_literal<dpf::bitstring<116>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b117() { return bitstring_literal<dpf::bitstring<117>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b118() { return bitstring_literal<dpf::bitstring<118>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b119() { return bitstring_literal<dpf::bitstring<119>, bits...>(); }
// 120--128
template <char ...bits> constexpr static auto operator "" _b120() { return bitstring_literal<dpf::bitstring<120>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b121() { return bitstring_literal<dpf::bitstring<121>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b122() { return bitstring_literal<dpf::bitstring<122>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b123() { return bitstring_literal<dpf::bitstring<123>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b124() { return bitstring_literal<dpf::bitstring<124>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b125() { return bitstring_literal<dpf::bitstring<125>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b126() { return bitstring_literal<dpf::bitstring<126>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b127() { return bitstring_literal<dpf::bitstring<127>, bits...>(); }
template <char ...bits> constexpr static auto operator "" _b128() { return bitstring_literal<dpf::bitstring<128>, 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<Nbits, WordT>`
/// @tparam Nbits width in bits
/// @tparam WordT word used to pack bits
template<std::size_t Nbits,
typename WordT>
class numeric_limits<dpf::bitstring<Nbits, WordT>>
{
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<int>((static_cast<unsigned long long>(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<typename dpf::bitstring<Nbits, WordT>::integral_type>::traps;
static constexpr bool tinyness_before = false;
HEDLEY_NO_THROW
static constexpr dpf::bitstring<Nbits, WordT> min() noexcept { return dpf::bitstring<Nbits, WordT>{}; }
HEDLEY_NO_THROW
static constexpr dpf::bitstring<Nbits, WordT> lowest() noexcept { return dpf::bitstring<Nbits, WordT>{}; }
HEDLEY_NO_THROW
static constexpr dpf::bitstring<Nbits, WordT> max() noexcept { return ~dpf::bitstring<Nbits, WordT>{}; }
HEDLEY_NO_THROW
static constexpr dpf::bitstring<Nbits, WordT> epsilon() noexcept { return 0; }
HEDLEY_NO_THROW
static constexpr dpf::bitstring<Nbits, WordT> round_error() noexcept { return 0; }
HEDLEY_NO_THROW
static constexpr dpf::bitstring<Nbits, WordT> infinity() noexcept { return 0; }
HEDLEY_NO_THROW
static constexpr dpf::bitstring<Nbits, WordT> quiet_NaN() noexcept { return 0; }
HEDLEY_NO_THROW
static constexpr dpf::bitstring<Nbits, WordT> signaling_NaN() noexcept { return 0; }
HEDLEY_NO_THROW
static constexpr dpf::bitstring<Nbits, WordT> denorm_min() noexcept { return 0; }
};
/// @details specializes `std::numeric_limits` for `dpf::bitstring<Nbits, WordT> const`
/// @tparam Nbits width in bits
/// @tparam WordT word used to pack bits
template<std::size_t Nbits,
typename WordT>
class numeric_limits<dpf::bitstring<Nbits, WordT> const>
: public numeric_limits<dpf::bitstring<Nbits, WordT>> {};
/// @details specializes `std::numeric_limits` for
/// @brief `dpf::bitstring<Nbits, WordT> volatile`
/// @tparam Nbits width in bits
/// @tparam WordT word used to pack bits
template<std::size_t Nbits,
typename WordT>
class numeric_limits<dpf::bitstring<Nbits, WordT> volatile>
: public numeric_limits<dpf::bitstring<Nbits, WordT>> {};
/// @details specializes `std::numeric_limits` for
/// @brief `dpf::bitstring<Nbits, WordT> const volatile`
/// @tparam Nbits width in bits
/// @tparam WordT word used to pack bits
template<std::size_t Nbits,
typename WordT>
class numeric_limits<dpf::bitstring<Nbits, WordT> const volatile>
: public numeric_limits<dpf::bitstring<Nbits, WordT>> {};
/// @}
} // namespace std
#endif // LIBDPF_INCLUDE_DPF_BITSTRING_HPP__