OpenTTD Source  20240917-master-g9ab0a47812
strong_typedef_type.hpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
10 #ifndef STRONG_TYPEDEF_TYPE_HPP
11 #define STRONG_TYPEDEF_TYPE_HPP
12 
13 #include "../3rdparty/fmt/format.h"
14 
17 
18 namespace StrongType {
22  struct Compare {
23  template <typename TType, typename TBaseType>
24  struct mixin {
25  friend constexpr bool operator ==(const TType &lhs, const TType &rhs) { return lhs.value == rhs.value; }
26  friend constexpr bool operator ==(const TType &lhs, const TBaseType &rhs) { return lhs.value == rhs; }
27 
28  friend constexpr bool operator !=(const TType &lhs, const TType &rhs) { return lhs.value != rhs.value; }
29  friend constexpr bool operator !=(const TType &lhs, const TBaseType &rhs) { return lhs.value != rhs; }
30 
31  friend constexpr bool operator <=(const TType &lhs, const TType &rhs) { return lhs.value <= rhs.value; }
32  friend constexpr bool operator <=(const TType &lhs, const TBaseType &rhs) { return lhs.value <= rhs; }
33 
34  friend constexpr bool operator <(const TType &lhs, const TType &rhs) { return lhs.value < rhs.value; }
35  friend constexpr bool operator <(const TType &lhs, const TBaseType &rhs) { return lhs.value < rhs; }
36 
37  friend constexpr bool operator >=(const TType &lhs, const TType &rhs) { return lhs.value >= rhs.value; }
38  friend constexpr bool operator >=(const TType &lhs, const TBaseType &rhs) { return lhs.value >= rhs; }
39 
40  friend constexpr bool operator >(const TType &lhs, const TType &rhs) { return lhs.value > rhs.value; }
41  friend constexpr bool operator >(const TType &lhs, const TBaseType &rhs) { return lhs.value > rhs; }
42  };
43  };
44 
52  struct Integer {
53  template <typename TType, typename TBaseType>
54  struct mixin {
55  friend constexpr TType &operator ++(TType &lhs) { lhs.value++; return lhs; }
56  friend constexpr TType &operator --(TType &lhs) { lhs.value--; return lhs; }
57  friend constexpr TType operator ++(TType &lhs, int) { TType res = lhs; lhs.value++; return res; }
58  friend constexpr TType operator --(TType &lhs, int) { TType res = lhs; lhs.value--; return res; }
59 
60  friend constexpr TType &operator +=(TType &lhs, const TType &rhs) { lhs.value += rhs.value; return lhs; }
61  friend constexpr TType operator +(const TType &lhs, const TType &rhs) { return TType{ lhs.value + rhs.value }; }
62  friend constexpr TType operator +(const TType &lhs, const TBaseType &rhs) { return TType{ lhs.value + rhs }; }
63 
64  friend constexpr TType &operator -=(TType &lhs, const TType &rhs) { lhs.value -= rhs.value; return lhs; }
65  friend constexpr TType operator -(const TType &lhs, const TType &rhs) { return TType{ lhs.value - rhs.value }; }
66  friend constexpr TType operator -(const TType &lhs, const TBaseType &rhs) { return TType{ lhs.value - rhs }; }
67 
68  /* For most new types, the rest of the operators make no sense. For example,
69  * what does it actually mean to multiply a Year with a value. Or to do a
70  * bitwise OR on a Date. Or to divide a TileIndex by 2. Conceptually, they
71  * don't really mean anything. So force the user to first cast it to the
72  * base type, so the operation no longer returns the new Typedef. */
73 
74  constexpr TType &operator *=(const TType &rhs) = delete;
75  constexpr TType operator *(const TType &rhs) = delete;
76  constexpr TType operator *(const TBaseType &rhs) = delete;
77 
78  constexpr TType &operator /=(const TType &rhs) = delete;
79  constexpr TType operator /(const TType &rhs) = delete;
80  constexpr TType operator /(const TBaseType &rhs) = delete;
81 
82  constexpr TType &operator %=(const TType &rhs) = delete;
83  constexpr TType operator %(const TType &rhs) = delete;
84  constexpr TType operator %(const TBaseType &rhs) = delete;
85 
86  constexpr TType &operator &=(const TType &rhs) = delete;
87  constexpr TType operator &(const TType &rhs) = delete;
88  constexpr TType operator &(const TBaseType &rhs) = delete;
89 
90  constexpr TType &operator |=(const TType &rhs) = delete;
91  constexpr TType operator |(const TType &rhs) = delete;
92  constexpr TType operator |(const TBaseType &rhs) = delete;
93 
94  constexpr TType &operator ^=(const TType &rhs) = delete;
95  constexpr TType operator ^(const TType &rhs) = delete;
96  constexpr TType operator ^(const TBaseType &rhs) = delete;
97 
98  constexpr TType &operator <<=(const TType &rhs) = delete;
99  constexpr TType operator <<(const TType &rhs) = delete;
100  constexpr TType operator <<(const TBaseType &rhs) = delete;
101 
102  constexpr TType &operator >>=(const TType &rhs) = delete;
103  constexpr TType operator >>(const TType &rhs) = delete;
104  constexpr TType operator >>(const TBaseType &rhs) = delete;
105 
106  constexpr TType operator ~() = delete;
107  constexpr TType operator -() = delete;
108  };
109  };
110 
118  template <typename TCompatibleType>
119  struct Compatible {
120  template <typename TType, typename TBaseType>
121  struct mixin {
122  friend constexpr bool operator ==(const TType &lhs, TCompatibleType rhs) { return lhs.value == static_cast<TBaseType>(rhs); }
123  friend constexpr bool operator !=(const TType &lhs, TCompatibleType rhs) { return lhs.value != static_cast<TBaseType>(rhs); }
124 
125  friend constexpr bool operator <=(const TType &lhs, TCompatibleType rhs) { return lhs.value <= static_cast<TBaseType>(rhs); }
126  friend constexpr bool operator <(const TType &lhs, TCompatibleType rhs) { return lhs.value < static_cast<TBaseType>(rhs); }
127  friend constexpr bool operator >=(const TType &lhs, TCompatibleType rhs) { return lhs.value >= static_cast<TBaseType>(rhs); }
128  friend constexpr bool operator >(const TType &lhs, TCompatibleType rhs) { return lhs.value > static_cast<TBaseType>(rhs); }
129 
130  friend constexpr TType operator +(const TType &lhs, TCompatibleType rhs) { return { static_cast<TBaseType>(lhs.value + rhs) }; }
131  friend constexpr TType operator -(const TType &lhs, TCompatibleType rhs) { return { static_cast<TBaseType>(lhs.value - rhs) }; }
132  };
133  };
134 
149  template <typename TBaseType, typename TTag, typename... TProperties>
150  struct EMPTY_BASES Typedef : public StrongTypedefBase, public TProperties::template mixin<Typedef<TBaseType, TTag, TProperties...>, TBaseType>... {
151  using BaseType = TBaseType;
152 
153  constexpr Typedef() = default;
154  constexpr Typedef(const Typedef &) = default;
155  constexpr Typedef(Typedef &&) = default;
156 
157  constexpr Typedef(const TBaseType &value) : value(value) {}
158 
159  constexpr Typedef &operator =(const Typedef &rhs) { this->value = rhs.value; return *this; }
160  constexpr Typedef &operator =(Typedef &&rhs) { this->value = std::move(rhs.value); return *this; }
161  constexpr Typedef &operator =(const TBaseType &rhs) { this->value = rhs; return *this; }
162 
163  /* Only allow conversion to BaseType via method. */
164  constexpr TBaseType base() const { return this->value; }
165 
166  /* Only allow TProperties classes access to the internal value. Everyone else needs to call .base(). */
167  friend struct Compare;
168  friend struct Integer;
169  template <typename TCompatibleType> friend struct Compatible;
170 
171 /* GCC / MSVC don't pick up on the "friend struct" above, where CLang does.
172  * As in our CI we compile for all three targets, it is sufficient to have one
173  * that errors on this; but nobody should be using "value" directly. Instead,
174  * use base() to convert to the base type. */
175 #ifdef __clang__
176  protected:
177 #endif /* __clang__ */
178  TBaseType value{};
179  };
180 }
181 
182 #endif /* STRONG_TYPEDEF_TYPE_HPP */
StrongType::Compare
Mix-in which makes the new Typedef comparable with itself and its base type.
Definition: strong_typedef_type.hpp:22
StrongType::Integer
Mix-in which makes the new Typedef behave more like an integer.
Definition: strong_typedef_type.hpp:52
StrongType::Typedef
Templated helper to make a type-safe 'typedef' representing a single POD value.
Definition: strong_typedef_type.hpp:150
StrongType::Integer::mixin
Definition: strong_typedef_type.hpp:54
StrongType::Compatible
Mix-in which makes the new Typedef compatible with another type (which is not the base type).
Definition: strong_typedef_type.hpp:119
StrongType::Compatible::mixin
Definition: strong_typedef_type.hpp:121
StrongType::Compare::mixin
Definition: strong_typedef_type.hpp:24
StrongTypedefBase
Non-templated base for StrongType::Typedef for use with type trait queries.
Definition: strong_typedef_type.hpp:16