13#include "concepts.hpp"
40namespace hi::inline
v1 {
42[[nodiscard]]
constexpr T
copy(T value)
noexcept
54template<
typename Out,
typename In>
55[[nodiscard]]
constexpr Out
up_cast(In *rhs)
noexcept
57 using out_type = std::remove_pointer_t<Out>;
59 static_assert(std::is_pointer_v<Out>,
"up_cast() Out template paramater must be a pointer if the input is a pointer.");
60 static_assert(std::is_const_v<out_type> == std::is_const_v<In> or std::is_const_v<out_type>,
"up_cast() can not cast away const.");
61 static_assert(std::is_base_of_v<out_type, In>,
"up_cast() may only be used to cast to a base-type.");
63 return static_cast<Out
>(rhs);
74[[nodiscard]]
constexpr Out
up_cast(nullptr_t)
noexcept
76 static_assert(std::is_pointer_v<Out>,
"up_cast() Out template paramater must be a pointer.");
87template<
typename Out,
typename In>
88[[nodiscard]]
constexpr Out
up_cast(In& rhs)
noexcept
90 using out_type = std::remove_reference_t<Out>;
92 static_assert(std::is_reference_v<Out>,
"up_cast() Out template paramater must be a reference if the input is a reference.");
93 static_assert(std::is_const_v<out_type> == std::is_const_v<In> or std::is_const_v<out_type>,
"up_cast() can not cast away const.");
94 static_assert(std::is_base_of_v<out_type, In>,
"up_cast() may only be used to cast to a base-type.");
96 return static_cast<Out
>(rhs);
107template<
typename Out,
typename In>
110 using out_type = std::remove_pointer_t<Out>;
112 static_assert(std::is_pointer_v<Out>,
"down_cast() Out template paramater must be a pointer if the input is a pointer.");
113 static_assert(std::is_const_v<out_type> == std::is_const_v<In> or std::is_const_v<out_type>,
"down_cast() can not cast away const.");
114 static_assert(std::is_base_of_v<out_type, In> or std::is_base_of_v<In, out_type>,
"down_cast() may only be used to cast to a related type.");
116 if constexpr (not std::is_base_of_v<out_type, In>) {
117 hi_axiom(rhs ==
nullptr or
dynamic_cast<Out
>(rhs) !=
nullptr);
119 return static_cast<Out
>(rhs);
127template<
typename Out>
128[[nodiscard]]
constexpr Out
down_cast(nullptr_t)
noexcept
129 requires std::is_pointer_v<Out>
141template<
typename Out,
typename In>
144 using out_type = std::remove_reference_t<Out>;
146 static_assert(std::is_reference_v<Out>,
"down_cast() Out template paramater must be a reference if the input is a reference.");
147 static_assert(std::is_const_v<out_type> == std::is_const_v<In> or std::is_const_v<out_type>,
"down_cast() can not cast away const.");
148 static_assert(std::is_base_of_v<out_type, In> or std::is_base_of_v<In, out_type>,
"down_cast() may only be used to cast to a related type.");
150 if constexpr (not std::is_base_of_v<out_type, In>) {
153 return static_cast<Out
>(rhs);
164template<
typename Out, std::same_as<Out> In>
165[[nodiscard]]
constexpr Out
wide_cast(In
const& rhs)
noexcept
177template<std::
floating_po
int Out, std::
floating_po
int In>
178[[nodiscard]]
constexpr Out
wide_cast(In
const& rhs)
noexcept
179 requires(not std::same_as<In, Out>)
183 "wide_cast() is only allowed to a floating point of the same or larger size.");
185 return static_cast<Out
>(rhs);
195template<std::
integral Out, std::
integral In>
197 requires(not std::same_as<In, Out>)
201 "wide_cast() is only allowed if the input is unsigned or if both input and output have the same signess.");
205 "wide_cast() is only allowed to an integer of the same or larger size.");
207 return static_cast<Out
>(rhs);
224template<std::
floating_po
int Out, std::
integral In>
229 "wide_cast() is only allowed if the input can be represented with perfect accuracy by the floating point output type.");
231 return static_cast<Out
>(rhs);
240template<std::
integral Out, arithmetic In>
243 if constexpr (std::is_floating_point_v<In>) {
254 return static_cast<Out
>(rhs);
265template<
typename Out, std::same_as<Out> In>
278template<std::
floating_po
int Out, std::
floating_po
int In>
280 requires(not std::same_as<In, Out>)
298template<std::
integral Out, std::
integral In>
299[[nodiscard]]
constexpr bool can_narrow_cast(In
const& rhs)
noexcept
300 requires(not std::same_as<In, Out>)
337template<std::
floating_po
int Out, std::
integral In>
343 constexpr auto lowest = -
max;
345 return rhs >= lowest and rhs <=
max;
366template<
typename Out, std::same_as<Out> In>
381template<std::
floating_po
int Out, std::
floating_po
int In>
383 requires(not std::same_as<In, Out>)
392 return static_cast<Out
>(rhs);
404template<std::
integral Out, std::
integral In>
405[[nodiscard]]
constexpr Out narrow_cast(In
const& rhs)
noexcept
406 requires(not std::same_as<In, Out>)
428 return static_cast<Out
>(rhs);
440template<std::
floating_po
int Out, std::
integral In>
441[[nodiscard]]
constexpr Out
narrow_cast(In
const& rhs)
noexcept
446 constexpr auto lowest = -
max;
448 hi_axiom(rhs >= lowest and rhs <= max);
457 return static_cast<Out
>(rhs);
460template<std::
integral Out, std::
floating_po
int In>
461[[nodiscard]]
constexpr bool can_round_cast(In rhs)
noexcept
467template<
std::integral Out,
std::floating_point In>
468[[nodiscard]] constexpr
bool can_floor_cast(In rhs) noexcept
474template<
std::integral Out,
std::floating_point In>
475[[nodiscard]] constexpr
bool can_ceil_cast(In rhs) noexcept
481template<
std::integral Out,
std::floating_point In>
482[[nodiscard]] constexpr Out round_cast(In rhs) noexcept
486 return static_cast<Out
>(rhs_);
489template<std::
integral Out, std::
floating_po
int In>
490[[nodiscard]]
constexpr Out floor_cast(In rhs)
noexcept
494 return static_cast<Out
>(rhs_);
497template<std::
integral Out, std::
floating_po
int In>
498[[nodiscard]]
constexpr Out ceil_cast(In rhs)
noexcept
502 return static_cast<Out
>(rhs_);
507template<std::
integral In>
508[[nodiscard]]
constexpr std::make_unsigned_t<In>
to_unsigned(In rhs)
noexcept
510 return static_cast<std::make_unsigned_t<In>
>(rhs);
515template<std::
integral In>
516[[nodiscard]]
constexpr std::make_signed_t<In>
to_signed(In rhs)
noexcept
518 return static_cast<std::make_signed_t<In>
>(rhs);
523template<std::
integral Out, std::
integral In>
524[[nodiscard]]
constexpr Out
truncate(In rhs)
noexcept
539template<std::
integral Out, std::
integral In>
542 using in_unsigned_type = std::make_unsigned_t<In>;
543 using out_unsigned_type = std::make_unsigned_t<Out>;
546 auto in_unsigned =
static_cast<in_unsigned_type
>(rhs);
547 auto out_unsigned = narrow_cast<out_unsigned_type>(in_unsigned);
548 return static_cast<Out
>(out_unsigned);
561template<std::
integral Out>
562[[nodiscard]]
constexpr Out
char_cast(std::byte rhs)
noexcept
564 return char_cast<Out>(
static_cast<uint8_t
>(rhs));
569template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
572 static_assert(
sizeof(OutType) * 2 ==
sizeof(InType),
"Return value of low_bit_cast must be half the size of the input");
573 return static_cast<OutType
>(value);
578template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
581 static_assert(
sizeof(OutType) * 2 ==
sizeof(InType),
"Return value of high_bit_cast must be half the size of the input");
582 return static_cast<OutType
>(value >>
sizeof(OutType) * CHAR_BIT);
587template<std::
signed_
integral OutType, std::
signed_
integral InType>
588[[nodiscard]]
constexpr OutType low_bit_cast(InType value)
noexcept
590 using UInType = std::make_unsigned_t<InType>;
591 using UOutType = std::make_unsigned_t<OutType>;
592 return static_cast<OutType
>(low_bit_cast<UOutType>(
static_cast<UInType
>(value)));
597template<std::
signed_
integral OutType, std::
signed_
integral InType>
598[[nodiscard]]
constexpr OutType
high_bit_cast(InType value)
noexcept
600 using UInType = std::make_unsigned_t<InType>;
601 using UOutType = std::make_unsigned_t<OutType>;
602 return static_cast<OutType
>(high_bit_cast<UOutType>(
static_cast<UInType
>(value)));
607template<std::
unsigned_
integral OutType, std::
signed_
integral InType>
608[[nodiscard]]
constexpr OutType
low_bit_cast(InType value)
noexcept
610 using UInType = std::make_unsigned_t<InType>;
611 return low_bit_cast<OutType>(
static_cast<UInType
>(value));
616template<std::
unsigned_
integral OutType, std::
signed_
integral InType>
617[[nodiscard]]
constexpr OutType
high_bit_cast(InType value)
noexcept
619 using UInType = std::make_unsigned_t<InType>;
620 return high_bit_cast<OutType>(
static_cast<UInType
>(value));
625template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
628 static_assert(
sizeof(OutType) ==
sizeof(InType) * 2,
"Return value of merge_bit_cast must be double the size of the input");
630 OutType r =
static_cast<OutType
>(
hi);
631 r <<=
sizeof(InType) * CHAR_BIT;
632 r |=
static_cast<OutType
>(lo);
638template<std::
signed_
integral OutType, std::
signed_
integral InType>
639[[nodiscard]]
constexpr OutType merge_bit_cast(InType
hi, InType lo)
noexcept
641 using UInType = std::make_unsigned_t<InType>;
642 using UOutType = std::make_unsigned_t<OutType>;
643 return static_cast<OutType
>(merge_bit_cast<UOutType>(
static_cast<UInType
>(
hi),
static_cast<UInType
>(lo)));
648template<std::
signed_
integral OutType, std::
unsigned_
integral InType>
649[[nodiscard]]
constexpr OutType
merge_bit_cast(InType
hi, InType lo)
noexcept
651 using UOutType = std::make_unsigned_t<OutType>;
652 return narrow_cast<OutType>(merge_bit_cast<UOutType>(
hi, lo));
655[[nodiscard]]
constexpr auto to_underlying(scoped_enum
auto rhs)
noexcept
657 return static_cast<std::underlying_type_t<decltype(rhs)
>>(rhs);
661[[nodiscard]]
constexpr bool to_bool(T&& rhs)
noexcept
662 requires(
requires(T&& x) {
static_cast<bool>(std::forward<T>(x)); })
664 return static_cast<bool>(std::forward<T>(rhs));
669 requires std::is_pointer_v<T>
671 return reinterpret_cast<T
>(value);
680template<
typename T,
byte_like Byte>
681[[nodiscard]] copy_cv_t<T, Byte>& implicit_cast(std::span<Byte> bytes)
683 using value_type = copy_cv_t<T, Byte>;
685 static_assert(std::is_trivially_default_constructible_v<value_type>);
686 static_assert(std::is_trivially_destructible_v<value_type>);
688 if (
sizeof(value_type) > bytes.size()) {
693 if constexpr (
alignof(value_type) != 1) {
694 if (std::bit_cast<std::uintptr_t>(bytes.data()) %
alignof(value_type) != 0) {
699 return *
reinterpret_cast<value_type *
>(bytes.data());
702template<
typename T,
byte_like Byte>
703[[nodiscard]] std::span<copy_cv_t<T, Byte>> implicit_cast(std::span<Byte> bytes,
size_t n)
705 using value_type = copy_cv_t<T, Byte>;
707 static_assert(std::is_trivially_default_constructible_v<value_type>);
708 static_assert(std::is_trivially_destructible_v<value_type>);
710 if (
sizeof(value_type) * n > bytes.size()) {
715 if constexpr (
alignof(value_type) != 1) {
716 if (std::bit_cast<std::uintptr_t>(bytes.data()) %
alignof(value_type) != 0) {
721 return {
reinterpret_cast<value_type *
>(bytes.data()), n};
724template<
typename T,
byte_like Byte>
725[[nodiscard]] copy_cv_t<T, Byte>& implicit_cast(
size_t& offset, std::span<Byte> bytes)
727 using value_type = copy_cv_t<T, Byte>;
729 static_assert(std::is_trivially_default_constructible_v<value_type>);
730 static_assert(std::is_trivially_destructible_v<value_type>);
732 if (
sizeof(value_type) + offset > bytes.size()) {
737 hilet data = bytes.data() + offset;
739 if constexpr (
alignof(value_type) != 1) {
740 if (std::bit_cast<std::uintptr_t>(data) %
alignof(value_type) != 0) {
745 offset +=
sizeof(value_type);
746 return *
reinterpret_cast<value_type *
>(data);
749template<
typename T,
byte_like Byte>
750[[nodiscard]] std::span<copy_cv_t<T, Byte>> implicit_cast(
size_t& offset, std::span<Byte> bytes,
size_t n)
752 using value_type = copy_cv_t<T, Byte>;
754 static_assert(std::is_trivially_default_constructible_v<value_type>);
755 static_assert(std::is_trivially_destructible_v<value_type>);
757 if (
sizeof(value_type) * n + offset > bytes.size()) {
762 hilet data = bytes.data() + offset;
764 if constexpr (
alignof(value_type) != 1) {
765 if (std::bit_cast<std::uintptr_t>(data) %
alignof(value_type) != 0) {
770 offset +=
sizeof(value_type) * n;
771 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
hi_warning_ignore_msvc(26472)
Definition int_carry.hpp:27
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:626
constexpr OutType high_bit_cast(InType value) noexcept
Return the upper half of the input value.
Definition cast.hpp:579
constexpr Out saturate_cast(In rhs) noexcept
Cast a numeric value to an integer saturating on overflow.
Definition cast.hpp:241
constexpr Out char_cast(In rhs) noexcept
Cast a character.
Definition cast.hpp:540
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:367
constexpr Out down_cast(In *rhs) noexcept
Cast a pointer to a class to its derived class or itself.
Definition cast.hpp:108
constexpr Out up_cast(In *rhs) noexcept
Cast a pointer to a class to its base class or itself.
Definition cast.hpp:55
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:508
constexpr OutType low_bit_cast(InType value) noexcept
Return the low half of the input value.
Definition cast.hpp:570
constexpr bool can_narrow_cast(In const &rhs) noexcept
Check if a value can be casted to a narrow type.
Definition cast.hpp:266
constexpr Out truncate(In rhs) noexcept
Cast between integral types truncating or zero-extending the result.
Definition cast.hpp:524
constexpr Out wide_cast(In const &rhs) noexcept
Cast to a type which can hold all values from the input type.
Definition cast.hpp:165
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:516
geometry/margins.hpp
Definition cache.hpp:11