20hi_warning_ignore_msvc(26472);
25hi_warning_ignore_msvc(26467);
28hi_warning_ignore_msvc(26496);
31hi_warning_ignore_msvc(26466);
34hi_warning_ignore_msvc(26474);
36namespace hi::inline
v1 {
38[[nodiscard]]
constexpr T
copy(T value)
noexcept
45template<
typename Out, std::derived_from<std::remove_po
inter_t<Out>> In>
46[[nodiscard]]
constexpr Out
up_cast(In *rhs)
noexcept
47 requires std::is_pointer_v<Out> and
48 (std::is_const_v<std::remove_pointer_t<Out>> == std::is_const_v<In> or std::is_const_v<std::remove_pointer_t<Out>>)
50 if constexpr (std::is_same_v<std::remove_const_t<In>, remove_cvptr_t<Out>>) {
53 return static_cast<Out
>(rhs);
60[[nodiscard]]
constexpr Out
up_cast(nullptr_t)
noexcept
61 requires std::is_pointer_v<Out>
68template<
typename Out, std::derived_from<std::remove_reference_t<Out>> In>
69[[nodiscard]]
constexpr Out
up_cast(In& rhs)
noexcept
70 requires std::is_reference_v<Out> and
71 (std::is_const_v<std::remove_reference_t<Out>> == std::is_const_v<In> or std::is_const_v<std::remove_reference_t<Out>>)
73 if constexpr (std::is_same_v<std::remove_const_t<In>, std::remove_cvref_t<Out>>) {
76 return static_cast<Out
>(rhs);
87template<
typename Out, base_of<std::remove_po
inter_t<Out>> In>
88[[nodiscard]]
constexpr Out
down_cast(In *rhs)
noexcept
89 requires std::is_pointer_v<Out> and
90 (std::is_const_v<std::remove_pointer_t<Out>> == std::is_const_v<In> or std::is_const_v<std::remove_pointer_t<Out>>)
92 if constexpr (std::is_same_v<std::remove_const_t<In>, remove_cvptr_t<Out>>) {
95 hi_axiom(rhs ==
nullptr or
dynamic_cast<Out
>(rhs) !=
nullptr);
96 return static_cast<Out
>(rhs);
104template<
typename Out>
105[[nodiscard]]
constexpr Out
down_cast(nullptr_t)
noexcept
106 requires std::is_pointer_v<Out>
117template<
typename Out, base_of<std::remove_reference_t<Out>> In>
119 requires std::is_reference_v<Out> and
120 (std::is_const_v<std::remove_reference_t<Out>> == std::is_const_v<In> or std::is_const_v<std::remove_reference_t<Out>>)
122 if constexpr (std::is_same_v<std::remove_const_t<In>, std::remove_cvref_t<Out>>) {
126 return static_cast<Out
>(rhs);
132template<arithmetic Out, arithmetic In>
134 requires(type_in_range_v<Out, In>)
136 return static_cast<Out
>(rhs);
141template<arithmetic Out>
144 return static_cast<Out
>(rhs);
149template<arithmetic Out, arithmetic In>
150[[nodiscard]]
constexpr bool narrow_validate(Out out, In in)
noexcept
153 auto r = (in ==
static_cast<In
>(out));
158 r &= (in < In{}) == (out < Out{});
172template<std::
integral Out, arithmetic In>
175 if constexpr (std::is_floating_point_v<In>) {
186 return static_cast<Out
>(rhs);
198template<
typename Out,
typename In>
199[[nodiscard]]
constexpr Out narrow_cast(In
const& rhs)
noexcept;
209template<arithmetic Out, arithmetic In>
210[[nodiscard]]
constexpr Out narrow_cast(In
const& rhs)
noexcept
212 if constexpr (type_in_range_v<Out, In>) {
213 return static_cast<Out
>(rhs);
215 hilet r =
static_cast<Out
>(rhs);
216 hi_axiom(detail::narrow_validate(r, rhs));
221template<arithmetic Out, arithmetic In>
222[[nodiscard]]
constexpr Out round_cast(In rhs)
noexcept
224 if constexpr (std::is_floating_point_v<In>) {
227 return narrow_cast<Out>(rhs);
231template<arithmetic Out, arithmetic In>
232[[nodiscard]]
constexpr Out floor_cast(In rhs)
noexcept
234 if constexpr (std::is_floating_point_v<In>) {
237 return narrow_cast<Out>(rhs);
241template<arithmetic Out, arithmetic In>
242[[nodiscard]]
constexpr Out ceil_cast(In rhs)
noexcept
244 if constexpr (std::is_floating_point_v<In>) {
247 return narrow_cast<Out>(rhs);
253template<std::
integral In>
254[[nodiscard]]
constexpr std::make_unsigned_t<In>
to_unsigned(In rhs)
noexcept
256 return static_cast<std::make_unsigned_t<In>
>(rhs);
261template<std::
integral In>
262[[nodiscard]]
constexpr std::make_signed_t<In>
to_signed(In rhs)
noexcept
264 return static_cast<std::make_signed_t<In>
>(rhs);
269template<std::
integral Out, std::
integral In>
270[[nodiscard]]
constexpr Out
truncate(In rhs)
noexcept
285template<std::
integral Out, std::
integral In>
288 using in_unsigned_type = std::make_unsigned_t<In>;
289 using out_unsigned_type = std::make_unsigned_t<Out>;
292 auto in_unsigned =
static_cast<in_unsigned_type
>(rhs);
293 auto out_unsigned = narrow_cast<out_unsigned_type>(in_unsigned);
294 return static_cast<Out
>(out_unsigned);
307template<std::
integral Out>
308[[nodiscard]]
constexpr Out
char_cast(std::byte rhs)
noexcept
310 return char_cast<Out>(
static_cast<uint8_t
>(rhs));
315template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
318 static_assert(
sizeof(OutType) * 2 ==
sizeof(InType),
"Return value of low_bit_cast must be half the size of the input");
319 return static_cast<OutType
>(value);
324template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
327 static_assert(
sizeof(OutType) * 2 ==
sizeof(InType),
"Return value of high_bit_cast must be half the size of the input");
328 return static_cast<OutType
>(value >>
sizeof(OutType) * CHAR_BIT);
333template<std::
signed_
integral OutType, std::
signed_
integral InType>
334[[nodiscard]]
constexpr OutType low_bit_cast(InType value)
noexcept
336 using UInType = std::make_unsigned_t<InType>;
337 using UOutType = std::make_unsigned_t<OutType>;
338 return static_cast<OutType
>(low_bit_cast<UOutType>(
static_cast<UInType
>(value)));
343template<std::
signed_
integral OutType, std::
signed_
integral InType>
344[[nodiscard]]
constexpr OutType
high_bit_cast(InType value)
noexcept
346 using UInType = std::make_unsigned_t<InType>;
347 using UOutType = std::make_unsigned_t<OutType>;
348 return static_cast<OutType
>(high_bit_cast<UOutType>(
static_cast<UInType
>(value)));
353template<std::
unsigned_
integral OutType, std::
signed_
integral InType>
354[[nodiscard]]
constexpr OutType
low_bit_cast(InType value)
noexcept
356 using UInType = std::make_unsigned_t<InType>;
357 return low_bit_cast<OutType>(
static_cast<UInType
>(value));
362template<std::
unsigned_
integral OutType, std::
signed_
integral InType>
363[[nodiscard]]
constexpr OutType
high_bit_cast(InType value)
noexcept
365 using UInType = std::make_unsigned_t<InType>;
366 return high_bit_cast<OutType>(
static_cast<UInType
>(value));
371template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
374 static_assert(
sizeof(OutType) ==
sizeof(InType) * 2,
"Return value of merge_bit_cast must be double the size of the input");
376 OutType r =
static_cast<OutType
>(
hi);
377 r <<=
sizeof(InType) * CHAR_BIT;
378 r |=
static_cast<OutType
>(lo);
384template<std::
signed_
integral OutType, std::
signed_
integral InType>
385[[nodiscard]]
constexpr OutType merge_bit_cast(InType
hi, InType lo)
noexcept
387 using UInType = std::make_unsigned_t<InType>;
388 using UOutType = std::make_unsigned_t<OutType>;
389 return static_cast<OutType
>(merge_bit_cast<UOutType>(
static_cast<UInType
>(
hi),
static_cast<UInType
>(lo)));
394template<std::
signed_
integral OutType, std::
unsigned_
integral InType>
395[[nodiscard]]
constexpr OutType
merge_bit_cast(InType
hi, InType lo)
noexcept
397 using UOutType = std::make_unsigned_t<OutType>;
398 return narrow_cast<OutType>(merge_bit_cast<UOutType>(
hi, lo));
401[[nodiscard]]
constexpr auto to_underlying(scoped_enum
auto rhs)
noexcept
403 return static_cast<std::underlying_type_t<decltype(rhs)
>>(rhs);
407[[nodiscard]]
constexpr bool to_bool(T&& rhs)
noexcept
408 requires(
requires(T&& x) {
static_cast<bool>(std::forward<T>(x)); })
410 return static_cast<bool>(std::forward<T>(rhs));
415 requires std::is_pointer_v<T>
417 return reinterpret_cast<T
>(value);
426template<
typename T,
byte_like Byte>
427[[nodiscard]] copy_cv_t<T, Byte>& implicit_cast(std::span<Byte> bytes)
429 using value_type = copy_cv_t<T, Byte>;
431 static_assert(std::is_trivially_default_constructible_v<value_type>);
432 static_assert(std::is_trivially_destructible_v<value_type>);
434 if (
sizeof(value_type) > bytes.size()) {
439 if constexpr (
alignof(value_type) != 1) {
440 if (std::bit_cast<std::uintptr_t>(bytes.data()) %
alignof(value_type) != 0) {
445 return *
reinterpret_cast<value_type *
>(bytes.data());
448template<
typename T,
byte_like Byte>
449[[nodiscard]] std::span<copy_cv_t<T, Byte>> implicit_cast(std::span<Byte> bytes,
size_t n)
451 using value_type = copy_cv_t<T, Byte>;
453 static_assert(std::is_trivially_default_constructible_v<value_type>);
454 static_assert(std::is_trivially_destructible_v<value_type>);
456 if (
sizeof(value_type) * n > bytes.size()) {
461 if constexpr (
alignof(value_type) != 1) {
462 if (std::bit_cast<std::uintptr_t>(bytes.data()) %
alignof(value_type) != 0) {
467 return {
reinterpret_cast<value_type *
>(bytes.data()), n};
470template<
typename T,
byte_like Byte>
471[[nodiscard]] copy_cv_t<T, Byte>& implicit_cast(
size_t& offset, std::span<Byte> bytes)
473 using value_type = copy_cv_t<T, Byte>;
475 static_assert(std::is_trivially_default_constructible_v<value_type>);
476 static_assert(std::is_trivially_destructible_v<value_type>);
478 if (
sizeof(value_type) + offset > bytes.size()) {
483 hilet data = bytes.data() + offset;
485 if constexpr (
alignof(value_type) != 1) {
486 if (std::bit_cast<std::uintptr_t>(data) %
alignof(value_type) != 0) {
491 offset +=
sizeof(value_type);
492 return *
reinterpret_cast<value_type *
>(data);
495template<
typename T,
byte_like Byte>
496[[nodiscard]] std::span<copy_cv_t<T, Byte>> implicit_cast(
size_t& offset, std::span<Byte> bytes,
size_t n)
498 using value_type = copy_cv_t<T, Byte>;
500 static_assert(std::is_trivially_default_constructible_v<value_type>);
501 static_assert(std::is_trivially_destructible_v<value_type>);
503 if (
sizeof(value_type) * n + offset > bytes.size()) {
508 hilet data = bytes.data() + offset;
510 if constexpr (
alignof(value_type) != 1) {
511 if (std::bit_cast<std::uintptr_t>(data) %
alignof(value_type) != 0) {
516 offset +=
sizeof(value_type) * n;
517 return {
reinterpret_cast<value_type *
>(data), n};
Utilities to assert and bound check.
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hi_axiom_not_null(expression,...)
Assert if an expression is not nullptr.
Definition assert.hpp:272
Safe numeric comparison between different types.
Utilities used by the HikoGUI library itself.
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:13
constexpr OutType merge_bit_cast(InType hi, InType lo) noexcept
Return the upper half of the input value.
Definition cast.hpp:372
constexpr Out wide_cast(In rhs) noexcept
Cast a number to a type that will be able to represent all values without loss of precision.
Definition cast.hpp:133
constexpr OutType high_bit_cast(InType value) noexcept
Return the upper half of the input value.
Definition cast.hpp:325
constexpr Out saturate_cast(In rhs) noexcept
Cast a numeric value to an integer saturating on overflow.
Definition cast.hpp:173
constexpr Out up_cast(In *rhs) noexcept
Cast a pointer to a class to its base class or itself.
Definition cast.hpp:46
constexpr Out char_cast(In rhs) noexcept
Cast a character.
Definition cast.hpp:286
constexpr std::make_unsigned_t< In > to_unsigned(In rhs) noexcept
Cast an integral to an unsigned integral of the same size.
Definition cast.hpp:254
constexpr OutType low_bit_cast(InType value) noexcept
Return the low half of the input value.
Definition cast.hpp:316
constexpr Out down_cast(In *rhs) noexcept
Cast a pointer to a class to its derived class or itself.
Definition cast.hpp:88
constexpr Out truncate(In rhs) noexcept
Cast between integral types truncating or zero-extending the result.
Definition cast.hpp:270
constexpr std::make_signed_t< In > to_signed(In rhs) noexcept
Cast an integral to an signed integral of the same size.
Definition cast.hpp:262
geometry/margins.hpp
Definition cache.hpp:11
constexpr auto three_way_compare(Lhs const &lhs, Rhs const &rhs) noexcept
Safely compare two arithmetic values to each other.
Definition compare.hpp:123