SatCat5
utils.h
Go to the documentation of this file.
1 // Copyright 2021-2025 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
11 
12 #pragma once
13 
14 #include <cstring>
15 #include <satcat5/types.h>
16 
17 namespace satcat5 {
18  namespace util {
21  inline void set_mask_u8(volatile u8& val, u8 mask) {val |= mask;}
22  inline void clr_mask_u8(volatile u8& val, u8 mask) {val &= ~mask;}
23  inline void set_mask_u8(u8& val, u8 mask) {val |= mask;}
24  inline void clr_mask_u8(u8& val, u8 mask) {val &= ~mask;}
25  inline void set_mask_u16(u16& val, u16 mask) {val |= mask;}
26  inline void clr_mask_u16(u16& val, u16 mask) {val &= ~mask;}
27  inline void set_mask_u32(u32& val, u32 mask) {val |= mask;}
28  inline void clr_mask_u32(u32& val, u32 mask) {val &= ~mask;}
29  template<typename T>
30  inline void clr_mask(T& val, T mask) {val &= ~mask;}
31  template<typename T>
32  inline void set_mask(T& val, T mask) {val |= mask;}
34 
36  template<typename T>
37  inline void set_mask_if(T& val, T mask, bool b) {
38  if (b) set_mask<T>(val, mask);
39  else clr_mask<T>(val, mask);
40  }
41 
43  template <typename T> inline constexpr T mask_lower(unsigned n) {
44  return ((n >= 8*sizeof(T)) ? 0 : (T(1) << n)) - 1;
45  }
46 
52  template <typename T>
53  struct optional {
55  constexpr optional() : val_(), has_val_(false) {}
57  constexpr optional(const T& t) : val_(t), has_val_(true) {} // NOLINT
59  inline void reset() { has_val_ = false; }
61  inline optional& operator=(const T& t)
62  { val_ = t; has_val_ = true; return *this; }
64  inline T value() const { return val_; }
66  inline T value_or(const T& t) const { return has_val_ ? val_ : t; }
68  inline bool has_value() const { return has_val_; }
70  inline explicit operator bool() const { return has_val_; }
71  private:
72  T val_; bool has_val_;
73  };
74 
76  template <typename T>
77  inline T poll_counter(T& ct, bool reset = true) {
78  T tmp = ct;
79  if (reset) ct = 0;
80  return tmp;
81  }
82 
84  template<typename T>
85  bool countdown(T& timer, const T& decr) {
86  if (timer > decr) {
87  timer -= decr;
88  return false; // Continue countdown...
89  } else if (timer) {
90  timer = 0;
91  return true; // Countdown reached zero!
92  } else {
93  return false; // Timer idle.
94  }
95  }
96 
99  inline constexpr u8 min_u8(u8 a, u8 b)
100  {return (a < b) ? a : b;}
101  inline constexpr u16 min_u16(u16 a, u16 b)
102  {return (a < b) ? a : b;}
103  inline constexpr u32 min_u32(u32 a, u32 b)
104  {return (a < b) ? a : b;}
105  inline constexpr u64 min_u64(u64 a, u64 b)
106  {return (a < b) ? a : b;}
107  inline constexpr u32 min_s32(s32 a, s32 b)
108  {return (a < b) ? a : b;}
109  inline constexpr u64 min_s64(s64 a, s64 b)
110  {return (a < b) ? a : b;}
111  inline constexpr unsigned min_unsigned(unsigned a, unsigned b)
112  {return (a < b) ? a : b;}
113 
114  inline constexpr u8 max_u8(u8 a, u8 b)
115  {return (a > b) ? a : b;}
116  inline constexpr u16 max_u16(u16 a, u16 b)
117  {return (a > b) ? a : b;}
118  inline constexpr u32 max_u32(u32 a, u32 b)
119  {return (a > b) ? a : b;}
120  inline constexpr u64 max_u64(u64 a, u64 b)
121  {return (a > b) ? a : b;}
122  inline constexpr u32 max_s32(s32 a, s32 b)
123  {return (a > b) ? a : b;}
124  inline constexpr u64 max_s64(s64 a, s64 b)
125  {return (a > b) ? a : b;}
126  inline constexpr unsigned max_unsigned(unsigned a, unsigned b)
127  {return (a > b) ? a : b;}
129 
131  u32 max_u32(u32 a, u32 b, u32 c);
132 
136  template <typename T> inline constexpr T clamp(T x, T y) {
137  return (x < -y) ? -y : (x > y ? y : x);
138  }
139 
142  inline constexpr u8 abs_s8(s8 a)
143  {return (u8)((a < 0) ? -a : +a);}
144  inline constexpr u16 abs_s16(s16 a)
145  {return (u16)((a < 0) ? -a : +a);}
146  inline constexpr u32 abs_s32(s32 a)
147  {return (u32)((a < 0) ? -a : +a);}
148  inline constexpr u64 abs_s64(s64 a)
149  {return (u64)((a < 0) ? -a : +a);}
151 
153  template <typename T> inline constexpr T sign(T x) {
154  return T((x < 0) ? -1 : (x > 0 ? 1 : 0));
155  }
156 
159  inline u32 square_u16(u16 x) {
160  u32 xx = x;
161  return (xx * xx);
162  }
163  inline u32 square_s16(s16 x) {
164  u32 xx = (x < 0) ? -x : +x;
165  return (xx * xx);
166  }
168 
173  inline constexpr u16 modulo_add_u16(u16 sum, u16 m) {
174  return (sum >= m) ? (sum - m) : sum;
175  }
176  inline constexpr u32 modulo_add_u32(u32 sum, u32 m) {
177  return (sum >= m) ? (sum - m) : sum;
178  }
179  inline constexpr u32 modulo_add_u64(u64 sum, u64 m) {
180  return (sum >= m) ? (sum - m) : sum;
181  }
182  inline constexpr unsigned modulo_add_uns(unsigned sum, unsigned m) {
183  return (sum >= m) ? (sum - m) : sum;
184  }
186 
200  template <typename T> inline constexpr T divide(T a, T b) {
201  return (a % b < 0) ? (a / b - 1) : (a / b);
202  }
203  template <typename T> inline constexpr T modulo(T a, T b) {
204  return (a % b < 0) ? (a % b + b) : (a % b);
205  }
207 
209  template <typename T> unsigned log2_ceil(T x) {
210  unsigned count = 0;
211  while (x > 1) { ++count; x = (x+1)/2; }
212  return count;
213  }
214 
216  template <typename T> unsigned log2_floor(T x) {
217  unsigned count = 0;
218  while (x > 1) { ++count; x /= 2; }
219  return count;
220  }
221 
226  template <typename T> inline constexpr s64 round_s64(T x) {
227  return static_cast<s64>(x + (T)(x < 0 ? -0.5 : 0.5));
228  }
229  template <typename T> inline constexpr u64 round_u64(T x) {
230  return static_cast<u64>(x + (T)0.5);
231  }
233 
236  template <typename T> inline constexpr u64 round_s64z(T x) {
237  return (T(INT64_MIN) < x && x < T(INT64_MAX)) ? satcat5::util::round_s64(x) : 0;
238  }
239  template <typename T> inline constexpr u64 round_u64z(T x) {
240  return (x < T(UINT64_MAX)) ? satcat5::util::round_u64(x) : 0;
241  }
243 
249  template <typename T>
250  inline constexpr T saturate_add(T a, T b, T c = T(-1)) {
251  return (a + b < c && a + b >= a) ? (a + b) : (c);
252  }
253 
255  constexpr double pow2d(unsigned n) {
256  return (n < 64) ? (double(1ull << n)) : (double(1ull << 63) * pow2d(n-63));
257  }
258 
261  template <typename T> inline constexpr T div_floor(T a, T b)
262  {return divide<T>(a, b);}
263  template <typename T> inline constexpr T div_round(T a, T b)
264  {return divide<T>(a + b/2, b);}
265  template <typename T> inline constexpr T div_ceil(T a, T b)
266  {return divide<T>(a + b-1, b);}
267 
268  inline constexpr u32 div_floor_u32(u32 a, u32 b)
269  {return div_floor<u32>(a, b);}
270  inline constexpr s32 div_floor_s32(s32 a, s32 b)
271  {return div_floor<s32>(a, b);};
272  inline constexpr u32 div_round_u32(u32 a, u32 b)
273  {return div_round<u32>(a, b);};
274  inline constexpr s32 div_round_s32(s32 a, s32 b)
275  {return div_round<s32>(a, b);};
276  inline constexpr u32 div_ceil_u32 (u32 a, u32 b)
277  {return div_ceil<u32>(a, b);};
278  inline constexpr s32 div_ceil_s32 (s32 a, s32 b)
279  {return div_ceil<s32>(a, b);};
281 
283  bool is_multiple_u32(u32 a, u32 b);
284 
286  unsigned popcount(u32 x);
287 
290  inline constexpr u64 reverse_bytes_u64(u64 num) {
291  return ((num & 0xFF00000000000000ull) >> 56)
292  | ((num & 0x00FF000000000000ull) >> 40)
293  | ((num & 0x0000FF0000000000ull) >> 24)
294  | ((num & 0x000000FF00000000ull) >> 8)
295  | ((num & 0x00000000FF000000ull) << 8)
296  | ((num & 0x0000000000FF0000ull) << 24)
297  | ((num & 0x000000000000FF00ull) << 40)
298  | ((num & 0x00000000000000FFull) << 56);
299  }
300 
301  inline constexpr u32 reverse_bytes_u32(u32 num) {
302  return ((num & 0xFF000000u) >> 24)
303  | ((num & 0x00FF0000u) >> 8)
304  | ((num & 0x0000FF00u) << 8)
305  | ((num & 0x000000FFu) << 24);
306  }
307 
308  inline constexpr u16 reverse_bytes_u16(u16 num) {
309  return ((num & 0xFF00u) >> 8) | ((num & 0x00FFu) << 8);
310  }
312 
315  bool xor_reduce_u8(u8 x);
316  bool xor_reduce_u16(u16 x);
317  bool xor_reduce_u32(u32 x);
318  bool xor_reduce_u64(u64 x);
320 
322  unsigned min_2n(u32 x, u32 y);
323 
326  u32 sqrt_u64(u64 x);
327  u16 sqrt_u32(u32 x);
328  u8 sqrt_u16(u16 x);
330 
333  u16 extract_be_u16(const u8* src);
334  u32 extract_be_u32(const u8* src);
335  u64 extract_be_u64(const u8* src);
337 
340  void write_be_u16(u8* dst, u16 val);
341  void write_be_u32(u8* dst, u32 val);
342  void write_be_u64(u8* dst, u64 val);
344 
347  template <typename T> void swap_ptr(T* x, T* y) {
348  if (x != y) {T z = *x; *x = *y; *y = z;}
349  }
350  template <typename T> void swap_ref(T& x, T& y) {
351  if (x != y) {T z = x; x = y; y = z;}
352  }
354 
357  template <typename T> void sort(T* begin, T* end) {
358  // Using selection-sort for simplicity, O(N^2).
359  for (T* a = begin ; a+1 != end ; ++a) {
360  T* min_ptr = a;
361  for (T* b = a+1 ; b != end ; ++b) {
362  if (*b < *min_ptr) min_ptr = b;
363  }
364  satcat5::util::swap_ptr(a, min_ptr);
365  }
366  }
367 
370  class Prng final {
371  public:
373  explicit constexpr Prng(u64 seed = 123456789ull)
374  : m_state(seed) {}
375  u32 next();
376  u32 next(u32 mn, u32 mx);
378  inline void seed(u64 seed) {m_state = seed;}
379  protected:
380  u64 m_state;
381  };
382 
384  extern satcat5::util::Prng prng;
385 
389  class RunningMax {
390  public:
391  RunningMax();
392 
394  void clear();
395 
397  void update(const char* lbl, u32 value);
398 
399  // Parameters for the current record-holder.
400  const char* m_label;
401  u32 m_maximum;
402  };
403 
408  enum {SATCAT5_LITTLE_ENDIAN = 0x03020100ul, SATCAT5_BIG_ENDIAN = 0x00010203ul};
409  constexpr union {u8 bytes[4]; u32 value;} HOST_ORDER_CANARY = {{0,1,2,3}};
410  inline constexpr u32 HOST_BYTE_ORDER() {return HOST_ORDER_CANARY.value;}
412 
414  template<typename T1, typename T2> inline T2 reinterpret(T1 x) {
415  static_assert(sizeof(T1) == sizeof(T2), "Type size mismatch");
416  // Note: Using "memcpy" for type-punning is preferred safe-ish method.
417  // Most compilers will optimize this to a no-op, as desired. See also:
418  // https://gist.github.com/shafik/848ae25ee209f698763cffee272a58f8
419  // https://stackoverflow.com/questions/48803363/
420  T2 y;
421  std::memcpy(&y, &x, sizeof(T1));
422  return y;
423  }
424  }
425 }
Simple cross-platform psuedorandom number generator (PRNG).
Definition: utils.h:370
void seed(u64 seed)
Reset to the provided PRNG state.
Definition: utils.h:378
constexpr Prng(u64 seed=123456789ull)
Constructor sets initial PRNG state.
Definition: utils.h:373
u32 next()
Range [0..2^32)
Definition: utils.cc:194
Running maximum with label tracking.
Definition: utils.h:389
void clear()
Reset recorded maximum to zero.
Definition: utils.cc:217
void update(const char *lbl, u32 value)
Update stats if new value exceeds previous record.
Definition: utils.cc:222
u32 m_maximum
Maximum observed value.
Definition: utils.h:401
const char * m_label
Human-readable label.
Definition: utils.h:400
An optional field that may be filled or empty.
Definition: utils.h:53
void reset()
Reset to the empty state.
Definition: utils.h:59
bool has_value() const
Is this optional field present?
Definition: utils.h:68
constexpr optional(const T &t)
Create a filled value.
Definition: utils.h:57
T value() const
Fetch the inner value.
Definition: utils.h:64
optional & operator=(const T &t)
Assign a filled value.
Definition: utils.h:61
constexpr optional()
Create an empty value.
Definition: utils.h:55
T value_or(const T &t) const
Fetch the inner value if present, or the specified default.
Definition: utils.h:66
Basic type aliases and prototypes used throughout SatCat5.
constexpr s32 div_ceil_s32(s32 a, s32 b)
Integer division functions with various rounding options:
Definition: utils.h:278
constexpr unsigned min_unsigned(unsigned a, unsigned b)
Min and max functions.
Definition: utils.h:111
constexpr s32 div_round_s32(s32 a, s32 b)
Integer division functions with various rounding options:
Definition: utils.h:274
void set_mask_u32(u32 &val, u32 mask)
Set or clear bit masks.
Definition: utils.h:27
u32 square_u16(u16 x)
Square an input (and double output width)
Definition: utils.h:159
constexpr unsigned modulo_add_uns(unsigned sum, unsigned m)
Modulo addition function.
Definition: utils.h:182
void clr_mask(T &val, T mask)
Set or clear bit masks.
Definition: utils.h:30
constexpr T modulo(T a, T b)
Portability wrapper for platforms with signed division and modulo:
Definition: utils.h:203
void clr_mask_u16(u16 &val, u16 mask)
Set or clear bit masks.
Definition: utils.h:26
constexpr double pow2d(unsigned n)
Calculate 2^N for very large N, returning a double.
Definition: utils.h:255
constexpr u32 max_s32(s32 a, s32 b)
Min and max functions.
Definition: utils.h:122
void swap_ref(T &x, T &y)
Swap two values using a temporary variable.
Definition: utils.h:350
constexpr u32 HOST_BYTE_ORDER()
Cross-platform determination of native byte-order.
Definition: utils.h:410
constexpr u64 round_s64z(T x)
Variant of "round_u64" that returns zero if input is out of range.
Definition: utils.h:236
constexpr u64 max_s64(s64 a, s64 b)
Min and max functions.
Definition: utils.h:124
constexpr u8 min_u8(u8 a, u8 b)
Min and max functions.
Definition: utils.h:99
constexpr u32 modulo_add_u64(u64 sum, u64 m)
Modulo addition function.
Definition: utils.h:179
constexpr u8 max_u8(u8 a, u8 b)
Min and max functions.
Definition: utils.h:114
T2 reinterpret(T1 x)
In-place byte-for-byte format conversion, aka "type-punning".
Definition: utils.h:414
constexpr u64 round_u64z(T x)
Variant of "round_u64" that returns zero if input is out of range.
Definition: utils.h:239
constexpr u32 div_round_u32(u32 a, u32 b)
Integer division functions with various rounding options:
Definition: utils.h:272
constexpr u64 round_u64(T x)
Round a floating-point value to the nearest integer.
Definition: utils.h:229
u32 square_s16(s16 x)
Square an input (and double output width)
Definition: utils.h:163
constexpr u16 modulo_add_u16(u16 sum, u16 m)
Modulo addition function.
Definition: utils.h:173
constexpr u16 reverse_bytes_u16(u16 num)
Reverse the order of bytes in an integer.
Definition: utils.h:308
void clr_mask_u8(volatile u8 &val, u8 mask)
Set or clear bit masks.
Definition: utils.h:22
constexpr s32 div_floor_s32(s32 a, s32 b)
Integer division functions with various rounding options:
Definition: utils.h:270
void set_mask_if(T &val, T mask, bool b)
Call set_mask or clr_mask depending on the third argument.
Definition: utils.h:37
constexpr u64 abs_s64(s64 a)
Absolute value.
Definition: utils.h:148
void set_mask_u8(volatile u8 &val, u8 mask)
Set or clear bit masks.
Definition: utils.h:21
void clr_mask_u32(u32 &val, u32 mask)
Set or clear bit masks.
Definition: utils.h:28
constexpr T clamp(T x, T y)
Template "clamp" function.
Definition: utils.h:136
constexpr u32 min_u32(u32 a, u32 b)
Min and max functions.
Definition: utils.h:103
constexpr u32 reverse_bytes_u32(u32 num)
Reverse the order of bytes in an integer.
Definition: utils.h:301
void swap_ptr(T *x, T *y)
Swap two values using a temporary variable.
Definition: utils.h:347
constexpr T sign(T x)
Sign function (-x/0/+x -> -1/0/+1)
Definition: utils.h:153
constexpr u32 abs_s32(s32 a)
Absolute value.
Definition: utils.h:146
unsigned log2_ceil(T x)
Calculate log2(x), rounding up.
Definition: utils.h:209
bool countdown(T &timer, const T &decr)
Decrement a countdown timer, returning true if it reaches zero.
Definition: utils.h:85
constexpr u32 modulo_add_u32(u32 sum, u32 m)
Modulo addition function.
Definition: utils.h:176
constexpr T saturate_add(T a, T b, T c=T(-1))
Unsigned add with saturation: min(A + B, C).
Definition: utils.h:250
constexpr u32 max_u32(u32 a, u32 b)
Min and max functions.
Definition: utils.h:118
void set_mask(T &val, T mask)
Set or clear bit masks.
Definition: utils.h:32
constexpr u64 min_u64(u64 a, u64 b)
Min and max functions.
Definition: utils.h:105
constexpr unsigned max_unsigned(unsigned a, unsigned b)
Min and max functions.
Definition: utils.h:126
constexpr u16 min_u16(u16 a, u16 b)
Min and max functions.
Definition: utils.h:101
constexpr T div_ceil(T a, T b)
Integer division functions with various rounding options:
Definition: utils.h:265
constexpr u64 max_u64(u64 a, u64 b)
Min and max functions.
Definition: utils.h:120
constexpr union satcat5::util::@1 HOST_ORDER_CANARY
Cross-platform determination of native byte-order.
constexpr T mask_lower(unsigned n)
Return a bit-mask where the N LSBs are set.
Definition: utils.h:43
constexpr u64 reverse_bytes_u64(u64 num)
Reverse the order of bytes in an integer.
Definition: utils.h:290
constexpr u8 abs_s8(s8 a)
Absolute value.
Definition: utils.h:142
constexpr T divide(T a, T b)
Portability wrapper for platforms with signed division and modulo:
Definition: utils.h:200
constexpr u32 div_floor_u32(u32 a, u32 b)
Integer division functions with various rounding options:
Definition: utils.h:268
constexpr s64 round_s64(T x)
Round a floating-point value to the nearest integer.
Definition: utils.h:226
void sort(T *begin, T *end)
Templated in-place stable sort for small arrays.
Definition: utils.h:357
constexpr u64 min_s64(s64 a, s64 b)
Min and max functions.
Definition: utils.h:109
constexpr u16 max_u16(u16 a, u16 b)
Min and max functions.
Definition: utils.h:116
constexpr T div_floor(T a, T b)
Integer division functions with various rounding options:
Definition: utils.h:261
T poll_counter(T &ct, bool reset=true)
Poll a cumulative counter, optionally resetting it to zero.
Definition: utils.h:77
constexpr u32 div_ceil_u32(u32 a, u32 b)
Integer division functions with various rounding options:
Definition: utils.h:276
void set_mask_u16(u16 &val, u16 mask)
Set or clear bit masks.
Definition: utils.h:25
unsigned log2_floor(T x)
Calculate log2(x), rounding down.
Definition: utils.h:216
constexpr u16 abs_s16(s16 a)
Absolute value.
Definition: utils.h:144
constexpr u32 min_s32(s32 a, s32 b)
Min and max functions.
Definition: utils.h:107