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;
201template<
typename Out, std::same_as<Out> In>
202[[nodiscard]]
constexpr Out narrow_cast(In
const &rhs)
noexcept
215template<arithmetic Out, arithmetic In>
216[[nodiscard]]
constexpr Out narrow_cast(In
const& rhs)
noexcept requires (not std::same_as<In, Out>)
218 if constexpr (type_in_range_v<Out, In>) {
219 return static_cast<Out
>(rhs);
221 hilet r =
static_cast<Out
>(rhs);
222 hi_axiom(detail::narrow_validate(r, rhs));
227template<arithmetic Out, arithmetic In>
228[[nodiscard]]
constexpr Out round_cast(In rhs)
noexcept
230 if constexpr (std::is_floating_point_v<In>) {
233 return narrow_cast<Out>(rhs);
237template<arithmetic Out, arithmetic In>
238[[nodiscard]]
constexpr Out floor_cast(In rhs)
noexcept
240 if constexpr (std::is_floating_point_v<In>) {
243 return narrow_cast<Out>(rhs);
247template<arithmetic Out, arithmetic In>
248[[nodiscard]]
constexpr Out ceil_cast(In rhs)
noexcept
250 if constexpr (std::is_floating_point_v<In>) {
253 return narrow_cast<Out>(rhs);
259template<std::
integral In>
260[[nodiscard]]
constexpr std::make_unsigned_t<In>
to_unsigned(In rhs)
noexcept
262 return static_cast<std::make_unsigned_t<In>
>(rhs);
267template<std::
integral In>
268[[nodiscard]]
constexpr std::make_signed_t<In>
to_signed(In rhs)
noexcept
270 return static_cast<std::make_signed_t<In>
>(rhs);
275template<std::
integral Out, std::
integral In>
276[[nodiscard]]
constexpr Out
truncate(In rhs)
noexcept
291template<std::
integral Out, std::
integral In>
294 using in_unsigned_type = std::make_unsigned_t<In>;
295 using out_unsigned_type = std::make_unsigned_t<Out>;
298 auto in_unsigned =
static_cast<in_unsigned_type
>(rhs);
299 auto out_unsigned = narrow_cast<out_unsigned_type>(in_unsigned);
300 return static_cast<Out
>(out_unsigned);
313template<std::
integral Out>
314[[nodiscard]]
constexpr Out
char_cast(std::byte rhs)
noexcept
316 return char_cast<Out>(
static_cast<uint8_t
>(rhs));
321template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
324 static_assert(
sizeof(OutType) * 2 ==
sizeof(InType),
"Return value of low_bit_cast must be half the size of the input");
325 return static_cast<OutType
>(value);
330template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
333 static_assert(
sizeof(OutType) * 2 ==
sizeof(InType),
"Return value of high_bit_cast must be half the size of the input");
334 return static_cast<OutType
>(value >>
sizeof(OutType) * CHAR_BIT);
339template<std::
signed_
integral OutType, std::
signed_
integral InType>
340[[nodiscard]]
constexpr OutType low_bit_cast(InType value)
noexcept
342 using UInType = std::make_unsigned_t<InType>;
343 using UOutType = std::make_unsigned_t<OutType>;
344 return static_cast<OutType
>(low_bit_cast<UOutType>(
static_cast<UInType
>(value)));
349template<std::
signed_
integral OutType, std::
signed_
integral InType>
350[[nodiscard]]
constexpr OutType
high_bit_cast(InType value)
noexcept
352 using UInType = std::make_unsigned_t<InType>;
353 using UOutType = std::make_unsigned_t<OutType>;
354 return static_cast<OutType
>(high_bit_cast<UOutType>(
static_cast<UInType
>(value)));
359template<std::
unsigned_
integral OutType, std::
signed_
integral InType>
360[[nodiscard]]
constexpr OutType
low_bit_cast(InType value)
noexcept
362 using UInType = std::make_unsigned_t<InType>;
363 return low_bit_cast<OutType>(
static_cast<UInType
>(value));
368template<std::
unsigned_
integral OutType, std::
signed_
integral InType>
369[[nodiscard]]
constexpr OutType
high_bit_cast(InType value)
noexcept
371 using UInType = std::make_unsigned_t<InType>;
372 return high_bit_cast<OutType>(
static_cast<UInType
>(value));
377template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
380 static_assert(
sizeof(OutType) ==
sizeof(InType) * 2,
"Return value of merge_bit_cast must be double the size of the input");
382 OutType r =
static_cast<OutType
>(
hi);
383 r <<=
sizeof(InType) * CHAR_BIT;
384 r |=
static_cast<OutType
>(lo);
390template<std::
signed_
integral OutType, std::
signed_
integral InType>
391[[nodiscard]]
constexpr OutType merge_bit_cast(InType
hi, InType lo)
noexcept
393 using UInType = std::make_unsigned_t<InType>;
394 using UOutType = std::make_unsigned_t<OutType>;
395 return static_cast<OutType
>(merge_bit_cast<UOutType>(
static_cast<UInType
>(
hi),
static_cast<UInType
>(lo)));
400template<std::
signed_
integral OutType, std::
unsigned_
integral InType>
401[[nodiscard]]
constexpr OutType
merge_bit_cast(InType
hi, InType lo)
noexcept
403 using UOutType = std::make_unsigned_t<OutType>;
404 return narrow_cast<OutType>(merge_bit_cast<UOutType>(
hi, lo));
407[[nodiscard]]
constexpr auto to_underlying(scoped_enum
auto rhs)
noexcept
409 return static_cast<std::underlying_type_t<decltype(rhs)
>>(rhs);
413[[nodiscard]]
constexpr bool to_bool(T&& rhs)
noexcept
414 requires(
requires(T&& x) {
static_cast<bool>(std::forward<T>(x)); })
416 return static_cast<bool>(std::forward<T>(rhs));
421 requires std::is_pointer_v<T>
423 return reinterpret_cast<T
>(value);
432template<
typename T,
byte_like Byte>
433[[nodiscard]] copy_cv_t<T, Byte>& implicit_cast(std::span<Byte> bytes)
435 using value_type = copy_cv_t<T, Byte>;
437 static_assert(std::is_trivially_default_constructible_v<value_type>);
438 static_assert(std::is_trivially_destructible_v<value_type>);
440 if (
sizeof(value_type) > bytes.size()) {
445 if constexpr (
alignof(value_type) != 1) {
446 if (std::bit_cast<std::uintptr_t>(bytes.data()) %
alignof(value_type) != 0) {
451 return *
reinterpret_cast<value_type *
>(bytes.data());
454template<
typename T,
byte_like Byte>
455[[nodiscard]] std::span<copy_cv_t<T, Byte>> implicit_cast(std::span<Byte> bytes,
size_t n)
457 using value_type = copy_cv_t<T, Byte>;
459 static_assert(std::is_trivially_default_constructible_v<value_type>);
460 static_assert(std::is_trivially_destructible_v<value_type>);
462 if (
sizeof(value_type) * n > bytes.size()) {
467 if constexpr (
alignof(value_type) != 1) {
468 if (std::bit_cast<std::uintptr_t>(bytes.data()) %
alignof(value_type) != 0) {
473 return {
reinterpret_cast<value_type *
>(bytes.data()), n};
476template<
typename T,
byte_like Byte>
477[[nodiscard]] copy_cv_t<T, Byte>& implicit_cast(
size_t& offset, std::span<Byte> bytes)
479 using value_type = copy_cv_t<T, Byte>;
481 static_assert(std::is_trivially_default_constructible_v<value_type>);
482 static_assert(std::is_trivially_destructible_v<value_type>);
484 if (
sizeof(value_type) + offset > bytes.size()) {
489 hilet data = bytes.data() + offset;
491 if constexpr (
alignof(value_type) != 1) {
492 if (std::bit_cast<std::uintptr_t>(data) %
alignof(value_type) != 0) {
497 offset +=
sizeof(value_type);
498 return *
reinterpret_cast<value_type *
>(data);
501template<
typename T,
byte_like Byte>
502[[nodiscard]] std::span<copy_cv_t<T, Byte>> implicit_cast(
size_t& offset, std::span<Byte> bytes,
size_t n)
504 using value_type = copy_cv_t<T, Byte>;
506 static_assert(std::is_trivially_default_constructible_v<value_type>);
507 static_assert(std::is_trivially_destructible_v<value_type>);
509 if (
sizeof(value_type) * n + offset > bytes.size()) {
514 hilet data = bytes.data() + offset;
516 if constexpr (
alignof(value_type) != 1) {
517 if (std::bit_cast<std::uintptr_t>(data) %
alignof(value_type) != 0) {
522 offset +=
sizeof(value_type) * n;
523 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:378
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:331
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:292
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:260
constexpr OutType low_bit_cast(InType value) noexcept
Return the low half of the input value.
Definition cast.hpp:322
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:276
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:268
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