12#include "../macros.hpp"
15#include "concepts.hpp"
16#include "debugger.hpp"
17#include "exception.hpp"
26hi_export_module(hikogui.utility.cast);
31hi_warning_ignore_msvc(26472);
36hi_warning_ignore_msvc(26467);
39hi_warning_ignore_msvc(26496);
42hi_warning_ignore_msvc(26466);
45hi_warning_ignore_msvc(26474);
47hi_warning_ignore_msvc(4702);
49hi_export
namespace hi {
inline namespace v1 {
64template<
typename Out,
typename In>
67 using out_type = std::remove_pointer_t<Out>;
69 static_assert(std::is_pointer_v<Out>,
"up_cast() Out template paramater must be a pointer if the input is a pointer.");
70 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.");
71 static_assert(std::is_base_of_v<out_type, In>,
"up_cast() may only be used to cast to a base-type.");
73 return static_cast<Out>(rhs);
86 static_assert(std::is_pointer_v<Out>,
"up_cast() Out template paramater must be a pointer.");
97template<
typename Out,
typename In>
100 using out_type = std::remove_reference_t<Out>;
102 static_assert(std::is_reference_v<Out>,
"up_cast() Out template paramater must be a reference if the input is a reference.");
103 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.");
104 static_assert(std::is_base_of_v<out_type, In>,
"up_cast() may only be used to cast to a base-type.");
106 return static_cast<Out>(rhs);
117template<
typename Out,
typename In>
120 using out_type = std::remove_pointer_t<Out>;
122 static_assert(std::is_pointer_v<Out>,
"down_cast() Out template paramater must be a pointer if the input is a pointer.");
123 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.");
124 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.");
126 if constexpr (
not std::is_base_of_v<out_type, In>) {
127 hi_axiom(rhs ==
nullptr or dynamic_cast<Out>(rhs) !=
nullptr);
129 return static_cast<Out>(rhs);
137template<
typename Out>
139 requires std::is_pointer_v<Out>
151template<
typename Out,
typename In>
154 using out_type = std::remove_reference_t<Out>;
156 static_assert(std::is_reference_v<Out>,
"down_cast() Out template paramater must be a reference if the input is a reference.");
157 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.");
158 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.");
160 if constexpr (
not std::is_base_of_v<out_type, In>) {
161 hi_axiom(
dynamic_cast<std::add_pointer_t<out_type>
>(
std::addressof(rhs)) !=
nullptr);
163 return static_cast<Out>(rhs);
174template<
typename Out, std::same_as<Out> In>
187template<std::
floating_po
int Out, std::
floating_po
int In>
189 requires(
not std::same_as<In, Out>)
193 "wide_cast() is only allowed to a floating point of the same or larger size.");
195 return static_cast<Out>(rhs);
205template<std::
integral Out, std::
integral In>
207 requires(
not std::same_as<In, Out>)
211 "wide_cast() is only allowed if the input is unsigned or if both input and output have the same signess.");
215 "wide_cast() is only allowed to an integer of the same or larger size.");
217 return static_cast<Out>(rhs);
234template<std::
floating_po
int Out, std::
integral In>
239 "wide_cast() is only allowed if the input can be represented with perfect accuracy by the floating point output type.");
241 return static_cast<Out>(rhs);
250template<std::
integral Out, arithmetic In>
253 if constexpr (std::is_floating_point_v<In>) {
264 return static_cast<Out>(rhs);
275template<
typename Out, std::same_as<Out> In>
288template<std::
floating_po
int Out, std::
floating_po
int In>
290 requires(
not std::same_as<In, Out>)
308template<std::
integral Out, std::
integral In>
310 requires(
not std::same_as<In, Out>)
347template<std::
floating_po
int Out, std::
integral In>
353 constexpr auto lowest = -
max;
355 return rhs >= lowest
and rhs <=
max;
376template<
typename Out, std::same_as<Out> In>
391template<std::
floating_po
int Out, std::
floating_po
int In>
393 requires(
not std::same_as<In, Out>)
402 return static_cast<Out>(rhs);
414template<std::
integral Out, std::
integral In>
416 requires(
not std::same_as<In, Out>)
438 return static_cast<Out>(rhs);
450template<std::
floating_po
int Out, std::
integral In>
456 constexpr auto lowest = -
max;
458 hi_axiom(rhs >= lowest
and rhs <= max);
463 hi_axiom(rhs <= max);
467 return static_cast<Out>(rhs);
470template<std::
integral Out, std::
floating_po
int In>
471[[
nodiscard]]
constexpr bool can_round_cast(
In rhs)
noexcept
499template<std::
integral Out, std::
floating_po
int In>
507template<std::
integral Out, std::
floating_po
int In>
517template<std::
integral In>
520 return static_cast<std::make_unsigned_t<In>
>(rhs);
525template<std::
integral In>
528 return static_cast<std::make_signed_t<In>
>(rhs);
533template<std::
integral Out, std::
integral In>
549template<std::
integral Out, std::
integral In>
571template<std::
integral Out>
579template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
582 static_assert(
sizeof(
OutType) * 2 ==
sizeof(
InType),
"Return value of low_bit_cast must be half the size of the input");
583 return static_cast<OutType>(value);
588template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
591 static_assert(
sizeof(
OutType) * 2 ==
sizeof(
InType),
"Return value of high_bit_cast must be half the size of the input");
597template<std::
signed_
integral OutType, std::
signed_
integral InType>
600 using UInType = std::make_unsigned_t<InType>;
601 using UOutType = std::make_unsigned_t<OutType>;
607template<std::
signed_
integral OutType, std::
signed_
integral InType>
610 using UInType = std::make_unsigned_t<InType>;
611 using UOutType = std::make_unsigned_t<OutType>;
617template<std::
unsigned_
integral OutType, std::
signed_
integral InType>
620 using UInType = std::make_unsigned_t<InType>;
626template<std::
unsigned_
integral OutType, std::
signed_
integral InType>
629 using UInType = std::make_unsigned_t<InType>;
635template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
638 static_assert(
sizeof(
OutType) ==
sizeof(
InType) * 2,
"Return value of merge_bit_cast must be double the size of the input");
648template<std::
signed_
integral OutType, std::
signed_
integral InType>
651 using UInType = std::make_unsigned_t<InType>;
652 using UOutType = std::make_unsigned_t<OutType>;
658template<std::
signed_
integral OutType, std::
unsigned_
integral InType>
661 using UOutType = std::make_unsigned_t<OutType>;
666[[
nodiscard]]
constexpr bool to_bool(T&& rhs)
noexcept
667 requires(
requires(T&& x) {
static_cast<bool>(std::forward<T>(x)); })
669 return static_cast<bool>(std::forward<T>(rhs));
674 requires std::is_pointer_v<T>
676 return reinterpret_cast<T
>(value);
685template<
typename T,
byte_like Byte>
690 static_assert(std::is_trivially_default_constructible_v<value_type>);
691 static_assert(std::is_trivially_destructible_v<value_type>);
693 if (
sizeof(value_type) >
bytes.size()) {
696 hi_axiom_not_null(
bytes.data());
698 if constexpr (
alignof(value_type) != 1) {
699 if (std::bit_cast<std::uintptr_t>(
bytes.data()) %
alignof(value_type) != 0) {
704 return *
reinterpret_cast<value_type *
>(
bytes.data());
707template<
typename T,
byte_like Byte>
708[[
nodiscard]] std::span<copy_cv_t<T, Byte>> implicit_cast(std::span<Byte>
bytes,
size_t n)
712 static_assert(std::is_trivially_default_constructible_v<value_type>);
713 static_assert(std::is_trivially_destructible_v<value_type>);
715 if (
sizeof(value_type) * n >
bytes.size()) {
718 hi_axiom_not_null(
bytes.data());
720 if constexpr (
alignof(value_type) != 1) {
721 if (std::bit_cast<std::uintptr_t>(
bytes.data()) %
alignof(value_type) != 0) {
726 return {
reinterpret_cast<value_type *
>(
bytes.data()), n};
729template<
typename T,
byte_like Byte>
734 static_assert(std::is_trivially_default_constructible_v<value_type>);
735 static_assert(std::is_trivially_destructible_v<value_type>);
737 if (
sizeof(value_type) + offset >
bytes.size()) {
740 hi_axiom_not_null(
bytes.data());
742 hilet data =
bytes.data() + offset;
744 if constexpr (
alignof(value_type) != 1) {
745 if (std::bit_cast<std::uintptr_t>(data) %
alignof(value_type) != 0) {
750 offset +=
sizeof(value_type);
751 return *
reinterpret_cast<value_type *
>(data);
754template<
typename T,
byte_like Byte>
755[[
nodiscard]] std::span<copy_cv_t<T, Byte>> implicit_cast(
size_t& offset, std::span<Byte>
bytes,
size_t n)
759 static_assert(std::is_trivially_default_constructible_v<value_type>);
760 static_assert(std::is_trivially_destructible_v<value_type>);
762 if (
sizeof(value_type) * n + offset >
bytes.size()) {
765 hi_axiom_not_null(
bytes.data());
767 hilet data =
bytes.data() + offset;
769 if constexpr (
alignof(value_type) != 1) {
770 if (std::bit_cast<std::uintptr_t>(data) %
alignof(value_type) != 0) {
775 offset +=
sizeof(value_type) * n;
776 return {
reinterpret_cast<value_type *
>(data), n};
Utilities to assert and bound check.
@ truncate
After the file has been opened, truncate it.
DOXYGEN BUG.
Definition algorithm.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
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:526
constexpr Out char_cast(In rhs) noexcept
Cast a character.
Definition cast.hpp:550
constexpr OutType low_bit_cast(InType value) noexcept
Return the low half of the input value.
Definition cast.hpp:580
constexpr OutType high_bit_cast(InType value) noexcept
Return the upper half of the input value.
Definition cast.hpp:589
constexpr Out saturate_cast(In rhs) noexcept
Cast a numeric value to an integer saturating on overflow.
Definition cast.hpp:251
constexpr OutType merge_bit_cast(InType hi, InType lo) noexcept
Return the upper half of the input value.
Definition cast.hpp:636
constexpr bool can_narrow_cast(In const &rhs) noexcept
Check if a value can be casted to a narrow type.
Definition cast.hpp:276
constexpr auto three_way_compare(Lhs const &lhs, Rhs const &rhs) noexcept
Safely compare two arithmetic values to each other.
Definition compare.hpp:126
constexpr Out down_cast(In *rhs) noexcept
Cast a pointer to a class to its derived class or itself.
Definition cast.hpp:118
constexpr Out up_cast(In *rhs) noexcept
Cast a pointer to a class to its base class or itself.
Definition cast.hpp:65
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:518
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
constexpr Out wide_cast(In const &rhs) noexcept
Cast to a type which can hold all values from the input type.
Definition cast.hpp:175