HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
tagged_id.hpp
1// Copyright Take Vos 2020-2022.
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 "../macros.hpp"
8#include "fixed_string.hpp"
9#include "terminate.hpp"
10#include <limits>
11#include <typeinfo>
12#include <typeindex>
13#include <compare>
14#include <concepts>
15#include <bit>
16#include <optional>
17#include <string>
18#include <ostream>
19#include <cstddef>
20
21hi_export_module(hikogui.utility.tagged_id);
22
23hi_export namespace hi::inline v1 {
24
25template<std::unsigned_integral T, fixed_string Tag, std::size_t Max = std::numeric_limits<T>::max() - 1>
26class tagged_id {
27public:
28 static_assert(Max < std::numeric_limits<T>::max(), "Max must be at least one less than the maximum value of T");
29
30 using value_type = T;
31
32 constexpr static value_type max = Max;
33 constexpr static value_type invalid = max + 1;
34 constexpr static value_type mask = static_cast<value_type>((1ULL << std::bit_width(invalid)) - 1);
35
36 constexpr tagged_id() noexcept : value(invalid) {}
37 constexpr tagged_id(tagged_id const& other) noexcept = default;
38 constexpr tagged_id(tagged_id&& other) noexcept = default;
39 constexpr tagged_id& operator=(tagged_id const& other) noexcept = default;
40 constexpr tagged_id& operator=(tagged_id&& other) noexcept = default;
41
42 constexpr explicit tagged_id(std::integral auto rhs) noexcept : value(narrow_cast<value_type>(rhs))
43 {
44 hi_axiom(holds_invariant() and value != invalid);
45 }
46
47 constexpr tagged_id(std::nullopt_t) noexcept : value(invalid) {}
48
49 constexpr tagged_id(nullptr_t) noexcept : value(invalid) {}
50
51 constexpr tagged_id& operator=(std::integral auto rhs) noexcept
52 {
53 value = narrow_cast<value_type>(rhs);
54 hi_axiom(holds_invariant() and value != invalid);
55 return *this;
56 }
57
58 constexpr tagged_id& operator=(std::nullopt_t) noexcept
59 {
60 value = invalid;
61 return *this;
62 }
63
64 constexpr tagged_id& operator=(nullptr_t) noexcept
65 {
66 value = invalid;
67 return *this;
68 }
69
70 template<std::integral O>
71 constexpr explicit operator O() const noexcept
72 {
73 hi_axiom(value != invalid);
74 return narrow_cast<O>(value);
75 }
76
77 constexpr explicit operator bool() const noexcept
78 {
79 return value != invalid;
80 }
81
82 [[nodiscard]] constexpr value_type const& operator*() const noexcept
83 {
84 return value;
85 }
86
87 [[nodiscard]] constexpr std::size_t hash() const noexcept
88 {
89 return std::hash<value_type>{}(value);
90 }
91
92 [[nodiscard]] constexpr auto operator<=>(tagged_id const &) const noexcept = default;
93
94 [[nodiscard]] constexpr bool operator==(tagged_id const&) const noexcept = default;
95
96 [[nodiscard]] constexpr bool operator==(nullptr_t) const noexcept
97 {
98 return value == invalid;
99 }
100
101 [[nodiscard]] constexpr bool operator==(std::nullopt_t) const noexcept
102 {
103 return value == invalid;
104 }
105
106 // clang-format off
107 [[nodiscard]] constexpr bool operator==(signed char rhs) const noexcept { return value == rhs; }
108 [[nodiscard]] constexpr bool operator==(signed short rhs) const noexcept { return value == rhs; }
109 [[nodiscard]] constexpr bool operator==(signed int rhs) const noexcept { return value == rhs; }
110 [[nodiscard]] constexpr bool operator==(signed long rhs) const noexcept { return value == rhs; }
111 [[nodiscard]] constexpr bool operator==(signed long long rhs) const noexcept { return value == rhs; }
112 [[nodiscard]] constexpr bool operator==(unsigned char rhs) const noexcept { return value == rhs; }
113 [[nodiscard]] constexpr bool operator==(unsigned short rhs) const noexcept { return value == rhs; }
114 [[nodiscard]] constexpr bool operator==(unsigned int rhs) const noexcept { return value == rhs; }
115 [[nodiscard]] constexpr bool operator==(unsigned long rhs) const noexcept { return value == rhs; }
116 [[nodiscard]] constexpr bool operator==(unsigned long long rhs) const noexcept { return value == rhs; }
117 // clang-format on
118
119 [[nodiscard]] bool holds_invariant() const noexcept
120 {
121 return value <= max or value == invalid;
122 }
123
124 [[nodiscard]] friend std::string to_string(tagged_id const& rhs) noexcept
125 {
126 return std::format("{}:{}", Tag, rhs.value);
127 }
128
129 friend std::ostream& operator<<(std::ostream& lhs, tagged_id const& rhs)
130 {
131 return lhs << to_string(rhs);
132 }
133
134private:
135 value_type value;
136};
137
138} // namespace hi::inline v1
139
140hi_export template<typename T, hi::fixed_string Tag, std::size_t Max>
141struct std::hash<hi::tagged_id<T, Tag, Max>> {
142 [[nodiscard]] constexpr std::size_t operator()(hi::tagged_id<T, Tag, Max> const& rhs) const noexcept
143 {
144 return rhs.hash();
145 }
146};
Utilities for throwing exceptions and terminating the application.
The HikoGUI namespace.
Definition array_generic.hpp:20
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
Definition tagged_id.hpp:26
T operator()(T... args)