OpenTTD Source 20250205-master-gfd85ab1e2c
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
15namespace StrongType {
19 struct Compare {
20 template <typename TType, typename TBaseType>
21 struct mixin {
22 friend constexpr bool operator ==(const TType &lhs, const TType &rhs) { return lhs.value == rhs.value; }
23 friend constexpr bool operator ==(const TType &lhs, const TBaseType &rhs) { return lhs.value == rhs; }
24
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 };
41
49 struct Integer {
50 template <typename TType, typename TBaseType>
51 struct mixin {
52 friend constexpr TType &operator ++(TType &lhs) { lhs.value++; return lhs; }
53 friend constexpr TType &operator --(TType &lhs) { lhs.value--; return lhs; }
54 friend constexpr TType operator ++(TType &lhs, int) { TType res = lhs; lhs.value++; return res; }
55 friend constexpr TType operator --(TType &lhs, int) { TType res = lhs; lhs.value--; return res; }
56
57 friend constexpr TType &operator +=(TType &lhs, const TType &rhs) { lhs.value += rhs.value; return lhs; }
58 friend constexpr TType operator +(const TType &lhs, const TType &rhs) { return TType(lhs.value + rhs.value); }
59 friend constexpr TType operator +(const TType &lhs, const TBaseType &rhs) { return TType(lhs.value + rhs); }
60
61 friend constexpr TType &operator -=(TType &lhs, const TType &rhs) { lhs.value -= rhs.value; return lhs; }
62 friend constexpr TType operator -(const TType &lhs, const TType &rhs) { return TType(lhs.value - rhs.value); }
63 friend constexpr TType operator -(const TType &lhs, const TBaseType &rhs) { return TType(lhs.value - rhs); }
64
65 /* For most new types, the rest of the operators make no sense. For example,
66 * what does it actually mean to multiply a Year with a value. Or to do a
67 * bitwise OR on a Date. Or to divide a TileIndex by 2. Conceptually, they
68 * don't really mean anything. So force the user to first cast it to the
69 * base type, so the operation no longer returns the new Typedef. */
70
71 constexpr TType &operator *=(const TType &rhs) = delete;
72 constexpr TType operator *(const TType &rhs) = delete;
73 constexpr TType operator *(const TBaseType &rhs) = delete;
74
75 constexpr TType &operator /=(const TType &rhs) = delete;
76 constexpr TType operator /(const TType &rhs) = delete;
77 constexpr TType operator /(const TBaseType &rhs) = delete;
78
79 constexpr TType &operator %=(const TType &rhs) = delete;
80 constexpr TType operator %(const TType &rhs) = delete;
81 constexpr TType operator %(const TBaseType &rhs) = delete;
82
83 constexpr TType &operator &=(const TType &rhs) = delete;
84 constexpr TType operator &(const TType &rhs) = delete;
85 constexpr TType operator &(const TBaseType &rhs) = delete;
86
87 constexpr TType &operator |=(const TType &rhs) = delete;
88 constexpr TType operator |(const TType &rhs) = delete;
89 constexpr TType operator |(const TBaseType &rhs) = delete;
90
91 constexpr TType &operator ^=(const TType &rhs) = delete;
92 constexpr TType operator ^(const TType &rhs) = delete;
93 constexpr TType operator ^(const TBaseType &rhs) = delete;
94
95 constexpr TType &operator <<=(const TType &rhs) = delete;
96 constexpr TType operator <<(const TType &rhs) = delete;
97 constexpr TType operator <<(const TBaseType &rhs) = delete;
98
99 constexpr TType &operator >>=(const TType &rhs) = delete;
100 constexpr TType operator >>(const TType &rhs) = delete;
101 constexpr TType operator >>(const TBaseType &rhs) = delete;
102
103 constexpr TType operator ~() = delete;
104 constexpr TType operator -() = delete;
105 };
106 };
107
115 template <typename TCompatibleType>
116 struct Compatible {
117 template <typename TType, typename TBaseType>
118 struct mixin {
119 friend constexpr bool operator ==(const TType &lhs, TCompatibleType rhs) { return lhs.value == static_cast<TBaseType>(rhs); }
120 friend constexpr bool operator !=(const TType &lhs, TCompatibleType rhs) { return lhs.value != static_cast<TBaseType>(rhs); }
121
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 friend constexpr bool operator >=(const TType &lhs, TCompatibleType rhs) { return lhs.value >= static_cast<TBaseType>(rhs); }
125 friend constexpr bool operator >(const TType &lhs, TCompatibleType rhs) { return lhs.value > static_cast<TBaseType>(rhs); }
126
127 friend constexpr TType operator +(const TType &lhs, TCompatibleType rhs) { return TType(lhs.value + rhs); }
128 friend constexpr TType operator -(const TType &lhs, TCompatibleType rhs) { return TType(lhs.value - rhs); }
129 };
130 };
131
146 template <typename TBaseType, typename TTag, typename... TProperties>
147 struct EMPTY_BASES Typedef : public TProperties::template mixin<Typedef<TBaseType, TTag, TProperties...>, TBaseType>... {
148 using BaseType = TBaseType;
149
150 constexpr Typedef() = default;
151 constexpr Typedef(const Typedef &) = default;
152 constexpr Typedef(Typedef &&) = default;
153
154 explicit constexpr Typedef(const TBaseType &value) : value(value) {}
155
156 constexpr Typedef &operator =(const Typedef &rhs) { this->value = rhs.value; return *this; }
157 constexpr Typedef &operator =(Typedef &&rhs) { this->value = std::move(rhs.value); return *this; }
158
159 /* Only allow conversion to BaseType via method. */
160 constexpr TBaseType base() const noexcept { return this->value; }
161
162 /* Only allow TProperties classes access to the internal value. Everyone else needs to call .base(). */
163 friend struct Compare;
164 friend struct Integer;
165 template <typename TCompatibleType> friend struct Compatible;
166
167/* GCC / MSVC don't pick up on the "friend struct" above, where CLang does.
168 * As in our CI we compile for all three targets, it is sufficient to have one
169 * that errors on this; but nobody should be using "value" directly. Instead,
170 * use base() to convert to the base type. */
171#ifdef __clang__
172 protected:
173#endif /* __clang__ */
174 TBaseType value{};
175 };
176}
177
178#endif /* STRONG_TYPEDEF_TYPE_HPP */
Mix-in which makes the new Typedef comparable with itself and its base type.
Mix-in which makes the new Typedef compatible with another type (which is not the base type).
Mix-in which makes the new Typedef behave more like an integer.
Templated helper to make a type-safe 'typedef' representing a single POD value.