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:
Ryan Henry 2026-09-24 20:44:07 -06:00
parent 875f09fec1
commit 0d8a5a8131
97 changed files with 9212 additions and 1159 deletions

View file

@ -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)
{