16#ifndef JAU_CT_UTILS_HPP_
17#define JAU_CT_UTILS_HPP_
22#if defined(JAU_HAS_VALGRIND)
23 #include <valgrind/memcheck.h>
46inline void poison([[maybe_unused]]
const T* p, [[maybe_unused]]
size_t n)
48#if defined(JAU_HAS_VALGRIND)
49 VALGRIND_MAKE_MEM_UNDEFINED(p, n *
sizeof(T));
54inline void unpoison([[maybe_unused]]
const T* p, [[maybe_unused]]
size_t n)
56#if defined(JAU_HAS_VALGRIND)
57 VALGRIND_MAKE_MEM_DEFINED(p, n *
sizeof(T));
64#if defined(JAU_HAS_VALGRIND)
65 VALGRIND_MAKE_MEM_DEFINED(&p,
sizeof(T));
79 std::enable_if_t< std::is_integral_v<T> && std::is_unsigned_v<T>,
bool> =
true>
84 : m_mask(other.m_mask) { }
87 m_mask = other.m_mask;
97 static_assert(
sizeof(U) >
sizeof(T),
"sizes ok");
105 return Mask<T>(
static_cast<T
>(~0));
130 static_assert(
sizeof(U) <
sizeof(T),
"sizes ok");
139 return Mask<T>(ct_is_zero<T>(x));
155 return Mask<T>(ct_expand_top_bit<T>(x^((x^y) | ((x-y)^x))));
186 const T v_lt_l = v^((v^l) | ((v-l)^v));
187 const T v_gt_u = u^((u^v) | ((u-v)^u));
188 const T either = v_lt_l | v_gt_u;
196 for(
auto a: accepted)
198 const T diff = a ^ v;
199 const T eq_zero = ~diff & (diff - 1);
238 return Mask<T>(x.value() & y.value());
246 return Mask<T>(x.value() ^ y.value());
254 return Mask<T>(x.value() | y.value());
308 void select_n(T output[],
const T x[],
const T y[],
size_t len)
const noexcept
310 for(
size_t i = 0; i != len; ++i)
311 output[i] = this->
select(x[i], y[i]);
319 for(
size_t i = 0; i != elems; ++i)
352 Mask(T m) noexcept : m_mask(m) {}
362 size_t elems)
noexcept
365 mask.select_n(to, from0, from1, elems);
374 T t0 =
swap.select(y, x);
375 T t1 =
swap.select(x, y);
383 uintptr_t xp =
reinterpret_cast<uintptr_t
>(x);
384 uintptr_t yp =
reinterpret_cast<uintptr_t
>(y);
386 conditional_swap<uintptr_t>(cnd, xp, yp);
388 x =
reinterpret_cast<T
>(xp);
389 y =
reinterpret_cast<T
>(yp);
A Mask type used for constant-time operations.
Mask< T > & operator^=(Mask< T > o) noexcept
XOR-combine two masks.
Mask(Mask< U > o) noexcept
Derive a Mask from a Mask of a larger type.
Mask< T > operator~() const noexcept
Negate this mask.
Mask< T > & operator&=(Mask< T > o) noexcept
AND-combine two masks.
static Mask< T > is_gte(T x, T y) noexcept
Return a Mask<T> which is set if x >= y.
T unpoisoned_value() const noexcept
Return the value of the mask, unpoisoned.
void select_n(T output[], const T x[], const T y[], size_t len) const noexcept
Conditionally set output to x or y, depending on if mask is set or cleared (resp)
static Mask< T > set() noexcept
Return a Mask<T> with all bits set.
static Mask< T > cleared() noexcept
Return a Mask<T> with all bits cleared.
static Mask< T > is_gt(T x, T y) noexcept
Return a Mask<T> which is set if x > y.
T select(T x, T y) const noexcept
If this mask is set, return x, otherwise return y.
static Mask< T > is_equal(T x, T y) noexcept
Return a Mask<T> which is set if x == y.
friend Mask< T > operator&(Mask< T > x, Mask< T > y) noexcept
AND-combine two masks.
void if_set_zero_out(T buf[], size_t elems) noexcept
If this mask is set, zero out buf, otherwise do nothing.
T if_not_set_return(T x) const noexcept
Return x if the mask is cleared, or otherwise zero.
bool is_set() const noexcept
Return true iff this mask is set.
static Mask< T > expand(T v) noexcept
Return a Mask<T> which is set if v is != 0.
static Mask< T > is_lte(T x, T y) noexcept
Return a Mask<T> which is set if x <= y.
T value() const noexcept
Return the underlying value of the mask.
Mask< T > & operator=(const Mask< T > &other) noexcept
Mask< T > select_mask(Mask< T > x, Mask< T > y) const noexcept
If this mask is set, return x, otherwise return y.
static Mask< T > is_within_range(T v, T l, T u) noexcept
T if_set_return(T x) const noexcept
Return x if the mask is set, or otherwise zero.
Mask< T > & operator|=(Mask< T > o) noexcept
OR-combine two masks.
Mask(const Mask< T > &other) noexcept
static Mask< T > is_zero(T x) noexcept
Return a Mask<T> which is set if v is == 0 or cleared otherwise.
static Mask< T > is_any_of(T v, std::initializer_list< T > accepted) noexcept
T select_and_unpoison(T x, T y) const noexcept
static Mask< T > expand(Mask< U > m) noexcept
Return a Mask<T> which is set if m is set.
friend Mask< T > operator^(Mask< T > x, Mask< T > y) noexcept
XOR-combine two masks.
friend Mask< T > operator|(Mask< T > x, Mask< T > y) noexcept
OR-combine two masks.
static Mask< T > is_lt(T x, T y) noexcept
Return a Mask<T> which is set if x < y.
constexpr T ct_expand_top_bit(T x)
Returns ~0 (2-complement) if top bit of arg is set, otherwise 0 (w/o branching) in O(1) and constant ...
constexpr T ct_masked_merge(T mask, T a_if_masked, T b_if_unmasked)
Returns merged a_if_masked bits selected by mask 1 bits and b_if_unmasked bits selected by mask 0 bit...
void swap(cow_darray< Value_type, Size_type, Alloc_type > &rhs, cow_darray< Value_type, Size_type, Alloc_type > &lhs) noexcept
Functions for constant time operations on data and testing of constant time annotations using valgrin...
void poison(const T *p, size_t n)
Use valgrind to mark the contents of memory as being undefined.
void unpoison(const T *p, size_t n)
void conditional_swap(bool cnd, T &x, T &y) noexcept
Mask< T > conditional_copy_mem(T cnd, T *to, const T *from0, const T *from1, size_t elems) noexcept
void conditional_swap_ptr(bool cnd, T &x, T &y) noexcept