HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
cast.hpp
1// Copyright Take Vos 2020.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "required.hpp"
8#include "concepts.hpp"
9#include "assert.hpp"
10#include <type_traits>
11#include <concepts>
12#include <limits>
13
14namespace tt {
15
16template<typename T>
17[[nodiscard]] constexpr T copy(T value) noexcept
18{
19 return value;
20}
21
22template<std::signed_integral OutType, std::floating_point InType>
23[[nodiscard]] constexpr OutType narrow_cast(InType value) noexcept
24{
26 return static_cast<OutType>(value);
27}
28
29template<std::signed_integral OutType, std::signed_integral InType>
30[[nodiscard]] constexpr OutType narrow_cast(InType value) noexcept
31{
32 constexpr auto smin = static_cast<long long>(std::numeric_limits<OutType>::lowest());
33 constexpr auto smax = static_cast<long long>(std::numeric_limits<OutType>::max());
34 tt_axiom(value >= smin && value <= smax);
35 return static_cast<OutType>(value);
36}
37
38template<std::signed_integral OutType, std::unsigned_integral InType>
39[[nodiscard]] constexpr OutType narrow_cast(InType value) noexcept
40{
41 constexpr auto umax = static_cast<unsigned long long>(std::numeric_limits<OutType>::max());
42 tt_axiom(value <= umax);
43 return static_cast<OutType>(value);
44}
45
46template<std::unsigned_integral OutType, std::floating_point InType>
47[[nodiscard]] constexpr OutType narrow_cast(InType value) noexcept
48{
49 tt_axiom(value >= InType{0});
50 tt_axiom(value <= std::numeric_limits<OutType>::max());
51 return static_cast<OutType>(value);
52}
53
54template<std::unsigned_integral OutType, std::signed_integral InType>
55[[nodiscard]] constexpr OutType narrow_cast(InType value) noexcept
56{
57 tt_axiom(value >= InType{0});
58 if constexpr (sizeof(OutType) < sizeof(InType)) {
59 constexpr auto smax = static_cast<long long>(std::numeric_limits<OutType>::max());
60 tt_axiom(value <= smax);
61 }
62 return static_cast<OutType>(value);
63}
64
65template<std::unsigned_integral OutType, std::unsigned_integral InType>
66[[nodiscard]] constexpr OutType narrow_cast(InType value) noexcept
67{
68 constexpr auto umax = static_cast<unsigned long long>(std::numeric_limits<OutType>::max());
69 tt_axiom(value <= umax);
70 return static_cast<OutType>(value);
71}
72
73template<std::floating_point OutType, tt::arithmetic InType>
74[[nodiscard]] constexpr OutType narrow_cast(InType value) noexcept
75{
76 return static_cast<OutType>(value);
77}
78
79template<tt::lvalue_reference BaseType, tt::derived_from<std::remove_reference_t<BaseType>> DerivedType>
80[[nodiscard]] constexpr BaseType narrow_cast(DerivedType &value) noexcept
81{
82 static_assert(
83 !std::is_const_v<DerivedType> || std::is_const_v<std::remove_reference_t<BaseType>>,
84 "narrow_cast must not cast away const");
85 return static_cast<BaseType>(value);
86}
87
88template<tt::lvalue_reference DerivedType, tt::strict_base_of<std::remove_reference_t<DerivedType>> BaseType>
89[[nodiscard]] constexpr DerivedType narrow_cast(BaseType &value) noexcept
90{
91 static_assert(
92 !std::is_const_v<BaseType> || std::is_const_v<std::remove_reference_t<DerivedType>>,
93 "narrow_cast must not cast away const");
94 tt_axiom(dynamic_cast<std::remove_reference_t<DerivedType> *>(&value) != nullptr);
95 return static_cast<DerivedType>(value);
96}
97
98template<tt::pointer BaseType, tt::derived_from<std::remove_pointer_t<BaseType>> DerivedType>
99[[nodiscard]] constexpr BaseType narrow_cast(DerivedType *value) noexcept
100{
101 static_assert(
102 !std::is_const_v<DerivedType> || std::is_const_v<std::remove_pointer_t<BaseType>>,
103 "narrow_cast must not cast away const");
104 return static_cast<BaseType>(value);
105}
106
107template<tt::pointer DerivedType, tt::strict_base_of<std::remove_pointer_t<DerivedType>> BaseType>
108[[nodiscard]] constexpr DerivedType narrow_cast(BaseType *value) noexcept
109{
110 static_assert(
111 !std::is_const_v<BaseType> || std::is_const_v<std::remove_pointer_t<DerivedType>>,
112 "narrow_cast must not cast away const");
113 tt_axiom(dynamic_cast<DerivedType>(value) != nullptr);
114 return static_cast<DerivedType>(value);
115}
116
119template<std::unsigned_integral OutType, std::unsigned_integral InType>
120[[nodiscard]] constexpr OutType low_bit_cast(InType value) noexcept
121{
122 static_assert(sizeof(OutType) * 2 == sizeof(InType), "Return value of low_bit_cast must be half the size of the input");
123 return static_cast<OutType>(value);
124}
125
128template<std::unsigned_integral OutType, std::unsigned_integral InType>
129[[nodiscard]] constexpr OutType high_bit_cast(InType value) noexcept
130{
131 static_assert(sizeof(OutType) * 2 == sizeof(InType), "Return value of high_bit_cast must be half the size of the input");
132 return static_cast<OutType>(value >> sizeof(OutType) * CHAR_BIT);
133}
134
137template<std::signed_integral OutType, std::signed_integral InType>
138[[nodiscard]] constexpr OutType low_bit_cast(InType value) noexcept
139{
140 using UInType = std::make_unsigned_t<InType>;
141 using UOutType = std::make_unsigned_t<OutType>;
142 return static_cast<OutType>(low_bit_cast<UOutType>(static_cast<UInType>(value)));
143}
144
147template<std::signed_integral OutType, std::signed_integral InType>
148[[nodiscard]] constexpr OutType high_bit_cast(InType value) noexcept
149{
150 using UInType = std::make_unsigned_t<InType>;
151 using UOutType = std::make_unsigned_t<OutType>;
152 return static_cast<OutType>(high_bit_cast<UOutType>(static_cast<UInType>(value)));
153}
154
157template<std::unsigned_integral OutType, std::signed_integral InType>
158[[nodiscard]] constexpr OutType low_bit_cast(InType value) noexcept
159{
160 using UInType = std::make_unsigned_t<InType>;
161 return low_bit_cast<OutType>(static_cast<UInType>(value));
162}
163
166template<std::unsigned_integral OutType, std::signed_integral InType>
167[[nodiscard]] constexpr OutType high_bit_cast(InType value) noexcept
168{
169 using UInType = std::make_unsigned_t<InType>;
170 return high_bit_cast<OutType>(static_cast<UInType>(value));
171}
172
175template<std::unsigned_integral OutType, std::unsigned_integral InType>
176[[nodiscard]] constexpr OutType merge_bit_cast(InType hi, InType lo) noexcept
177{
178 static_assert(sizeof(OutType) == sizeof(InType) * 2, "Return value of merge_bit_cast must be double the size of the input");
179
180 OutType r = static_cast<OutType>(hi);
181 r <<= sizeof(InType) * CHAR_BIT;
182 r |= static_cast<OutType>(lo);
183 return r;
184}
185
188template<std::signed_integral OutType, std::signed_integral InType>
189[[nodiscard]] constexpr OutType merge_bit_cast(InType hi, InType lo) noexcept
190{
191 using UInType = std::make_unsigned_t<InType>;
192 using UOutType = std::make_unsigned_t<OutType>;
193 return static_cast<OutType>(merge_bit_cast<UOutType>(static_cast<UInType>(hi), static_cast<UInType>(lo)));
194}
195
198template<std::signed_integral OutType, std::unsigned_integral InType>
199[[nodiscard]] constexpr OutType merge_bit_cast(InType hi, InType lo) noexcept
200{
201 using UOutType = std::make_unsigned_t<OutType>;
202 return narrow_cast<OutType>(merge_bit_cast<UOutType>(hi, lo));
203}
204
205} // namespace tt
T copy(T... args)
T lowest(T... args)
T max(T... args)