13#include "../macros.hpp"
16#include "concepts.hpp"
17#include "exception.hpp"
27hi_export_module(hikogui.utility.cast);
32hi_warning_ignore_msvc(26472);
37hi_warning_ignore_msvc(26467);
40hi_warning_ignore_msvc(26496);
43hi_warning_ignore_msvc(26466);
46hi_warning_ignore_msvc(26474);
48hi_warning_ignore_msvc(4702);
50hi_export
namespace hi {
inline namespace v1 {
65template<
typename Out,
typename In>
68 using out_type = std::remove_pointer_t<Out>;
70 static_assert(std::is_pointer_v<Out>,
"up_cast() Out template paramater must be a pointer if the input is a pointer.");
71 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.");
72 static_assert(std::is_base_of_v<out_type, In>,
"up_cast() may only be used to cast to a base-type.");
74 return static_cast<Out>(rhs);
87 static_assert(std::is_pointer_v<Out>,
"up_cast() Out template paramater must be a pointer.");
98template<
typename Out,
typename In>
101 using out_type = std::remove_reference_t<Out>;
103 static_assert(std::is_reference_v<Out>,
"up_cast() Out template paramater must be a reference if the input is a reference.");
104 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.");
105 static_assert(std::is_base_of_v<out_type, In>,
"up_cast() may only be used to cast to a base-type.");
107 return static_cast<Out>(rhs);
118template<
typename Out,
typename In>
121 using out_type = std::remove_pointer_t<Out>;
123 static_assert(std::is_pointer_v<Out>,
"down_cast() Out template paramater must be a pointer if the input is a pointer.");
124 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.");
125 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.");
127 if constexpr (
not std::is_base_of_v<out_type, In>) {
128 hi_axiom(rhs ==
nullptr or dynamic_cast<Out>(rhs) !=
nullptr);
130 return static_cast<Out>(rhs);
138template<
typename Out>
140 requires std::is_pointer_v<Out>
152template<
typename Out,
typename In>
155 using out_type = std::remove_reference_t<Out>;
157 static_assert(std::is_reference_v<Out>,
"down_cast() Out template paramater must be a reference if the input is a reference.");
158 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.");
159 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.");
161 if constexpr (
not std::is_base_of_v<out_type, In>) {
162 hi_axiom(
dynamic_cast<std::add_pointer_t<out_type>
>(
std::addressof(rhs)) !=
nullptr);
164 return static_cast<Out>(rhs);
175template<
typename Out, std::same_as<Out> In>
188template<std::
floating_po
int Out, std::
floating_po
int In>
190 requires(
not std::same_as<In, Out>)
194 "wide_cast() is only allowed to a floating point of the same or larger size.");
196 return static_cast<Out>(rhs);
206template<std::
integral Out, std::
integral In>
208 requires(
not std::same_as<In, Out>)
212 "wide_cast() is only allowed if the input is unsigned or if both input and output have the same signess.");
216 "wide_cast() is only allowed to an integer of the same or larger size.");
218 return static_cast<Out>(rhs);
235template<std::
floating_po
int Out, std::
integral In>
240 "wide_cast() is only allowed if the input can be represented with perfect accuracy by the floating point output type.");
242 return static_cast<Out>(rhs);
251template<std::
integral Out, arithmetic In>
254 if constexpr (std::is_floating_point_v<In>) {
265 return static_cast<Out>(rhs);
276template<
typename Out, std::same_as<Out> In>
289template<std::
floating_po
int Out, std::
floating_po
int In>
291 requires(
not std::same_as<In, Out>)
309template<std::
integral Out, std::
integral In>
311 requires(
not std::same_as<In, Out>)
348template<std::
floating_po
int Out, std::
integral In>
354 constexpr auto lowest = -
max;
356 return rhs >= lowest
and rhs <=
max;
377template<
typename Out, std::same_as<Out> In>
392template<std::
floating_po
int Out, std::
floating_po
int In>
394 requires(
not std::same_as<In, Out>)
403 return static_cast<Out>(rhs);
415template<std::
integral Out, std::
integral In>
417 requires(
not std::same_as<In, Out>)
439 return static_cast<Out>(rhs);
451template<std::
floating_po
int Out, std::
integral In>
457 constexpr auto lowest = -
max;
459 hi_axiom(rhs >= lowest
and rhs <= max);
464 hi_axiom(rhs <= max);
468 return static_cast<Out>(rhs);
471template<std::
integral Out, std::
floating_po
int In>
472[[
nodiscard]]
constexpr bool can_round_cast(
In rhs)
noexcept
503template<std::
integral Out, std::
floating_po
int In>
514template<std::
integral Out, std::
floating_po
int In>
527template<std::
integral In>
530 return static_cast<std::make_unsigned_t<In>
>(rhs);
535template<std::
integral In>
538 return static_cast<std::make_signed_t<In>
>(rhs);
543template<std::
integral Out, std::
integral In>
559template<std::
integral Out, std::
integral In>
581template<std::
integral Out>
589template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
592 static_assert(
sizeof(
OutType) * 2 ==
sizeof(
InType),
"Return value of low_bit_cast must be half the size of the input");
593 return static_cast<OutType>(value);
598template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
601 static_assert(
sizeof(
OutType) * 2 ==
sizeof(
InType),
"Return value of high_bit_cast must be half the size of the input");
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::
signed_
integral OutType, std::
signed_
integral InType>
620 using UInType = std::make_unsigned_t<InType>;
621 using UOutType = std::make_unsigned_t<OutType>;
627template<std::
unsigned_
integral OutType, std::
signed_
integral InType>
630 using UInType = std::make_unsigned_t<InType>;
636template<std::
unsigned_
integral OutType, std::
signed_
integral InType>
639 using UInType = std::make_unsigned_t<InType>;
645template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
648 static_assert(
sizeof(
OutType) ==
sizeof(
InType) * 2,
"Return value of merge_bit_cast must be double the size of the input");
658template<std::
signed_
integral OutType, std::
signed_
integral InType>
661 using UInType = std::make_unsigned_t<InType>;
662 using UOutType = std::make_unsigned_t<OutType>;
668template<std::
signed_
integral OutType, std::
unsigned_
integral InType>
671 using UOutType = std::make_unsigned_t<OutType>;
676[[
nodiscard]]
constexpr bool to_bool(T&& rhs)
noexcept
677 requires(
requires(T&& x) {
static_cast<bool>(std::forward<T>(x)); })
679 return static_cast<bool>(std::forward<T>(rhs));
696 return std::bit_cast<T>(r);
701 requires std::is_pointer_v<T>
703 return reinterpret_cast<T
>(value);
712template<
typename T,
byte_like Byte>
717 static_assert(std::is_trivially_default_constructible_v<value_type>);
718 static_assert(std::is_trivially_destructible_v<value_type>);
720 if (
sizeof(value_type) >
bytes.size()) {
723 hi_axiom_not_null(
bytes.data());
725 if constexpr (
alignof(value_type) != 1) {
726 if (std::bit_cast<std::uintptr_t>(
bytes.data()) %
alignof(value_type) != 0) {
731 return *
reinterpret_cast<value_type *
>(
bytes.data());
734template<
typename T,
byte_like Byte>
735[[
nodiscard]] std::span<copy_cv_t<T, Byte>> implicit_cast(std::span<Byte>
bytes,
size_t n)
739 static_assert(std::is_trivially_default_constructible_v<value_type>);
740 static_assert(std::is_trivially_destructible_v<value_type>);
742 if (
sizeof(value_type) * n >
bytes.size()) {
745 hi_axiom_not_null(
bytes.data());
747 if constexpr (
alignof(value_type) != 1) {
748 if (std::bit_cast<std::uintptr_t>(
bytes.data()) %
alignof(value_type) != 0) {
753 return {
reinterpret_cast<value_type *
>(
bytes.data()), n};
756template<
typename T,
byte_like Byte>
761 static_assert(std::is_trivially_default_constructible_v<value_type>);
762 static_assert(std::is_trivially_destructible_v<value_type>);
764 if (
sizeof(value_type) + offset >
bytes.size()) {
767 hi_axiom_not_null(
bytes.data());
769 auto const data =
bytes.data() + offset;
771 if constexpr (
alignof(value_type) != 1) {
772 if (std::bit_cast<std::uintptr_t>(data) %
alignof(value_type) != 0) {
777 offset +=
sizeof(value_type);
778 return *
reinterpret_cast<value_type *
>(data);
781template<
typename T,
byte_like Byte>
782[[
nodiscard]] std::span<copy_cv_t<T, Byte>> implicit_cast(
size_t& offset, std::span<Byte>
bytes,
size_t n)
786 static_assert(std::is_trivially_default_constructible_v<value_type>);
787 static_assert(std::is_trivially_destructible_v<value_type>);
789 if (
sizeof(value_type) * n + offset >
bytes.size()) {
792 hi_axiom_not_null(
bytes.data());
794 auto const data =
bytes.data() + offset;
796 if constexpr (
alignof(value_type) != 1) {
797 if (std::bit_cast<std::uintptr_t>(data) %
alignof(value_type) != 0) {
802 offset +=
sizeof(value_type) * n;
803 return {
reinterpret_cast<value_type *
>(data), n};
Utilities to assert and bound check.
Utilities for throwing exceptions and terminating the application.
@ truncate
After the file has been opened, truncate it.
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
The HikoGUI namespace.
Definition recursive_iterator.hpp:15
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:536
constexpr Out char_cast(In rhs) noexcept
Cast a character.
Definition cast.hpp:560
constexpr OutType low_bit_cast(InType value) noexcept
Return the low half of the input value.
Definition cast.hpp:590
constexpr OutType high_bit_cast(InType value) noexcept
Return the upper half of the input value.
Definition cast.hpp:599
constexpr Out saturate_cast(In rhs) noexcept
Cast a numeric value to an integer saturating on overflow.
Definition cast.hpp:252
constexpr OutType merge_bit_cast(InType hi, InType lo) noexcept
Return the upper half of the input value.
Definition cast.hpp:646
constexpr bool can_narrow_cast(In const &rhs) noexcept
Check if a value can be casted to a narrow type.
Definition cast.hpp:277
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:119
constexpr Out up_cast(In *rhs) noexcept
Cast a pointer to a class to its base class or itself.
Definition cast.hpp:66
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:528
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:378
constexpr Out wide_cast(In const &rhs) noexcept
Cast to a type which can hold all values from the input type.
Definition cast.hpp:176
constexpr T to_mask(bool v) noexcept
Create a mask from a boolean value.
Definition cast.hpp:689