1248 lines
54 KiB
C++
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__
|