header_utils
Loading...
Searching...
No Matches
named.h
1
4
5#pragma once
6
7#include <algorithm>
8#include <cmath>
9
10namespace ghassanpl
11{
12 namespace detail
13 {
14 template<size_t N>
15 struct FixedString
16 {
17 constexpr FixedString(char const (&s)[N]) { std::copy_n(s, N, this->elems); }
18 constexpr std::strong_ordering operator<=>(FixedString const&) const = default;
19 char elems[N];
20 };
21 }
22
27 namespace traits
28 {
29 // TODO: not_equality_comparable
30 // TODO: not_orderable
31 // TODO: multipliable, multipliable_by_scalar<T>
32 // TODO: divisible, divisible_by_scalar<T>
33 // TODO: We should probably get rid of the <trait>::applies_to var, because we can explicitly test its requirements in `named`
34
36 struct addable {
37 template <typename SELF_TYPE, typename OTHERS_SELF_TYPE = SELF_TYPE>
38 //static constexpr bool applies_to = requires (SELF_TYPE::base_type a, std::remove_cvref_t<OTHERS_SELF_TYPE>::base_type b) { { a + b } -> std::convertible_to<SELF_TYPE::base_type>; };
39 static constexpr bool applies_to = true;
40 };
41
43 struct subtractable {
44 template <typename SELF_TYPE, typename OTHERS_SELF_TYPE = SELF_TYPE>
45 //static constexpr bool applies_to = requires (SELF_TYPE::base_type a, std::remove_cvref_t<OTHERS_SELF_TYPE>::base_type b) { { a - b } -> std::convertible_to<SELF_TYPE::base_type>; };
46 static constexpr bool applies_to = true;
47 };
48
51 template <typename SELF_TYPE>
52 static constexpr bool applies_to = true;
53 };
54
57 struct location { template <typename SELF_TYPE> static constexpr bool applies_to = true; };
58
62 struct displacement { template <typename SELF_TYPE> static constexpr bool applies_to = true; };
63
65 struct implicitly_convertible { template <typename SELF_TYPE> static constexpr bool applies_to = true; };
66
68 struct implicitly_constructible { template <typename SELF_TYPE> static constexpr bool applies_to = true; };
69
71 template <typename T>
72 struct implicitly_constructible_from { using type = T; template <typename SELF_TYPE> static constexpr bool applies_to = true; };
73
75 template <typename LOCATION_NAMED_TYPE>
77 using location_type = LOCATION_NAMED_TYPE;
78 template <typename SELF_TYPE>
79 static constexpr bool applies_to = std::same_as<typename std::remove_cvref_t<LOCATION_NAMED_TYPE>::base_type, typename SELF_TYPE::base_type>;
80 };
81
83 template <typename DISPLACEMENT_NAMED_TYPE>
85 using displacement_type = DISPLACEMENT_NAMED_TYPE;
86 template <typename SELF_TYPE>
87 static constexpr bool applies_to = std::same_as<typename std::remove_cvref_t<DISPLACEMENT_NAMED_TYPE>::base_type, typename SELF_TYPE::base_type>;
88 };
89
91 template <typename FROM, typename CONVERTOR>
93 {
94 using from = FROM;
95 using convertor = CONVERTOR;
96 };
97
98 template <typename DISPLACEMENT_TYPE, typename LOCATION_TYPE>
99 concept named_is_displacement_of =
100 is_displacement_of<LOCATION_TYPE>::template applies_to<std::remove_cvref_t<DISPLACEMENT_TYPE>> ||
101 is_location_of<DISPLACEMENT_TYPE>::template applies_to<std::remove_cvref_t<LOCATION_TYPE>>
102 ;
103
104 template <typename NAMED_TYPE, typename TRAIT_TYPE>
105 concept applies_to = std::remove_cvref_t<NAMED_TYPE>::template has_trait<std::remove_cvref_t<TRAIT_TYPE>>;
106 }
108
113
131 template <typename T, detail::FixedString PARAMETER, typename... TRAITS>
132 struct named
133 {
136 using addable = traits::addable;
137 using subtractable = traits::subtractable;
138 using location = traits::location;
139 using displacement = traits::displacement;
141
143 using base_type = T;
144
145 using self_type = named<T, PARAMETER, TRAITS...>;
146 static constexpr detail::FixedString name = PARAMETER;
147
148 private:
149
150 template <typename... TYPES>
151 struct type_pack {};
152
153 template <template <typename...> typename TRAIT_TYPE, typename... REST>
154 static constexpr auto find_trait_type_impl(TRAIT_TYPE<REST...>)
155 {
156 return std::type_identity<std::remove_cvref_t<TRAIT_TYPE<REST...>>>{};
157 }
158 template <template <typename...> typename TRAIT_TYPE, typename... REST>
159 static constexpr auto find_trait_type_impl(...)
160 {
161 return std::type_identity<void>{};
162 }
163
164 template <template <typename...> typename TRAIT_TYPE, typename GIVEN_PACK, typename... REST>
165 static constexpr auto find_trait_type_impl(GIVEN_PACK, TRAIT_TYPE<REST...>)
166 {
167 return []<typename U, typename... GIVEN_TYPES>(type_pack<GIVEN_TYPES...>, U) {
168 return [] <typename... SOME>(TRAIT_TYPE<GIVEN_TYPES..., SOME...>) {
169 return find_trait_type_impl(TRAIT_TYPE<GIVEN_TYPES..., SOME...>{});
170 }(U{});
171 }(GIVEN_PACK{}, TRAIT_TYPE<REST...>{});
172 }
173
174 template <template <typename...> typename TRAIT_TYPE, typename GIVEN_PACK, typename FIRST_TRAIT, typename... REST>
175 static constexpr auto find_trait_type_traits(FIRST_TRAIT trait, REST... traits)
176 {
177 using type_candidate = std::remove_cvref_t<typename decltype(find_trait_type_impl<TRAIT_TYPE>(GIVEN_PACK{}, trait))::type > ;
178 if constexpr (std::is_same_v<type_candidate, void>)
179 return find_trait_type_traits<TRAIT_TYPE, GIVEN_PACK>(traits...);
180 else
181 return std::type_identity<type_candidate>{};
182 }
183
184 template <template <typename...> typename TRAIT_TYPE, typename... GIVEN>
185 static constexpr auto find_trait_type_traits() { return std::type_identity<void>{}; }
186
187 template <template <typename...> typename TRAIT_TYPE, typename... GIVEN>
188 static constexpr auto find_trait_type()
189 {
190 return find_trait_type_traits<TRAIT_TYPE, type_pack<GIVEN...>>(TRAITS{}...);
191 }
192
193 template <template <typename...> typename TRAIT_TYPE, typename... GIVEN>
194 using concrete_trait_type_of = typename decltype(find_trait_type<TRAIT_TYPE, GIVEN...>())::type;
195
196 static constexpr auto find_displacement_type()
197 {
198 using trait = concrete_trait_type_of<traits::is_location_of>;
199 if constexpr (std::is_same_v<trait, void>)
200 return std::type_identity<void>{};
201 else
202 return std::type_identity<typename trait::displacement_type>{};
203 }
204
205 public:
206
207 template <typename TRAIT, typename... OTHER>
208 static constexpr bool has_trait = (std::is_same_v<TRAIT, TRAITS> || ...) && TRAIT::template applies_to<self_type, OTHER...>;
209
211 using displacement_type = typename decltype(find_displacement_type())::type;
212
213 T value{};
214
215 template <typename... ARGS>
216 requires std::constructible_from<T, ARGS...>
217 constexpr explicit named(ARGS&&... args) noexcept(std::is_nothrow_constructible_v<T, ARGS...>) : value(std::forward<ARGS>(args)...) {}
218
219 template <typename U>
220 requires has_trait<traits::implicitly_constructible> && std::is_same_v<std::remove_cvref_t<U>, T>
221 constexpr named(U&& arg) noexcept(std::is_nothrow_move_constructible_v<T>)
222 : value(std::forward<U>(arg))
223 {
224 }
225
226 template <typename U>
227 requires has_trait<traits::implicitly_constructible_from<U>>
228 constexpr named(U&& arg) noexcept(std::is_nothrow_move_constructible_v<T>)
229 : value((T)std::forward<U>(arg))
230 {
231 }
232
233 template <typename U>
234 requires (!std::is_same_v<concrete_trait_type_of<traits::constructible_using, std::remove_cvref_t<U>>, void>)
235 constexpr named(U&& arg) noexcept(std::is_nothrow_move_constructible_v<T>)
236 : value(typename concrete_trait_type_of<traits::constructible_using, std::remove_cvref_t<U>>::convertor{}(arg))
237 {
238 }
239
240 constexpr named() noexcept(std::is_nothrow_default_constructible_v<T>) = default;
241 constexpr named(named const&) noexcept(std::is_nothrow_copy_constructible_v<T>) = default;
242 constexpr named(named&&) noexcept(std::is_nothrow_move_constructible_v<T>) = default;
243 constexpr named& operator=(named const&) noexcept(std::is_nothrow_copy_assignable_v<T>) = default;
244 constexpr named& operator=(named&&) noexcept(std::is_nothrow_move_assignable_v<T>) = default;
245
246 template <typename U>
247 requires requires(U&& val) { { named_cast<self_type>(std::forward<U>(val)) } -> std::same_as<self_type>; }
248 constexpr named(U&& arg)
249 : named(named_cast<self_type>(std::forward<U>(arg)))
250 {
251
252 }
253
254 constexpr T& operator*() & noexcept { return value; }
255 constexpr T const& operator*() const & noexcept { return value; }
256 constexpr T operator*() && noexcept { return std::move(value); }
257
258 constexpr T* operator->() noexcept { return &value; }
259 constexpr T const* operator->() const noexcept { return &value; }
260
261 constexpr T& get() & noexcept { return value; }
262 constexpr T const& get() const& noexcept { return value; }
263 constexpr T get() && noexcept { return std::move(value); }
264
265 template <typename U>
266 constexpr U as() noexcept { return static_cast<U>(value); }
267
268 constexpr auto drop() noexcept(std::is_nothrow_move_constructible_v<T>) { return std::move(value); }
269
270 template <typename U, detail::FixedString OTHER_PARAMETER, typename... OTHER_CAPABILITIES>
271 requires requires(self_type const& self) { { named_cast<named<U, OTHER_PARAMETER, OTHER_CAPABILITIES...>>(self) } -> std::same_as<named<U, OTHER_PARAMETER, OTHER_CAPABILITIES...>>; }
272 constexpr operator named<U, OTHER_PARAMETER, OTHER_CAPABILITIES...>() const
273 {
274 return named_cast<named<U, OTHER_PARAMETER, OTHER_CAPABILITIES...>>(*this);
275 }
276
277 template <typename U>
278 requires requires(self_type const& self) { { named_cast<U>(self) } -> std::same_as<U>; }
279 constexpr explicit operator U() const
280 {
281 return named_cast<U>(*this);
282 }
283
284 constexpr explicit operator bool() const noexcept { return value; }
285 constexpr operator base_type() const noexcept requires has_trait<traits::implicitly_convertible> { return value; }
286
287 constexpr auto operator<=>(named const&) const = default;
288
289 template <typename U>
290 constexpr auto operator<=>(U const& b) const { return value <=> b; }
291 template <typename U>
292 constexpr bool operator==(U const& b) const { return value == b; }
293 //friend constexpr auto operator ==(T const& a, named const& b) { return a == b.value; }
294
295 constexpr named& operator++()
296 requires has_trait<traits::incrementable>
297 {
298 ++this->value;
299 return *this;
300 }
301
302 constexpr auto operator+(self_type const& val) const // TODO: these should be forwarding references
303 requires has_trait<displacement> || has_trait<addable>
304 {
305 return self_type{ this->value + val.value };
306 }
307
308 constexpr auto operator-() const
309 requires has_trait<displacement>
310 {
311 return self_type{ -this->value };
312 }
313
314 constexpr auto operator+() const
315 requires has_trait<displacement>
316 {
317 return self_type{ +this->value };
318 }
319
320 constexpr auto& operator+=(self_type const& val) // TODO: these should be forwarding references
321 requires has_trait<displacement> || has_trait<addable>
322 {
323 this->value += val.value;
324 return *this;
325 }
326
327
328 friend constexpr auto operator-(self_type const& other, self_type const& self)
329 requires (has_trait<displacement> || has_trait<subtractable>) && (!has_trait<location>)
330 {
331 return self_type{ other.value - self.value };
332 }
333
334 constexpr auto operator-(self_type const& val) const
335 requires (has_trait<location>) && (!std::same_as<displacement_type, void>)
336 {
337 return displacement_type{ this->value - val.value };
338 }
339
341 template <typename LOCATION_TYPE>
342 constexpr auto operator+(LOCATION_TYPE&& val) const
343 requires
344 (has_trait<displacement>) &&
345 (traits::applies_to<LOCATION_TYPE, location>) &&
346 (traits::named_is_displacement_of<self_type, LOCATION_TYPE>) &&
347 (addable::applies_to<self_type, LOCATION_TYPE>)
348 {
349 return std::remove_cvref_t<LOCATION_TYPE>{ this->value + std::forward<LOCATION_TYPE>(val).value };
350 }
351
353 template <typename DISPLACEMENT_TYPE>
354 constexpr auto operator+(DISPLACEMENT_TYPE&& val) const
355 requires
356 (has_trait<location>) &&
357 (traits::applies_to<DISPLACEMENT_TYPE, displacement>) &&
358 (traits::named_is_displacement_of<DISPLACEMENT_TYPE, self_type>) &&
359 (addable::applies_to<self_type, DISPLACEMENT_TYPE>)
360 {
361 return self_type{ this->value + std::forward<DISPLACEMENT_TYPE>(val).value };
362 }
363
364 template <typename U>
365 constexpr auto operator*(U&& val) const
366 requires has_trait<displacement> && std::constructible_from<T, decltype(std::declval<T>() * std::declval<U>())>
367 {
368 return self_type{ this->value * std::forward<U>(val) };
369 }
370
371 template <typename U>
372 friend constexpr auto operator*(U&& val, named self)
373 requires has_trait<displacement> && std::constructible_from<T, decltype(std::declval<T>() * std::declval<U>())>
374 {
375 return self_type{ std::forward<U>(val) * self.value};
376 }
377
378 template <typename U>
379 constexpr auto operator/(U&& val) const
380 requires has_trait<displacement> && std::constructible_from<T, decltype(std::declval<T>() / std::declval<U>())>
381 {
382 return self_type{ this->value / std::forward<U>(val) };
383 }
384
385 constexpr auto operator/(self_type const& val) const
386 requires has_trait<displacement>
387 {
388 return this->value / val.value;
389 }
390
391 private:
392
393 };
394
396#define ghassanpl_named_string_literal(named_name, suffix) \
397 inline named_name operator "" suffix(const char* str, std::size_t len) { \
398 return named_name{named_name::base_type{str,len}}; \
399 }
400
402#define ghassanpl_named_integer_literal(named_name, suffix) \
403 inline named_name operator "" suffix(unsigned long long int val) { \
404 return named_name{named_name::base_type(val)}; \
405 }
406
408#define ghassanpl_named_float_literal(named_name, suffix) \
409 inline named_name operator "" suffix(long double val) { \
410 return named_name{named_name::base_type(val)}; \
411 }
412
414
415 static_assert(std::is_trivially_copyable_v<named<int, "int">> == std::is_trivially_copyable_v<int>);
416
417 namespace detail {
418 template <typename U, ::ghassanpl::detail::FixedString OTHER_PARAMETER, typename... OTHER_CAPABILITIES>
419 static constexpr bool is_named_impl(std::type_identity<named<U, OTHER_PARAMETER, OTHER_CAPABILITIES...>>) { return true; }
420 static constexpr bool is_named_impl(...) { return false; }
421 }
422 template <typename OTHER>
423 static constexpr bool is_named_v = ::ghassanpl::detail::is_named_impl(std::type_identity<std::remove_cvref_t<OTHER>>{});
424
425
426 template <typename T, detail::FixedString PARAMETER, typename STRINGIFIER>
427 auto stringify(STRINGIFIER& str, named<T, PARAMETER> const& val)
428 {
429 return str(val.value);
430 }
431
432 template <typename ALPHA, typename T, detail::FixedString PARAMETER, typename... TRAITS>
433 auto lerp(named<T, PARAMETER, TRAITS...> const& value_a, named<T, PARAMETER, TRAITS...> const& value_b, ALPHA&& alpha)
434 {
435 using std::lerp;
436 return named<T, PARAMETER, TRAITS...>{ lerp(value_a.value, value_b.value, std::forward<ALPHA>(alpha)) };
437 }
438
439}
Alternative to named_cast, as a trait.
Definition named.h:93
The below code is based on Sun's libm library code, which is licensed under the following license:
Primary namespace for everything in this library.
Definition align+rec2.h:10
Used to create a strong typedef of T.
Definition named.h:133
typename decltype(find_displacement_type())::type displacement_type
Definition named.h:211
constexpr auto operator+(LOCATION_TYPE &&val) const
If we're a displacement, we can be added to a location.
Definition named.h:342
constexpr auto operator+(DISPLACEMENT_TYPE &&val) const
If we're a location, we can be added to a displacement.
Definition named.h:354
Specifies that the named type can be addable to itself.
Definition named.h:36
This trait implies the named type is an linear type, that is, a type that has the addition operator d...
Definition named.h:62
Specifies that the named type can be implicitly constructible from another type.
Definition named.h:72
Specifies that the named type can be implicitly constructible from its base type.
Definition named.h:68
Specifies that the named type can be implicitly convertible from its base type.
Definition named.h:65
Makes the named incrementable.
Definition named.h:50
Used in conjuction with traits::displacement, specifies which location type this is a displacement of...
Definition named.h:76
Used in conjuction with traits::location, specifies which displacement type this is a location of.
Definition named.h:84
This trait implies the named type is an affine type, that is, a type that does not have the addition ...
Definition named.h:57
Specifies that the named type can be subtractable from itself.
Definition named.h:43