IceShard 1
A personal game engine project, with development focused on 2D/2.5D games.
Loading...
Searching...
No Matches
nvalue.hxx
Go to the documentation of this file.
1
3
4#pragma once
5#include <ice/mem.hxx>
6#include <ice/base.hxx>
7
8namespace ice
9{
10
11 struct nvalue;
12
13 namespace detail
14 {
15
18
19 // utilities
20
21 consteval auto nvalue_min_value() noexcept -> ice::detail::nvalue_base_utype;
22 consteval auto nvalue_max_value() noexcept -> ice::detail::nvalue_base_utype;
23
24 // Sanity Checks
25
26 static_assert(sizeof(ice::detail::nvalue_base_utype) == sizeof(size_t));
27 static_assert(sizeof(ice::detail::nvalue_base_stype) == sizeof(size_t));
28
29 } // namespace detail
30
31 struct ncount;
32 struct nindex;
33
34 namespace concepts
35 {
36
37 template<typename T>
38 concept NValueCompatibleType = (std::is_arithmetic_v<T> and not std::is_floating_point_v<T>)
39 or std::is_same_v<T, ice::nvalue>
40 or std::is_same_v<T, ice::ncount>
41 or std::is_same_v<T, ice::nindex>;
42
43 } // namespace concepts
44
45#if ISP_ARCH_BITS == 64
46#define ICE_NVALUE_VALUE_MAX 0x0000'7fff'ffff'ffff
47#define ICE_NVALUE_VALUE_FIELD_BITS : 48
48#define ICE_NVALUE_WIDTH_FIELD_BITS : 16
49
50 static_assert(sizeof(ice::detail::nvalue_base_utype) == 8);
51 static_assert(sizeof(ice::detail::nvalue_base_stype) == 8);
52#elif ISP_ARCH_BITS == 32
53#define ICE_NVALUE_VALUE_MAX 0xffff'ffff
54#define ICE_NVALUE_VALUE_FIELD_BITS
55#define ICE_NVALUE_WIDTH_FIELD_BITS
56
57 static_assert(sizeof(ice::detail::nvalue_base_utype) == 4);
58 static_assert(sizeof(ice::detail::nvalue_base_stype) == 4);
59#else
60# error Unhandled architecture!
61#endif
62
64 {
65 return 0;
66 }
67
69 {
70 return ICE_NVALUE_VALUE_MAX;
71 }
72
73 struct nvalue
74 {
77
78 // NOTE: The '_width' needs to be defined BEFORE value. So the high-bits (that are accessed less frequently) contain
79 // the '_width' field and the low-bits contain the '_value' field.
80 // This is to ensure that the compiler does not need to shift the '_value' part every time an operation is done.
83
84 // Checks if the value is valid. (_width != 0)
85 template<typename Self>
86 constexpr bool is_valid(this Self self) noexcept { return static_cast<bool>(self._width); }
87
88 template<typename Self>
89 constexpr auto value_or(this Self self, ice::concepts::NValueCompatibleType auto fallback) noexcept
90 {
91 return self.is_valid() ? static_cast<std::remove_reference_t<decltype(fallback)>>(self.native()) : fallback;
92 }
93
94 template<typename Self>
95 constexpr auto min_value_or(
96 this Self self,
99 ) noexcept
100 {
101 using ResultType = std::remove_reference_t<decltype(fallback)>;
102
103 ResultType const second_value = static_cast<ResultType>(other);
104 return self.is_valid() ? ice::min<ResultType>(static_cast<ResultType>(self.native()), second_value) : fallback;
105 }
106
107 // NOTE: In most cases we will use '_width' as a validation field instead of actually using it's value.
108 // I may come in handy for some operations (ncount -> usize) but it's purpose is to define a concrete 'invalid' state.
109 constexpr auto native() const noexcept { return static_cast<base_type>(_value * (_width != 0)); }
110 constexpr auto internal() const noexcept { return static_cast<base_signed_type>(_value * (_width != 0)); }
111 constexpr auto u8() const noexcept { return static_cast<ice::u8>(native()); }
112 constexpr auto u16() const noexcept { return static_cast<ice::u16>(native()); }
113 constexpr auto u32() const noexcept { return static_cast<ice::u32>(native()); }
114 constexpr auto u64() const noexcept { return static_cast<ice::u64>(native()); }
115
116 // Allow 'nvalue' types collaps to the 'base_type'
117#if ISP_WEBAPP || ISP_UNIX
118 // NOTE: We would like to capture us with a 'Self' value but on WebAsm this results in invalid codegen.
119 constexpr operator base_type() const noexcept { return this->native(); }
120#else
121 constexpr operator base_type(this nvalue self) noexcept { return self.native(); }
122#endif
123
124 // Equality is has two cases:
125 // > when deriving from 'nvalue':
126 // - both sides need to be either invalid or valid and have the same '_value'.
127 // - the '_width' can be different.
128 // > when comparing to a regular number:
129 // - the 'nvalue' needs to be valid and the number has the the same value as '_value'
130 template<typename Self>
131 constexpr bool operator==(this Self self, ice::concepts::NValueCompatibleType auto other) noexcept;
132
133 template<typename Self>
134 constexpr auto operator<=>(
135 this Self self, ice::concepts::NValueCompatibleType auto other
136 ) noexcept -> std::strong_ordering;
137
138 // Increments
139 template<typename Self>
140 constexpr auto operator++(this Self& self) noexcept -> Self&;
141
142 template<typename Self>
143 constexpr auto operator++(this Self& self, int) noexcept -> Self;
144
145 template<typename Self>
146 constexpr auto operator--(this Self& self) noexcept -> Self&;
147
148 template<typename Self>
149 constexpr auto operator--(this Self& self, int) noexcept -> Self;
150
151 // Arithmetics
152 template<typename Self>
153 constexpr auto operator+(this Self self, ice::concepts::NValueCompatibleType auto other) noexcept -> Self;
154
155 template<typename Self>
156 constexpr auto operator-(this Self self, ice::concepts::NValueCompatibleType auto other) noexcept -> Self;
157
158 template<typename Self>
159 constexpr auto operator*(this Self self, ice::concepts::NValueCompatibleType auto other) noexcept -> Self;
160
161 template<typename Self>
162 constexpr auto operator/(this Self self, ice::concepts::NValueCompatibleType auto other) noexcept -> Self;
163
164 template<typename Self>
165 constexpr auto operator+=(this Self& self, ice::concepts::NValueCompatibleType auto other) noexcept -> Self&;
166
167 template<typename Self>
168 constexpr auto operator-=(this Self& self, ice::concepts::NValueCompatibleType auto other) noexcept -> Self&;
169
170 template<typename Self>
171 constexpr auto operator*=(this Self& self, ice::concepts::NValueCompatibleType auto other) noexcept -> Self&;
172
173 template<typename Self>
174 constexpr auto operator/=(this Self& self, ice::concepts::NValueCompatibleType auto other) noexcept -> Self&;
175 };
176
177 template<typename Self>
178 inline constexpr bool nvalue::operator==(
179 this Self self, ice::concepts::NValueCompatibleType auto other
180 ) noexcept
181 {
182 if constexpr (std::is_base_of_v<ice::nvalue, decltype(other)>)
183 {
184#if 0 // The naive approach (contains jump instructions even after optimization)
185 return self.is_valid() == other.is_valid() && (self.is_valid() == false || self.native() == other.native());
186#else // The mathematical approach (jump instructions are not present, branch predictor is happy)
187 return static_cast<bool>((self._width * other._width) * (self._value == other._value) + ((self._width + other._width) == 0));
188#endif
189 }
190 else
191 {
192 return self.native() == other;
193 }
194 }
195
196 // (nvalue{W, V} == nvalue{W, V});
197 static_assert(nvalue{0, 0} == nvalue{0, 0}, "Invalid values are equal to each other");
198 static_assert(nvalue{0, 1} == nvalue{0, 1}, "Invalid values are equal to each other ('_value' is not '0')");
199 static_assert(nvalue{1, 0} == nvalue{1, 0}, "Valid values are equal if '_value' is the same.");
200 static_assert(nvalue{1, 4} == nvalue{2, 4}, "Valid values are equal if '_value' is the same. ('_width' differs)");
201 static_assert(nvalue{1, 0} != nvalue{0, 0}, "Valid values are not equal to invalid values. ('_value' is '0' in both)");
202 static_assert(nvalue{1, 0} != nvalue{1, 1}, "Valid values are not equal if '_value' differs ('_width' is '1' in both)");
203 static_assert(nvalue{1, 1} != nvalue{2, 2}, "Valid values are not equal if '_value' differs ('_width' and '_value' differs)");
204
205 template<typename Self>
206 inline constexpr auto nvalue::operator<=>(
207 this Self self, ice::concepts::NValueCompatibleType auto other
208 ) noexcept -> std::strong_ordering
209 {
210 if constexpr (std::is_base_of_v<ice::nvalue, decltype(other)>)
211 {
212 return self.internal() <=> other.internal();
213 }
214 else
215 {
216 return self.internal() <=> static_cast<ice::detail::nvalue_base_stype>(other);
217 }
218 }
219
220 // Increments
221 template<typename Self>
222 constexpr auto nvalue::operator++(this Self& self) noexcept -> Self&
223 {
224 self._value += 1;
225 return self;
226 }
227
228 template<typename Self>
229 constexpr auto nvalue::operator++(this Self& self, int) noexcept -> Self
230 {
231 const Self old = self;
232 self._value += 1;
233 return old;
234 }
235
236 template<typename Self>
237 constexpr auto nvalue::operator--(this Self& self) noexcept -> Self&
238 {
239 self._value -= 1;
240 return self;
241 }
242
243 template<typename Self>
244 constexpr auto nvalue::operator--(this Self& self, int) noexcept -> Self
245 {
246 const Self old = self;
247 self._value -= 1;
248 return old;
249 }
250
251 // Arithmetics
252 template<typename Self>
253 inline constexpr auto nvalue::operator+(
254 this Self self, ice::concepts::NValueCompatibleType auto other
255 ) noexcept -> Self
256 {
257 return Self{ ice::nvalue{ self._width, self._value + static_cast<ice::detail::nvalue_base_stype>(other) } };
258 }
259
260 template<typename Self>
261 inline constexpr auto nvalue::operator-(
262 this Self self, ice::concepts::NValueCompatibleType auto other
263 ) noexcept -> Self
264 {
265 return Self{ ice::nvalue{ self._width, self._value - static_cast<ice::detail::nvalue_base_stype>(other) } };
266 }
267
268 template<typename Self>
269 inline constexpr auto nvalue::operator*(
270 this Self self, ice::concepts::NValueCompatibleType auto other
271 ) noexcept -> Self
272 {
273 return Self{ ice::nvalue{ self._width, self._value * static_cast<ice::detail::nvalue_base_stype>(other) } };
274 }
275
276 template<typename Self>
277 inline constexpr auto nvalue::operator/(
278 this Self self, ice::concepts::NValueCompatibleType auto other
279 ) noexcept -> Self
280 {
281 return Self{ ice::nvalue{ self._width, self._value / static_cast<ice::detail::nvalue_base_stype>(other) } };
282 }
283
284 template<typename Self>
285 inline constexpr auto nvalue::operator+=(
286 this Self& self, ice::concepts::NValueCompatibleType auto other
287 ) noexcept -> Self&
288 {
289 self._value += static_cast<ice::detail::nvalue_base_stype>(other);
290 return self;
291 }
292
293 template<typename Self>
294 inline constexpr auto nvalue::operator-=(
295 this Self& self, ice::concepts::NValueCompatibleType auto other
296 ) noexcept -> Self&
297 {
298 self._value -= static_cast<ice::detail::nvalue_base_stype>(other);
299 return self;
300 }
301
302 template<typename Self>
303 inline constexpr auto nvalue::operator*=(
304 this Self& self, ice::concepts::NValueCompatibleType auto other
305 ) noexcept -> Self&
306 {
307 self._value *= static_cast<ice::detail::nvalue_base_stype>(other);
308 return self;
309 }
310
311 template<typename Self>
312 inline constexpr auto nvalue::operator/=(
313 this Self& self, ice::concepts::NValueCompatibleType auto other
314 ) noexcept -> Self&
315 {
316 self._value /= static_cast<ice::detail::nvalue_base_stype>(other);
317 return self;
318 }
319
320} // namespace ice
Definition nvalue.hxx:38
Definition container_concepts.hxx:12
Definition hashmap_details.hxx:13
consteval auto nvalue_min_value() noexcept -> ice::detail::nvalue_base_utype
Definition nvalue.hxx:63
consteval auto nvalue_max_value() noexcept -> ice::detail::nvalue_base_utype
Definition nvalue.hxx:68
ice::usize::base_type nvalue_base_utype
Definition nvalue.hxx:16
ice::isize::base_type nvalue_base_stype
Definition nvalue.hxx:17
constexpr auto min(arr_t< Size, T > left, arr_t< Size, U > right) noexcept -> arr_t< Size, T >
Definition array_operations.hxx:60
SPDX-License-Identifier: MIT.
Definition array.hxx:12
std::uint64_t u64
Definition types.hxx:27
std::uint16_t u16
Definition types.hxx:25
std::uint32_t u32
Definition types.hxx:26
std::uint8_t u8
Definition types.hxx:24
std::conditional_t< ice::build::is_x64, ice::i64, ice::i32 > base_type
Definition mem_size_types.hxx:16
Definition ncount.hxx:14
constexpr bool operator==(this ncount self, ncount_invalid_t) noexcept
Definition ncount.hxx:53
Definition nindex.hxx:13
Definition nvalue.hxx:74
ice::detail::nvalue_base_stype base_signed_type
Definition nvalue.hxx:76
constexpr auto operator/=(this Self &self, ice::concepts::NValueCompatibleType auto other) noexcept -> Self &
Definition nvalue.hxx:312
constexpr auto operator--(this Self &self) noexcept -> Self &
Definition nvalue.hxx:237
constexpr auto u16() const noexcept
Definition nvalue.hxx:112
constexpr auto min_value_or(this Self self, ice::concepts::NValueCompatibleType auto other, ice::concepts::NValueCompatibleType auto fallback) noexcept
Definition nvalue.hxx:95
constexpr auto operator-=(this Self &self, ice::concepts::NValueCompatibleType auto other) noexcept -> Self &
Definition nvalue.hxx:294
constexpr auto u32() const noexcept
Definition nvalue.hxx:113
constexpr auto operator/(this Self self, ice::concepts::NValueCompatibleType auto other) noexcept -> Self
Definition nvalue.hxx:277
constexpr auto operator-(this Self self, ice::concepts::NValueCompatibleType auto other) noexcept -> Self
Definition nvalue.hxx:261
constexpr auto operator++(this Self &self) noexcept -> Self &
Definition nvalue.hxx:222
constexpr auto internal() const noexcept
Definition nvalue.hxx:110
constexpr auto u64() const noexcept
Definition nvalue.hxx:114
constexpr auto operator<=>(this Self self, ice::concepts::NValueCompatibleType auto other) noexcept -> std::strong_ordering
Definition nvalue.hxx:206
constexpr auto operator+=(this Self &self, ice::concepts::NValueCompatibleType auto other) noexcept -> Self &
Definition nvalue.hxx:285
constexpr auto u8() const noexcept
Definition nvalue.hxx:111
constexpr bool operator==(this Self self, ice::concepts::NValueCompatibleType auto other) noexcept
Definition nvalue.hxx:178
ice::detail::nvalue_base_utype _width ICE_NVALUE_WIDTH_FIELD_BITS
Definition nvalue.hxx:81
constexpr auto operator*=(this Self &self, ice::concepts::NValueCompatibleType auto other) noexcept -> Self &
Definition nvalue.hxx:303
constexpr auto operator*(this Self self, ice::concepts::NValueCompatibleType auto other) noexcept -> Self
Definition nvalue.hxx:269
constexpr bool is_valid(this Self self) noexcept
Definition nvalue.hxx:86
constexpr auto native() const noexcept
Definition nvalue.hxx:109
constexpr auto operator+(this Self self, ice::concepts::NValueCompatibleType auto other) noexcept -> Self
Definition nvalue.hxx:253
ice::detail::nvalue_base_utype base_type
Definition nvalue.hxx:75
constexpr auto value_or(this Self self, ice::concepts::NValueCompatibleType auto fallback) noexcept
Definition nvalue.hxx:89
ice::detail::nvalue_base_stype _value ICE_NVALUE_VALUE_FIELD_BITS
Definition nvalue.hxx:82
std::size_t base_type
Definition mem_size_types.hxx:28