libhatchet
Loading...
Searching...
No Matches
hxutility.h
Go to the documentation of this file.
1#pragma once
2// SPDX-FileCopyrightText: © 2017-2026 Adrian Johnston.
3// SPDX-License-Identifier: MIT
4// This file is licensed under the MIT license found in the LICENSE.md file.
5
8
9#include "libhatchet.h"
10
11// HX_USE_MACROS_WITH_MODULE allows including macros alongside the module.
12#if HX_USE_MACROS_WITH_MODULE
13#error Header does not provide macros alone.
14#endif
15
16HX_C_BEGIN_
17
18// -- C Utilities --------------------------------------------------------------
19
23void hxfloat_view(const float* address_, size_t size_) hxattr_nonnull(1) hxattr_cold;
24
30void hxhex_view(const void* address_, size_t bytes_, bool pretty_) hxattr_nonnull(1) hxattr_cold;
31
32HX_C_END_
33#if HX_CPLUSPLUS
34HX_NS_BEGIN_
35
36// -- C and C++ Utilities ------------------------------------------------------
37
40template<typename T_, hxsize_t N_> hxattr_nodiscard constexpr
41hxsize_t hxsize(T_ (&)[N_]) { return N_; }
42
43// -- C++ SFINAE ---------------------------------------------------------------
44// Substitution Failure Is Not An Error. enable_if checks.
45
47template<bool condition_, typename type_=void> struct hxenable_if_ { };
48template<typename type_> struct hxenable_if_<true, type_> { using type = type_; };
49template<bool condition_, typename type_=void>
50using hxenable_if_t = typename hxenable_if_<condition_, type_>::type;
52
57class hxnil_t {
58public:
60 template<typename T_> hxinline constexpr operator T_*() const { return 0; }
62 template<typename T_, typename M_> hxinline constexpr operator M_ T_::*() const { return 0; }
63};
64
68
70template<typename T_> struct hxremove_cv_ { using type = T_; };
71template<typename T_> struct hxremove_cv_<const T_> { using type = T_; };
72template<typename T_> struct hxremove_cv_<volatile T_> { using type = T_; };
73template<typename T_> struct hxremove_cv_<const volatile T_> { using type = T_; };
75
79template<typename T_> using hxremove_cv_t = typename hxremove_cv_<T_>::type;
80
82template<typename T_> struct hxremove_pointer_ { using type = T_; };
83template<typename T_> struct hxremove_pointer_<T_*> { using type = T_; };
84template<typename T_> struct hxremove_pointer_<T_* const> { using type = T_; };
85template<typename T_> struct hxremove_pointer_<T_* volatile> { using type = T_; };
86template<typename T_> struct hxremove_pointer_<T_* const volatile> { using type = T_; };
88
90template<typename T_> using hxremove_pointer_t = typename hxremove_pointer_<T_>::type;
91
93template<typename T_> struct hxremove_reference_ { using type = T_; };
94template<typename T_> struct hxremove_reference_<T_&> { using type = T_; };
95template<typename T_> struct hxremove_reference_<T_&&> { using type = T_; };
97
99template<typename T_> using hxremove_reference_t = typename hxremove_reference_<T_>::type;
100
104
107template<typename T_> T_&& hxdeclval(void) noexcept;
108
110struct hxtrue_t { constexpr static bool value = true; };
112struct hxfalse_t { constexpr static bool value = false; };
113
115template<typename T_, typename U_>
116struct hxbinds_directly_ {
117private:
118 static hxtrue_t test_(T_&);
119 static hxfalse_t test_(T_&&);
120 static hxfalse_t test_(...);
121public:
122#if defined _MSC_VER
123#pragma warning(push)
124#pragma warning(disable: 4244 4267)
125#endif
126 constexpr static bool value = decltype(test_(hxdeclval<U_&>()))::value;
127#if defined _MSC_VER
128#pragma warning(pop)
129#endif
130};
132
137template<typename T_, typename U_>
138hxattr_nodiscard constexpr bool hxbinds_directly(void) { return hxbinds_directly_<T_, U_>::value; }
139
141template<typename T_> struct hxis_array_ : public hxfalse_t { };
142template<typename T_, size_t size_> struct hxis_array_<T_[size_]> : public hxtrue_t { };
143template<typename T_> struct hxis_array_<T_[]> : public hxtrue_t { };
145
147template<typename T_>
148hxattr_nodiscard constexpr bool hxis_array(void) { return hxis_array_<T_>::value; }
149
151template<typename T_> struct hxis_const_ : public hxfalse_t { };
152template<typename T_> struct hxis_const_<const T_> : public hxtrue_t { };
154
156template<typename T_>
157hxattr_nodiscard constexpr bool hxis_const(void) { return hxis_const_<T_>::value; }
158
160template<typename T_> struct hxis_floating_point_ : public hxfalse_t { };
161template<> struct hxis_floating_point_<float> : public hxtrue_t { };
162template<> struct hxis_floating_point_<double> : public hxtrue_t { };
163template<> struct hxis_floating_point_<long double> : public hxtrue_t { };
165
167template<typename T_>
169 return hxis_floating_point_<hxremove_cv_t<T_>>::value;
170}
171
173template<typename T_> struct hxis_integral_ : public hxfalse_t { };
174template<> struct hxis_integral_<bool> : public hxtrue_t { };
175template<> struct hxis_integral_<char> : public hxtrue_t { };
176template<> struct hxis_integral_<signed char> : public hxtrue_t { };
177template<> struct hxis_integral_<unsigned char> : public hxtrue_t { };
178template<> struct hxis_integral_<wchar_t> : public hxtrue_t { };
179template<> struct hxis_integral_<char16_t> : public hxtrue_t { };
180template<> struct hxis_integral_<char32_t> : public hxtrue_t { };
181#if HX_CPLUSPLUS >= 202002L
182template<> struct hxis_integral_<char8_t> : public hxtrue_t { };
183#endif
184template<> struct hxis_integral_<short> : public hxtrue_t { };
185template<> struct hxis_integral_<unsigned short> : public hxtrue_t { };
186template<> struct hxis_integral_<int> : public hxtrue_t { };
187template<> struct hxis_integral_<unsigned int> : public hxtrue_t { };
188template<> struct hxis_integral_<long> : public hxtrue_t { };
189template<> struct hxis_integral_<unsigned long> : public hxtrue_t { };
190template<> struct hxis_integral_<long long> : public hxtrue_t { };
191template<> struct hxis_integral_<unsigned long long> : public hxtrue_t { };
193
195template<typename T_>
196hxattr_nodiscard constexpr bool hxis_integral(void) {
197 return hxis_integral_<hxremove_cv_t<T_>>::value;
198}
199
201template<typename T_> struct hxis_lvalue_reference_ : public hxfalse_t { };
202template<typename T_> struct hxis_lvalue_reference_<T_&> : public hxtrue_t { };
204
206template<typename T_>
207hxattr_nodiscard constexpr bool hxis_lvalue_reference(void) { return hxis_lvalue_reference_<T_>::value; }
208
210template<typename T_> struct hxis_pointer_ : public hxfalse_t { };
211template<typename T_> struct hxis_pointer_<T_*> : public hxtrue_t { };
213
215template<typename T_>
216hxattr_nodiscard constexpr bool hxis_pointer(void) {
217 return hxis_pointer_<hxremove_cv_t<T_>>::value;
218}
219
221template<typename T_> struct hxis_reference_ : public hxfalse_t { };
222template<typename T_> struct hxis_reference_<T_&> : public hxtrue_t { };
223template<typename T_> struct hxis_reference_<T_&&> : public hxtrue_t { };
225
227template<typename T_>
228hxattr_nodiscard constexpr bool hxis_reference(void) { return hxis_reference_<T_>::value; }
229
231template<typename T_> struct hxis_rvalue_reference_ : public hxfalse_t { };
232template<typename T_> struct hxis_rvalue_reference_<T_&&> : public hxtrue_t { };
234
236template<typename T_>
237hxattr_nodiscard constexpr bool hxis_rvalue_reference(void) { return hxis_rvalue_reference_<T_>::value; }
238
240template<typename A_, typename B_> struct hxis_same_ : public hxfalse_t { };
241template<typename A_> struct hxis_same_<A_, A_> : public hxtrue_t { };
243
245template<typename A_, typename B_>
246hxattr_nodiscard constexpr bool hxis_same(void) { return hxis_same_<A_, B_>::value; }
247
248#if HX_CPLUSPLUS >= 202002L
254template<typename from_t_, typename to_t_>
255concept hxconvertible_to = requires(from_t_ (&&from_)()) {
256 requires requires { static_cast<to_t_>(from_()); };
257};
258
264template<typename from_t_, typename to_t_>
265concept hxsame_as = hxis_same_<from_t_, to_t_>::value;
266#endif
267
269template<typename T_> struct hxis_void_ : public hxfalse_t { };
270template<> struct hxis_void_<void> : public hxtrue_t { };
272
274template<typename T_>
275hxattr_nodiscard constexpr bool hxis_void(void) {
276 return hxis_void_<hxremove_cv_t<T_>>::value;
277}
278
280template<typename T_> struct hxrestrict_t_ { using type = T_; };
281template<typename T_> struct hxrestrict_t_<T_*> { using type = T_* hxrestrict; };
282template<typename T_> struct hxrestrict_t_<T_* const> { using type = T_* const hxrestrict; };
284
287template<typename T_> using hxrestrict_t = typename hxrestrict_t_<T_>::type;
288
293hxattr_nodiscard constexpr bool hxisgraph(char ch_) {
294 return ((static_cast<unsigned char>(ch_) - 0x21u) < 0x5eu)
295 || ((static_cast<unsigned char>(ch_) & 0x80u) != 0u);
296}
297
303hxattr_nodiscard constexpr bool hxisspace(char ch_) {
304 return ch_ == ' ' || (static_cast<unsigned char>(ch_) - 0x09u) < 0x05u;
305}
306
313#if defined _MSC_VER
314 unsigned long index_ = 0ul;
315 ::_BitScanReverse(&index_, i_);
316 return static_cast<int>(index_);
317#elif defined __GNUC__ || defined __clang__
318 return 31 - __builtin_clz(i_);
319#else
320 float f_ = static_cast<float>(i_);
321 uint32_t bits_ = 0u; ::memcpy(&bits_, &f_, sizeof f_);
322 return static_cast<int>((bits_ >> 23) & 0xffu) - 127;
323#endif
324}
325
328template<typename T_>
329hxattr_nodiscard constexpr T_ hxabs(T_ x_) { return (x_ < T_()) ? (T_() - x_) : x_; }
330
336template<typename T_>
337hxattr_nodiscard constexpr T_ hxclamp(T_ x_, T_ minimum_, T_ maximum_) {
338#if HX_CPLUSPLUS >= 201402L
339 hxassertf(!(maximum_ < minimum_), "bad_span inversion");
340#endif
341 return (x_ < minimum_) ? minimum_ : ((maximum_ < x_) ? maximum_ : x_);
342}
343
352template<typename T_>
354 static_assert(!hxis_lvalue_reference<T_>(), "T must be a `T&&` reference");
355 return static_cast<T_&&>(x_);
356}
357
361template<typename T_>
363 return static_cast<T_&&>(x_);
364}
365
367template<typename value_t_>
368value_t_& hxforward_like_result_(value_t_&, hxtrue_t, hxfalse_t);
369template<typename value_t_>
370const value_t_& hxforward_like_result_(value_t_&, hxtrue_t, hxtrue_t);
371template<typename value_t_>
372value_t_&& hxforward_like_result_(value_t_&, hxfalse_t, hxfalse_t);
373template<typename value_t_>
374const value_t_&& hxforward_like_result_(value_t_&, hxfalse_t, hxtrue_t);
375
376template<typename like_t_, typename value_t_>
377using hxforward_like_t_ = decltype(hxforward_like_result_(
379 hxis_lvalue_reference_<like_t_>(),
380 hxis_const_<hxremove_reference_t<like_t_>>()));
382
386template<typename like_t_, typename value_t_>
387hxattr_nodiscard constexpr hxforward_like_t_<like_t_, value_t_> hxforward_like(value_t_& value_) {
388 return static_cast<hxforward_like_t_<like_t_, value_t_>>(value_);
389}
390
394template<typename T_>
395hxattr_nodiscard constexpr T_ hxmax(T_ x_, T_ y_) { return (y_ < x_) ? x_ : y_; }
396
400template<typename T_>
401hxattr_nodiscard constexpr T_ hxmin(T_ x_, T_ y_) { return (x_ < y_) ? x_ : y_; }
402
406template<typename T_>
407constexpr hxremove_reference_t<T_>&& hxmove(T_&& t_) {
408 return static_cast<hxremove_reference_t<T_>&&>(t_);
409}
410
413template<typename T_>
414hxconstexpr void hxswap(T_& x_, T_& y_) {
415 T_ t_(hxmove(x_));
416 x_ = hxmove(y_);
417 y_ = hxmove(t_);
418}
419
425template<typename T_>
426void hxswap_memcpy(T_& x_, T_& y_) {
427 char t_[sizeof x_];
428 ::memcpy(t_, &y_, sizeof x_); // NOLINT(bugprone-undefined-memory-manipulation)
429 ::memcpy(static_cast<void*>(&y_), &x_, sizeof x_); // NOLINT(bugprone-undefined-memory-manipulation)
430 ::memcpy(static_cast<void*>(&x_), t_, sizeof x_); // NOLINT(bugprone-undefined-memory-manipulation)
431}
432
433HX_NS_END_
434#else // !HX_CPLUSPLUS
435
436// -- C Macro Utility API - Does it all backwards in heels --------------------
437
440#define hxsize(x_) (sizeof(x_) / sizeof(x_)[0])
441
445#define hxabs(x_) ((x_) < 0 ? (0 - (x_)) : (x_))
446
452#define hxclamp(x_, minimum_, maximum_) \
453 ((x_) < (minimum_) ? (minimum_) : ((maximum_) < (x_) ? (maximum_) : (x_)))
454
459#define hxmax(x_, y_) ((y_) < (x_) ? (x_) : (y_))
460
465#define hxmin(x_, y_) ((x_) < (y_) ? (x_) : (y_))
466
472#define hxswap_memcpy(x_,y_) do { \
473 char t_[sizeof(x_) == sizeof(y_) ? (int)sizeof(x_) : -1]; \
474 memcpy(t_, &(y_), sizeof(x_)); \
475 memcpy(&(y_), &(x_), sizeof(x_)); \
476 memcpy(&(x_), t_, sizeof(x_)); } while(0)
477
478#endif // !HX_CPLUSPLUS
hxnil_t - A class that will only convert to a null T pointer or a null hxhandle_t.
Definition hxutility.h:57
hxconvertible_to - A concept that requires one type to be convertible to another.
Definition hxutility.h:255
hxsame_as - A concept that requires two types to be the same.
Definition hxutility.h:265
#define hxinline
hxinline - Force a function to be inlined into its callers.
Definition hxsettings.h:125
#define hxrestrict
hxrestrict - A pointer attribute indicating that for the lifetime of that pointer,...
Definition hxsettings.h:75
#define hxinline_constexpr
hxinline_constexpr - Enables C++17 compatable "inline constexpr" usage for variables so they can be e...
Definition hxsettings.h:275
#define hxattr_nonnull(...)
hxattr_nonnull - Indicates that a function has args that should not be null.
Definition hxsettings.h:106
#define hxattr_nodiscard
hxattr_nodiscard - Indicates the caller should not discard the return value.
Definition hxsettings.h:98
#define hxattr_cold
hxattr_cold - Optimize a function for size.
Definition hxsettings.h:86
#define hxconstexpr
hxconstexpr - Enables C++23 compatable constexpr usage for functions as that has support for destruct...
Definition hxsettings.h:266
void hxhex_view(const void *address_, size_t bytes_, bool pretty_)
hxhex_view - Prints an array of bytes formatted in hexadecimal.
constexpr bool hxisgraph(char ch_)
hxisgraph - Implements standard isgraph for a locale where all non-ASCII characters are considered gr...
Definition hxutility.h:293
constexpr bool hxis_same(void)
hxis_same<A, B> - Implements std::is_same.
Definition hxutility.h:246
typename hxremove_cv_< T >::type hxremove_cv_t
hxremove_cv_t - Removes const and volatile from a type.
Definition hxutility.h:79
typename hxrestrict_t_< T >::type hxrestrict_t
hxrestrict_t - Adds the __restrict keyword to C++ pointers.
Definition hxutility.h:287
constexpr void hxswap(T &x_, T &y_)
hxswap - Exchanges the contents of x and y using a temporary.
Definition hxutility.h:414
constexpr T && hxforward(hxremove_reference_t< T > &&x_)
hxforward - Implements std::forward.
Definition hxutility.h:353
constexpr bool hxis_rvalue_reference(void)
hxis_rvalue_reference<T> - Implements std::is_rvalue_reference.
Definition hxutility.h:237
constexpr T hxabs(T x_)
hxabs - Returns the absolute value of x using a < comparison.
Definition hxutility.h:329
void hxswap_memcpy(T &x_, T &y_)
hxswap_memcpy - Exchanges the contents of x and y using memcpy and a stack temporary.
Definition hxutility.h:426
hxremove_cv_t< hxremove_reference_t< T > > hxremove_cvref_t
hxremove_cvref_t<T> - Returns T with const, volatile, and references removed.
Definition hxutility.h:103
constexpr bool hxis_lvalue_reference(void)
hxis_lvalue_reference<T> - Implements std::is_lvalue_reference.
Definition hxutility.h:207
constexpr bool hxis_array(void)
hxis_array<T> - Implements std::is_array.
Definition hxutility.h:148
constexpr bool hxis_floating_point(void)
hxis_floating_point<T> - Implements std::is_floating_point.
Definition hxutility.h:168
constexpr T hxclamp(T x_, T minimum_, T maximum_)
hxclamp - Returns x clamped between the minimum and maximum using < comparisons.
Definition hxutility.h:337
constexpr T hxmax(T x_, T y_)
hxmax - Returns the maximum value of x and y using a < comparison.
Definition hxutility.h:395
T && hxdeclval(void) noexcept
hxdeclval - Implements std::declval.
constexpr T hxmin(T x_, T y_)
hxmin - Returns the minimum value of x and y using a < comparison.
Definition hxutility.h:401
constexpr bool hxis_reference(void)
hxis_reference<T> - Implements std::is_reference.
Definition hxutility.h:228
constexpr hxnil_t hxnil
hxnil - An instance of hxnil_t useful as a shorthand.
Definition hxutility.h:67
constexpr bool hxbinds_directly(void)
hxbinds_directly<T, U> - Returns true when an lvalue of type U binds to T& without creating a tempora...
Definition hxutility.h:138
constexpr bool hxisspace(char ch_)
hxisspace - Implements standard isspace for a locale where all non-ASCII characters are considered gr...
Definition hxutility.h:303
constexpr hxremove_reference_t< T > && hxmove(T &&t_)
hxmove - Implements std::move.
Definition hxutility.h:407
constexpr bool hxis_integral(void)
hxis_integral<T> - Implements std::is_integral.
Definition hxutility.h:196
constexpr bool hxis_pointer(void)
hxis_pointer<T> - Implements std::is_pointer.
Definition hxutility.h:216
constexpr hxforward_like_t_< like_t_, value_t_ > hxforward_like(value_t_ &value_)
hxforward_like<T> - Returns value with the constness and value category of T.
Definition hxutility.h:387
typename hxremove_reference_< T >::type hxremove_reference_t
hxremove_reference_t<T> - Returns T with references removed.
Definition hxutility.h:99
constexpr bool hxis_void(void)
hxis_void<T> - Implements std::is_void.
Definition hxutility.h:275
constexpr bool hxis_const(void)
hxis_const<T> - Implements std::is_const.
Definition hxutility.h:157
HX_C_END_ HX_NS_BEGIN_ constexpr hxsize_t hxsize(T(&)[N_])
hxsize - Returns the size of a C array.
Definition hxutility.h:41
typename hxremove_pointer_< T >::type hxremove_pointer_t
hxremove_pointer_t<T> - Returns T with one pointer level removed.
Definition hxutility.h:90
HX_C_BEGIN_ void hxfloat_view(const float *address_, size_t size_)
hxfloat_view - Prints an array of floating point values.
int hxlog2i(uint32_t i_)
hxlog2i - Returns log2(n) as an integer which is the power of 2 of the largest bit in n.
Definition hxutility.h:312
Provides core macros, memory management and feature detection.
#define hxassertf(x_,...)
hxassertf(bool x, ...) - Logs an error and terminates execution if x is false.
Definition libhatchet.h:101
ptrdiff_t hxsize_t
hxsize_t - A signed size type, same as ssize_t or ptrdiff_t.
Definition libhatchet.h:207
hxfalse_t - Implements std::false_type.
Definition hxutility.h:112
static constexpr bool value
Definition hxutility.h:112
hxtrue_t - Implements std::true_type.
Definition hxutility.h:110
static constexpr bool value
Definition hxutility.h:110