Annotate noexcept and constexpr with HEDLEY, and add interval containment, ChaCha, and the dyadic range tables.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
875f09fec1
commit
0d8a5a8131
97 changed files with 9212 additions and 1159 deletions
|
|
@ -69,14 +69,23 @@ class numeric_limits<::uint128_t>
|
|||
static constexpr bool traps = false;
|
||||
static constexpr bool tinyness_before = false;
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint128_t min() noexcept { return uint128_t{0ul, 0ul}; }
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint128_t lowest() noexcept { return uint128_t{0ul, 0ul}; }
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint128_t max() noexcept { return uint128_t{-1ul, -1ul}; }
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint128_t epsilon() noexcept { return 0; }
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint128_t round_error() noexcept { return 0; }
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint128_t infinity() noexcept { return 0; }
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint128_t quiet_NaN() noexcept { return 0; }
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint128_t signaling_NaN() noexcept { return 0; }
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint128_t denorm_min() noexcept { return 0; }
|
||||
};
|
||||
|
||||
|
|
@ -127,14 +136,23 @@ class numeric_limits<::uint256_t>
|
|||
static constexpr bool traps = false;
|
||||
static constexpr bool tinyness_before = false;
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint256_t min() noexcept { return uint256_t{uint128_t{0ul, 0ul}, uint128_t{0ul, 0ul}}; }
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint256_t lowest() noexcept { return uint256_t{uint128_t{0ul, 0ul}, uint128_t{0ul, 0ul}}; }
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint256_t max() noexcept { return uint256_t{uint128_t{-1ul, -1ul}, uint128_t{-1ul, -1ul}}; }
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint256_t epsilon() noexcept { return 0; }
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint256_t round_error() noexcept { return 0; }
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint256_t infinity() noexcept { return 0; }
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint256_t quiet_NaN() noexcept { return 0; }
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint256_t signaling_NaN() noexcept { return 0; }
|
||||
HEDLEY_NO_THROW
|
||||
static constexpr uint256_t denorm_min() noexcept { return 0; }
|
||||
};
|
||||
|
||||
|
|
@ -266,6 +284,7 @@ auto make_bitset(Bools ...bs)
|
|||
}
|
||||
|
||||
template <typename NodeT>
|
||||
HEDLEY_NO_THROW
|
||||
static NodeT single_bit_mask(std::size_t i) noexcept;
|
||||
|
||||
template <>
|
||||
|
|
@ -449,6 +468,7 @@ struct make_from_integral_value
|
|||
// for `unsigned __int128`.
|
||||
using integral_type = typename make_signed_if<S_integral_type,
|
||||
std::is_signed_v<T> && sizeof(S_integral_type) <= 8>::type;
|
||||
HEDLEY_NO_THROW
|
||||
constexpr T operator()(integral_type val) const noexcept
|
||||
{
|
||||
return static_cast<T>(val);
|
||||
|
|
@ -459,6 +479,7 @@ struct make_from_integral_value
|
|||
/// `static_cast<T>(x0 ^ x1)`: for `keyword`, `operator^` yields the parent
|
||||
/// `modint`, which cannot convert back through the private keyword ctor.
|
||||
template <typename T>
|
||||
HEDLEY_NO_THROW
|
||||
constexpr T xor_input_shares(T x0, T x1) noexcept
|
||||
{
|
||||
constexpr auto to_int = to_integral_type<T>{};
|
||||
|
|
@ -490,6 +511,7 @@ static constexpr IntegralT get_node_mask(InputT mask, std::size_t level_index)
|
|||
/// width is undefined for the native unsigned types).
|
||||
template <typename IntegralT>
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
HEDLEY_NO_THROW
|
||||
constexpr IntegralT shift_right(IntegralT value, std::size_t offset) noexcept
|
||||
{
|
||||
if (offset >= bitlength_of_v<IntegralT>)
|
||||
|
|
@ -500,6 +522,7 @@ constexpr IntegralT shift_right(IntegralT value, std::size_t offset) noexcept
|
|||
/// Floor of `from_inclusive / 2^lg_opl`. `lg_opl` is `log2(outputs_per_leaf)`.
|
||||
template <typename IntegralT>
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
HEDLEY_NO_THROW
|
||||
constexpr IntegralT leaf_node_floor(IntegralT from_inclusive, std::size_t lg_opl) noexcept
|
||||
{
|
||||
if (lg_opl == 0)
|
||||
|
|
@ -514,6 +537,7 @@ constexpr IntegralT leaf_node_floor(IntegralT from_inclusive, std::size_t lg_opl
|
|||
/// end (`[from, 2^width)`), which `split_leaf_nodes` interprets.
|
||||
template <typename IntegralT>
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
HEDLEY_NO_THROW
|
||||
constexpr IntegralT leaf_node_ceil_exclusive(IntegralT to_inclusive, std::size_t lg_opl) noexcept
|
||||
{
|
||||
constexpr std::size_t width = bitlength_of_v<IntegralT>;
|
||||
|
|
@ -585,25 +609,87 @@ struct node_segments
|
|||
std::size_t total = 0;
|
||||
};
|
||||
|
||||
/// True when the inclusive walk `[from, to]` wraps the low `bits` of the
|
||||
/// domain. Comparison is on the post-MSB-flip bit pattern. Leaf ids alone
|
||||
/// cannot carry this: packing can put a wrapping pair into `from_node <= to_node`.
|
||||
template <typename IntegralT>
|
||||
inline bool interval_wraps(IntegralT from, IntegralT to, std::size_t bits)
|
||||
{
|
||||
if (bits == 0)
|
||||
return false;
|
||||
if (bits < bitlength_of_v<IntegralT>)
|
||||
{
|
||||
const IntegralT mask = static_cast<IntegralT>(
|
||||
(IntegralT{1} << bits) - IntegralT{1});
|
||||
return (from & mask) > (to & mask);
|
||||
}
|
||||
return from > to;
|
||||
}
|
||||
|
||||
/// Split an inclusive output interval, already reduced to leaf ids, into one
|
||||
/// or two half-open walks. A linearized `from_node > to_node` wraps the node
|
||||
/// id space `[0, 2^depth)`. A saturated `to_node == 0` means the exclusive end
|
||||
/// is `2^{bitwidth(IntegralT)}`, which is the whole id space when `depth` is
|
||||
/// that width.
|
||||
///
|
||||
/// `input_wraps` is the order of the original inputs, before leaf coarsening.
|
||||
/// The buffer is still two runs, `[from_node, 2^depth)` then `[0, to_node)`,
|
||||
/// even when packing makes `from_node <= to_node`. In that case the runs
|
||||
/// overlap on the shared leaf: the iterable's preclip consumes the start of
|
||||
/// the first copy and its length stops inside the second. Collapsing the
|
||||
/// overlap into one forward segment writes the wrong leaves.
|
||||
template <typename IntegralT>
|
||||
inline node_segments<IntegralT> split_leaf_nodes(IntegralT from_node,
|
||||
IntegralT to_node, std::size_t depth)
|
||||
IntegralT to_node, std::size_t depth, bool input_wraps = false)
|
||||
{
|
||||
node_segments<IntegralT> out;
|
||||
constexpr std::size_t width = bitlength_of_v<IntegralT>;
|
||||
constexpr std::size_t size_digits = bitlength_of_v<std::size_t>;
|
||||
auto push = [&](IntegralT lo, IntegralT hi)
|
||||
{
|
||||
const std::size_t count = static_cast<std::size_t>(hi - lo);
|
||||
std::size_t count = 0;
|
||||
if (hi == IntegralT{0} && lo != IntegralT{0})
|
||||
{
|
||||
// Exclusive end is 2^width. The count fits in size_t only when
|
||||
// that power is one past size_t's maximum and lo is nonzero.
|
||||
if (width > size_digits)
|
||||
throw std::length_error("DPF leaf domain does not fit in size_t");
|
||||
count = static_cast<std::size_t>(0) - static_cast<std::size_t>(lo);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto wide = hi - lo;
|
||||
if (wide > IntegralT(std::numeric_limits<std::size_t>::max()))
|
||||
throw std::length_error("DPF leaf domain does not fit in size_t");
|
||||
count = static_cast<std::size_t>(wide);
|
||||
}
|
||||
if (count == 0)
|
||||
return;
|
||||
if (out.total > std::numeric_limits<std::size_t>::max() - count)
|
||||
throw std::length_error("DPF leaf domain does not fit in size_t");
|
||||
out.seg[out.n++] = node_segment<IntegralT>{lo, hi, count};
|
||||
out.total += count;
|
||||
};
|
||||
|
||||
if (input_wraps)
|
||||
{
|
||||
if (depth >= width)
|
||||
{
|
||||
if (from_node == IntegralT{0})
|
||||
throw std::length_error("DPF leaf domain does not fit in size_t");
|
||||
push(from_node, IntegralT{0});
|
||||
if (to_node != IntegralT{0})
|
||||
push(IntegralT{0}, to_node);
|
||||
return out;
|
||||
}
|
||||
const IntegralT domain_end = static_cast<IntegralT>(IntegralT{1} << depth);
|
||||
if (from_node < domain_end)
|
||||
push(from_node, domain_end);
|
||||
if (to_node != IntegralT{0})
|
||||
push(IntegralT{0}, to_node);
|
||||
return out;
|
||||
}
|
||||
|
||||
if (to_node != IntegralT{0} && from_node < to_node)
|
||||
{
|
||||
push(from_node, to_node);
|
||||
|
|
@ -612,7 +698,6 @@ inline node_segments<IntegralT> split_leaf_nodes(IntegralT from_node,
|
|||
if (to_node != IntegralT{0} && from_node == to_node)
|
||||
return out;
|
||||
|
||||
constexpr std::size_t width = bitlength_of_v<IntegralT>;
|
||||
if (from_node == IntegralT{0} && to_node == IntegralT{0})
|
||||
throw std::length_error("DPF leaf domain does not fit in size_t");
|
||||
|
||||
|
|
@ -638,14 +723,26 @@ static constexpr std::size_t get_leafnodes_in_node_interval(IntegralT from_node,
|
|||
return static_cast<std::size_t>(to_node - from_node);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void flip_msb_if_signed_integral(T & x);
|
||||
|
||||
template <typename DpfKey,
|
||||
typename InputT = typename DpfKey::input_type,
|
||||
typename IntegralT = typename DpfKey::integral_type>
|
||||
static std::size_t get_leafnodes_in_output_interval(InputT from, InputT to)
|
||||
{
|
||||
return split_leaf_nodes(get_from_node<DpfKey, InputT, IntegralT>(from),
|
||||
get_to_node<DpfKey, InputT, IntegralT>(to),
|
||||
static_cast<std::size_t>(DpfKey::depth)).total;
|
||||
// Match eval: the walk order is the bit pattern after the sign flip.
|
||||
InputT flipped_from = from;
|
||||
InputT flipped_to = to;
|
||||
flip_msb_if_signed_integral(flipped_from);
|
||||
flip_msb_if_signed_integral(flipped_to);
|
||||
constexpr auto to_int = to_integral_type<InputT>{};
|
||||
const auto from_i = static_cast<IntegralT>(to_int(flipped_from));
|
||||
const auto to_i = static_cast<IntegralT>(to_int(flipped_to));
|
||||
const bool wraps = interval_wraps(from_i, to_i, bitlength_of_v<InputT>);
|
||||
return split_leaf_nodes(get_from_node<DpfKey, InputT, IntegralT>(flipped_from),
|
||||
get_to_node<DpfKey, InputT, IntegralT>(flipped_to),
|
||||
static_cast<std::size_t>(DpfKey::depth), wraps).total;
|
||||
}
|
||||
|
||||
/// Historical name used by the test suite.
|
||||
|
|
@ -660,6 +757,7 @@ static std::size_t get_nodes_in_interval(InputT from, InputT to)
|
|||
template <typename T>
|
||||
struct mod_pow_2
|
||||
{
|
||||
HEDLEY_NO_THROW
|
||||
std::size_t operator()(T val, std::size_t n) const noexcept
|
||||
{
|
||||
if (n == 0)
|
||||
|
|
@ -696,6 +794,7 @@ static constexpr auto msb_of_v = msb_of<T>::value;
|
|||
template <typename T>
|
||||
struct countl_zero
|
||||
{
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_CONST
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr std::size_t operator()(T val) const noexcept
|
||||
|
|
@ -724,6 +823,7 @@ struct countl_zero
|
|||
template <typename T>
|
||||
struct countr_zero
|
||||
{
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_CONST
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr std::size_t operator()(T val) const noexcept
|
||||
|
|
@ -756,6 +856,7 @@ struct countr_zero
|
|||
template <typename T>
|
||||
struct countl_zero_symmetric_difference
|
||||
{
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_CONST
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr std::size_t operator()(T lhs, T rhs) const noexcept
|
||||
|
|
@ -773,6 +874,7 @@ struct countl_zero<simde_int128>
|
|||
{
|
||||
using T = simde_int128;
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_PURE
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr std::size_t operator()(const T & val) const noexcept
|
||||
|
|
@ -795,6 +897,7 @@ struct countl_zero<simde_uint128>
|
|||
{
|
||||
using T = simde_uint128;
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_PURE
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr std::size_t operator()(const T & val) const noexcept
|
||||
|
|
@ -812,6 +915,7 @@ struct countl_zero<uint128_t>
|
|||
{
|
||||
using T = uint128_t;
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_PURE
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr std::size_t operator()(const T & val) const noexcept
|
||||
|
|
@ -828,6 +932,7 @@ struct countl_zero<uint256_t>
|
|||
{
|
||||
using T = uint256_t;
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_PURE
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr std::size_t operator()(const T & val) const noexcept
|
||||
|
|
@ -844,6 +949,7 @@ struct countl_zero<simde__m128i>
|
|||
{
|
||||
using T = simde__m128i;
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_PURE
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
std::size_t operator()(const T & val) const noexcept
|
||||
|
|
@ -860,6 +966,7 @@ template <>
|
|||
struct countl_zero<simde__m256i>
|
||||
{
|
||||
using T = simde__m256i;
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_PURE
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr std::size_t operator()(const T & val) const noexcept
|
||||
|
|
@ -882,6 +989,7 @@ struct countr_zero<simde_int128>
|
|||
{
|
||||
using T = simde_int128;
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_PURE
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr std::size_t operator()(const T & val) const noexcept
|
||||
|
|
@ -898,6 +1006,7 @@ struct countr_zero<simde_uint128>
|
|||
{
|
||||
using T = simde_uint128;
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_PURE
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr std::size_t operator()(const T & val) const noexcept
|
||||
|
|
@ -914,6 +1023,7 @@ struct countr_zero<uint128_t>
|
|||
{
|
||||
using T = uint128_t;
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_PURE
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr std::size_t operator()(const T & val) const noexcept
|
||||
|
|
@ -930,6 +1040,7 @@ struct countr_zero<uint256_t>
|
|||
{
|
||||
using T = uint256_t;
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_PURE
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr std::size_t operator()(const T & val) const noexcept
|
||||
|
|
@ -946,6 +1057,7 @@ struct countr_zero<simde__m128i>
|
|||
{
|
||||
using T = simde__m128i;
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_PURE
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
std::size_t operator()(const T & val) const noexcept
|
||||
|
|
@ -963,6 +1075,7 @@ struct countr_zero<simde__m256i>
|
|||
{
|
||||
using T = simde__m256i;
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_PURE
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr std::size_t operator()(const T & val) const noexcept
|
||||
|
|
@ -1026,13 +1139,19 @@ static constexpr std::size_t packed_lane_bits_v
|
|||
= packed_lane_bits<std::remove_cv_t<T>>::value;
|
||||
|
||||
template <typename T>
|
||||
auto data(T & bar) // NOLINT(runtime/references)
|
||||
HEDLEY_PURE
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr auto data(T & bar) noexcept // NOLINT(runtime/references)
|
||||
{
|
||||
return std::data(bar);
|
||||
}
|
||||
|
||||
/// Pointer overload. Constness of `bar` is the constness of `T`.
|
||||
template <typename T>
|
||||
auto data(T * bar)
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr T * data(T * bar) noexcept
|
||||
{
|
||||
return bar;
|
||||
}
|
||||
|
|
@ -1063,7 +1182,10 @@ template <typename T>
|
|||
static constexpr bool is_tuple_v = is_tuple<T>::value;
|
||||
|
||||
template <std::size_t I, typename T>
|
||||
auto & get(T & t) // NOLINT(runtime/references)
|
||||
HEDLEY_PURE
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr auto & get(T & t) noexcept // NOLINT(runtime/references)
|
||||
{
|
||||
if constexpr(I == 0 && is_tuple_v<T> == false)
|
||||
{
|
||||
|
|
@ -1085,7 +1207,10 @@ template <typename T>
|
|||
static constexpr bool is_bit_array_v = is_bit_array<T>::value;
|
||||
|
||||
template <typename T>
|
||||
auto size(const T & t)
|
||||
HEDLEY_PURE
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
constexpr auto size(const T & t) noexcept
|
||||
{
|
||||
if constexpr(is_bit_array_v<T> == false)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue