Document the new DPF surfaces in one command set, and test the field, half-tree, and multipoint edges.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ryan Henry 2026-09-24 23:18:10 -06:00
parent 0d8a5a8131
commit 0dff6df8ed
250 changed files with 12199 additions and 1981 deletions

View file

@ -1,6 +1,5 @@
/// @file dpf/bit_array.hpp
/// @brief
/// @details
/// @brief Packed bit arrays, static and dynamic, with bit proxies and iterators.
/// @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;
@ -68,6 +67,8 @@ class const_bit_iterator; // forward reference
/// @brief a base class for classes representing a sequence of bits
/// @details A `bit_array` represents a sequence of bits. The underlying
/// storage is an array of integers of type `dpf::bit_array::word_type`.
/// @tparam ConcreteBitArrayT concrete bit array type
/// @tparam WordT word used to pack bits
template <typename ConcreteBitArrayT, typename WordT = psnip_uint64_t>
class bit_array_base
{
@ -143,10 +144,12 @@ class bit_array_base
~bit_array_base() = default;
/// @brief default copy assignment
/// @return `*this`
inline constexpr
bit_array_base & operator=(const bit_array_base &) = default;
/// @brief defaulted move assignment
/// @return `*this`
HEDLEY_NO_THROW
inline constexpr
bit_array_base & operator=(bit_array_base &&) noexcept = default;
@ -202,7 +205,7 @@ class bit_array_base
/// significant to most significant)
/// @note Unlike `test` and `at`, does not throw exceptions: the behavior
/// is undefined if `pos` is out of bounds
/// @returns an object of type `dpf::bit_array_base::reference`, which
/// @return an object of type `dpf::bit_array_base::reference`, which
/// allows writing to the requested bit
/// @complexity `O(1)`
HEDLEY_NO_THROW
@ -215,9 +218,9 @@ class bit_array_base
/// @details accesses the bit at position `pos`
/// @param pos the 0-based position of the bit to return (least
/// significant to most significant)
/// @return the value of the requested bit
/// @note Unlike `test` and `at`, does not throw exceptions: the behavior
/// is undefined if `pos` is out of bounds
/// @returns the value of the requested bit
/// @complexity `O(1)`
HEDLEY_NO_THROW
inline constexpr const_reference operator[](size_type pos) const noexcept
@ -235,7 +238,7 @@ class bit_array_base
/// significant to most significant)
/// @throws std::out_of_range if `pos` does not correspond to a valid
/// position within the `bit_array_base`
/// @returns an object of type `dpf::bit_array_base::reference`, which
/// @return an object of type `dpf::bit_array_base::reference`, which
/// allows writing to the requested bit
/// @complexity `O(1)`
constexpr reference at(size_type pos)
@ -249,9 +252,9 @@ class bit_array_base
/// @details accesses the bit at position `pos`
/// @param pos the 0-based position of the bit to return (least
/// significant to most significant)
/// @return the value of the requested bit
/// @throws std::out_of_range if `pos` does not correspond to a valid
/// position within the `bit_array_base`
/// @returns the value of the requested bit
/// @complexity `O(1)`
constexpr const_reference at(size_type pos) const
{
@ -264,7 +267,7 @@ class bit_array_base
/// @brief returns an iterator to the first bit
/// @{
/// @returns iterator to the first element
/// @return iterator to the first element
/// @complexity `O(1)`
HEDLEY_NO_THROW
constexpr iterator begin() noexcept
@ -273,7 +276,7 @@ class bit_array_base
if (p == nullptr) return iterator{};
return iterator{p, word_type(1)};
}
/// @returns iterator to the first element
/// @return iterator to the first element
/// @complexity `O(1)`
HEDLEY_NO_THROW
constexpr const_iterator begin() const noexcept
@ -282,7 +285,7 @@ class bit_array_base
if (p == nullptr) return const_iterator{};
return const_iterator{p, word_type(1)};
}
/// @returns iterator to the first element
/// @return iterator to the first element
/// @complexity `O(1)`
HEDLEY_NO_THROW
constexpr const_iterator cbegin() const noexcept
@ -293,7 +296,7 @@ class bit_array_base
/// @brief returns an iterator to the end (one past the last bit)
/// @{
/// @returns iterator to the element following the last element
/// @return iterator to the element following the last element
/// @complexity `O(1)`
HEDLEY_NO_THROW
constexpr iterator end() noexcept
@ -303,7 +306,7 @@ class bit_array_base
return iterator{p + (size() >> lg_bits_per_word),
static_cast<word_type>(word_type(1) << (size() % bits_per_word))};
}
/// @returns iterator to the element following the last element
/// @return iterator to the element following the last element
/// @complexity `O(1)`
HEDLEY_NO_THROW
constexpr const_iterator end() const noexcept
@ -313,7 +316,7 @@ class bit_array_base
return const_iterator{p + (size() >> lg_bits_per_word),
static_cast<word_type>(word_type(1) << (size() % bits_per_word))};
}
/// @returns iterator to the element following the last element
/// @return iterator to the element following the last element
/// @complexity `O(1)`
HEDLEY_NO_THROW
constexpr const_iterator cend() const noexcept
@ -325,7 +328,7 @@ class bit_array_base
/// @brief checks if the specified bit is set to `true`
/// @param pos the 0-based position of the bit to return (least
/// significant to most significant)
/// @returns `true` if the requested bit is set, `false` otherwise
/// @return `true` if the requested bit is set, `false` otherwise
/// @complexity `O(1)`
bool test(size_type pos) const
{
@ -357,10 +360,9 @@ class bit_array_base
}
/// @details checks if all bits in a range are set to `true`
/// @param first,last the range of elements under consideration
/// @tparam Iterator an iterator type
/// @return `true` if all of the bits in the given range are set to
/// `true`, otherwise `false`
/// @param first,last the range of elements under consideration
/// @return `true` if all of the bits in the given range are set to `true`, otherwise `false`
/// @complexity `O(last-first)`
template <typename Iterator>
HEDLEY_NO_THROW
@ -394,10 +396,9 @@ class bit_array_base
}
/// @details checks if any bits in a range are set to `true`
/// @param first,last the range of elements under consideration
/// @tparam Iterator an iterator type
/// @return `true` if any of the bits in the given range are set to
/// `true`, otherwise `false`
/// @param first,last the range of elements under consideration
/// @return `true` if any of the bits in the given range are set to `true`, otherwise `false`
/// @complexity `O(last-first)`
template <typename Iterator>
HEDLEY_NO_THROW
@ -422,10 +423,9 @@ class bit_array_base
}
/// @details checks if none bits in a range are set to `true`
/// @param first,last the range of elements under consideration
/// @tparam Iterator an iterator type
/// @return `true` if none of the bits in the given range are set to
/// `true`, otherwise `false`
/// @param first,last the range of elements under consideration
/// @return `true` if none of the bits in the given range are set to `true`, otherwise `false`
/// @complexity `O(last-first)`
template <typename Iterator>
HEDLEY_NO_THROW
@ -438,7 +438,7 @@ class bit_array_base
/// @brief returns the number of bits set to `true`
/// @{
/// @details counts the number of bits that are set to `true`
/// @returns the number of bits set to `true`
/// @return the number of bits set to `true`
/// @complexity `O(size())`
HEDLEY_NO_THROW
size_type count() const noexcept
@ -456,8 +456,8 @@ class bit_array_base
return sum;
}
/// @details counts the number of bits in a range that are set to `true`
/// @param first,last the range of elements under consideration
/// @tparam Iterator an iterator type
/// @param first,last the range of elements under consideration
/// @return the number of bits in the given range that are set to `true`
/// @complexity `O(last-first)`
template <typename Iterator>
@ -477,7 +477,7 @@ class bit_array_base
/// @brief returns the parity of all stored bits
/// @{
/// @details counts the parity of all stored bits
/// @returns the parity of all stored bits
/// @return the parity of all stored bits
/// @complexity `O(size())`
HEDLEY_NO_THROW
size_type parity() const noexcept
@ -496,8 +496,8 @@ class bit_array_base
}
/// @details counts the parity of bits in a range
/// @param first,last the range of elements under consideration
/// @tparam Iterator an iterator type
/// @param first,last the range of elements under consideration
/// @return the parity of all bits in the given range
/// @complexity `O(last-first)`
template <typename Iterator>
@ -515,7 +515,7 @@ class bit_array_base
/// @}
/// @brief returns the number of bits
/// @returns number of bits that the `bit_array_base` holds
/// @return number of bits that the `bit_array_base` holds
/// @complexity `O(1)`
HEDLEY_NO_THROW
HEDLEY_PURE
@ -633,9 +633,12 @@ class bit_array_base
/// contains `size()` characters with the first character
/// corresponding to the last `(size()-1th)` bit and the last
/// character corresponding tot he first `(0th)` bit.
/// @tparam CharT character type
/// @tparam Traits character traits
/// @tparam Allocator allocator type
/// @param zero character to use to represent `false`/`0` (default: ``CharT('0')``)
/// @param one character to use to represent `true`/`1` (default: ``CharT('1')``)
/// @returns the converted string
/// @return the converted string
/// @throws May throw `std::bad_alloc` from the `std::string` constructor.
/// @complexity `O(size())`
template <typename CharT = char,
@ -731,6 +734,9 @@ class bit_array_base
/// @brief XOR. Exact match so `bit_reference - bit_reference` is not
/// ambiguous with integer subtraction of the proxy.
/// @param lhs the left-hand operand
/// @param rhs the right-hand operand
/// @return XOR
friend constexpr dpf::bit operator-(bit_reference lhs, bit_reference rhs) noexcept
{
return static_cast<dpf::bit>(static_cast<bool>(lhs) ^ static_cast<bool>(rhs));
@ -746,7 +752,7 @@ class bit_array_base
/// @{
/// @details sets `*this` to the result of binary AND on `*this` and `b`
/// @param b the other bit
/// @returns `*this`
/// @return `*this`
/// @complexity `O(1)`
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
@ -758,7 +764,7 @@ class bit_array_base
/// @details sets `*this` to the result of binary OR on `*this` and `b`
/// @param b the other bit
/// @returns `*this`
/// @return `*this`
/// @complexity `O(1)`
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
@ -770,7 +776,7 @@ class bit_array_base
/// @details sets `*this` to the result of binary XOR on `*this` and `b`
/// @param b the other bit
/// @returns `*this`
/// @return `*this`
/// @complexity `O(1)`
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
@ -780,8 +786,8 @@ class bit_array_base
return *this;
}
/// @details returns a temporary copy of `*this` with its value
/// flipped (binary NOT)
/// @details returns a temporary copy of `*this` with its value flipped (binary NOT)
/// @return the flipped bit
/// @complexity `O(1)`
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
@ -792,7 +798,7 @@ class bit_array_base
/// @}
/// @brief sets to the referenced bit to 1
/// @returns `*this`
/// @return `*this`
/// @complexity `O(1)`
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
@ -805,7 +811,7 @@ class bit_array_base
}
/// @brief unsets the referenced bit to 0
/// @returns `*this`
/// @return `*this`
/// @complexity `O(1)`
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
@ -818,7 +824,8 @@ class bit_array_base
}
/// @brief assigns `b ? 1 : 0` to the referenced bit
/// @returns `*this`
/// @param b the `b`
/// @return `*this`
/// @complexity `O(1)`
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
@ -832,7 +839,7 @@ class bit_array_base
}
/// @brief flips the referenced bit
/// @returns `*this`
/// @return `*this`
/// @complexity `O(1)`
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
@ -846,6 +853,8 @@ class bit_array_base
/// @brief Exchange the bits named by two proxies, including temporaries
/// returned from `operator[]` and `operator*`.
/// @param a the `a`
/// @param b the `b`
HEDLEY_NO_THROW
friend constexpr void swap(bit_reference a, bit_reference b) noexcept
{
@ -897,6 +906,8 @@ class bit_array_base
static constexpr word_type sentinel = ~word_type(0);
/// @brief Low `n` bits set. `n == 0` yields 0. `n >= bits_per_word` yields all ones.
/// @param n the `n`
/// @return Low `n` bits set
HEDLEY_NO_THROW
static constexpr word_type low_bits_mask(size_type n) noexcept
{
@ -913,6 +924,8 @@ class bit_array_base
}
/// @brief Bits strictly below the single set bit in `mask`.
/// @param mask the bit mask
/// @return Bits strictly below the single set bit in `mask`
HEDLEY_NO_THROW
static constexpr word_type bits_below(word_type mask) noexcept
{
@ -920,6 +933,8 @@ class bit_array_base
}
/// @brief Bits at and above the single set bit in `mask`.
/// @param mask the bit mask
/// @return Bits at and above the single set bit in `mask`
HEDLEY_NO_THROW
static constexpr word_type bits_at_and_above(word_type mask) noexcept
{
@ -929,6 +944,11 @@ class bit_array_base
/// @brief Invoke `fn(masked_bits, relevant_mask)` for each limb touched by
/// `[first, last)`. Does not dereference a one-past-the-end word.
/// `fn` returns false to stop early.
/// @tparam Iterator iterator type
/// @tparam Fn fn
/// @param first the first element of the range
/// @param last the past-the-end element of the range
/// @param fn the `fn`
template <typename Iterator, typename Fn>
void for_each_span(Iterator first, Iterator last, Fn fn) const
{
@ -975,6 +995,8 @@ class bit_array_base
/// @brief a base class provided to simplify the definition of
/// `bit_iterator` and `const_bit_iterator`
/// @tparam ConcreteBitArrayT concrete bit array type
/// @tparam WordT word used to pack bits
template <typename ConcreteBitArrayT,
typename WordT>
class bit_iterator_base
@ -1461,6 +1483,7 @@ class alignas(utils::max_align_v) static_bit_array final
}
/// @brief constructs a `static_bit_array` from the low bits of `val`
/// @param val the `val`
inline constexpr explicit static_bit_array(std::size_t val)
: data_{}
{
@ -1503,7 +1526,7 @@ class alignas(utils::max_align_v) static_bit_array final
}
/// @brief returns the number of bits
/// @returns number of bits that the `static_bit_array` holds
/// @return number of bits that the `static_bit_array` holds
/// @complexity `O(1)`
HEDLEY_NO_THROW
HEDLEY_PURE
@ -1534,6 +1557,8 @@ class dynamic_bit_array
using unique_ptr = typename allocator::unique_ptr;
public:
/// @brief constructs a zeroed `dynamic_bit_array` that holds `nbits` bits
/// @param nbits the width in bits
/// @param alloc the `alloc`
/// @throws std::bad_alloc if allocating storage fails
inline explicit dynamic_bit_array(std::size_t nbits,
allocator alloc = allocator{})
@ -1605,6 +1630,7 @@ class dynamic_bit_array
}
/// @brief direct access to the underlying data array
/// @param i the `i`
/// @return a pointer to the start of the data array
HEDLEY_ALWAYS_INLINE
HEDLEY_NO_THROW
@ -1625,6 +1651,7 @@ class dynamic_bit_array
}
/// @brief direct access to the underlying data array
/// @param i the `i`
/// @return a pointer to the start of the data array
HEDLEY_ALWAYS_INLINE
HEDLEY_NO_THROW
@ -1643,7 +1670,7 @@ class dynamic_bit_array
}
/// @brief returns the number of bits
/// @returns number of bits that the `dynamic_bit_array` holds
/// @return number of bits that the `dynamic_bit_array` holds
/// @complexity `O(1)`
HEDLEY_NO_THROW
HEDLEY_PURE
@ -1654,7 +1681,7 @@ class dynamic_bit_array
}
private:
/// Store zeros through `volatile` so the wipe is not deleted as a dead store.
/// @brief Store zeros through `volatile` so the wipe is not deleted as a dead store.
HEDLEY_NO_THROW
void wipe() noexcept
{
@ -1671,7 +1698,10 @@ class dynamic_bit_array
unique_ptr data_;
};
/// @brief
/// @brief Exchanges the bits named by two `dynamic_bit_array` proxies.
/// @tparam WordT word used to pack bits
/// @param lhs the left-hand operand
/// @param rhs the right-hand operand
template <typename WordT>
HEDLEY_NO_THROW
inline constexpr void swap(typename dynamic_bit_array<WordT>::reference lhs,
@ -1682,6 +1712,11 @@ inline constexpr void swap(typename dynamic_bit_array<WordT>::reference lhs,
rhs = tmp;
}
/// @brief Exchanges the bits named by two `static_bit_array` proxies.
/// @tparam Nbits width in bits
/// @tparam WordT word used to pack bits
/// @param lhs the left-hand operand
/// @param rhs the right-hand operand
template <std::size_t Nbits,
typename WordT>
HEDLEY_NO_THROW