1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef MAPLE_UTIL_INCLUDE_MPL_NUMBER_H
17 #define MAPLE_UTIL_INCLUDE_MPL_NUMBER_H
18 #include <algorithm>
19 #include <string>
20 #include "utils/meta.h"
21
22 namespace maple {
23 namespace utils {
24 template <typename T, typename = void>
25 class Number {
26 public:
27 static_assert(std::is_integral<T>::value, "Type for Number should be an integral.");
28
29 using ElementType = T;
30
31 Number() = default;
32
Number(ElementType data)33 explicit Number(ElementType data) : val(data) {}
34
35 template <typename U, typename = std::enable_if_t<std::is_integral<U>::value>>
Number(U data)36 explicit Number(U data) : val(static_cast<T>(data))
37 {
38 }
39
Number(const Number &num)40 Number(const Number &num) : val(num.val) {}
41
move(num.val)42 Number(Number &&num) noexcept : val(std::move(num.val)) {}
43
44 ~Number() = default;
45
46 // As the implicit T cast is enabled, disable it to avoid implicit cast for `Number<T, Tag1> num = Number<T,
47 // Tag2>()` which should be two types and should not be able to neither convert to each other nor compare with each
48 // other.
49 Number &operator=(ElementType data) = delete;
50
51 Number &operator=(const Number &num) noexcept
52 {
53 if (&num != this) {
54 val = num.val;
55 }
56 return *this;
57 }
58
59 Number &operator=(Number &&num) noexcept
60 {
61 if (&num != this) {
62 val = std::move(num.val);
63 }
64 return *this;
65 }
66
67 void reset(ElementType data = 0) noexcept
68 {
69 val = data;
70 }
71
72 void swap(Number &other) noexcept
73 {
74 std::swap(val, other.val);
75 }
76
77 ElementType get() const noexcept
78 {
79 return val;
80 }
81
82 template <typename U = T>
83 operator std::enable_if_t<std::is_same<U, T>::value, U>() const noexcept
84 {
85 return val;
86 }
87
88 template <typename U = size_t>
89 operator std::enable_if_t<meta_and<meta_not<std::is_same<U, T>>, std::is_same<U, size_t>>::value, U>()
90 const noexcept
91 {
92 return static_cast<size_t>(val);
93 }
94
95 template <typename U, typename = std::enable_if_t<
96 meta_and<meta_not<std::is_same<U, T>>, meta_not<std::is_same<U, size_t>>>::value>>
97 explicit operator U() const noexcept
98 {
99 return static_cast<U>(val);
100 }
101
102 Number &operator+=(const T &data) noexcept
103 {
104 val += data;
105 }
106
107 Number &operator+=(const Number &num) noexcept
108 {
109 val += num.val;
110 }
111
112 Number &operator-=(const T &data) noexcept
113 {
114 val -= data;
115 }
116
117 Number &operator-=(const Number &num) noexcept
118 {
119 val -= num.val;
120 }
121
122 Number &operator++() noexcept
123 {
124 ++val;
125 return *this;
126 }
127
operator ++(int)128 const Number operator++(int)
129 {
130 auto tmp = val;
131 this->operator++();
132 return Number(tmp);
133 }
134
135 Number &operator--() noexcept
136 {
137 --val;
138 return *this;
139 }
140
operator --(int)141 const Number operator--(int)
142 {
143 auto tmp = val;
144 this->operator--;
145 return Number(tmp);
146 }
147
GetIdx() const148 T GetIdx() const
149 {
150 return val;
151 }
152
SetIdx(T i)153 void SetIdx(T i)
154 {
155 val = i;
156 }
157
158 private:
159 ElementType val = 0;
160 };
161
162 template <typename T, typename Tag>
operator ==(const Number<T, Tag> &lhs, const Number<T, Tag> &rhs)163 inline bool operator==(const Number<T, Tag> &lhs, const Number<T, Tag> &rhs)
164 {
165 return lhs.get() == rhs.get();
166 }
167
168 template <typename T, typename Tag>
operator !=(const Number<T, Tag> &lhs, const Number<T, Tag> &rhs)169 inline bool operator!=(const Number<T, Tag> &lhs, const Number<T, Tag> &rhs)
170 {
171 return !(lhs == rhs);
172 }
173
174 template <typename T, typename Tag>
operator <(const Number<T, Tag> &lhs, const Number<T, Tag> &rhs)175 inline bool operator<(const Number<T, Tag> &lhs, const Number<T, Tag> &rhs)
176 {
177 return lhs.get() < rhs.get();
178 }
179
180 template <typename T, typename Tag>
operator <=(const Number<T, Tag> &lhs, const Number<T, Tag> &rhs)181 inline bool operator<=(const Number<T, Tag> &lhs, const Number<T, Tag> &rhs)
182 {
183 return lhs.get() <= rhs.get();
184 }
185
186 template <typename T, typename Tag>
operator >(const Number<T, Tag> &lhs, const Number<T, Tag> &rhs)187 inline bool operator>(const Number<T, Tag> &lhs, const Number<T, Tag> &rhs)
188 {
189 return !(lhs <= rhs);
190 }
191
192 template <typename T, typename Tag>
operator >=(const Number<T, Tag> &lhs, const Number<T, Tag> &rhs)193 inline bool operator>=(const Number<T, Tag> &lhs, const Number<T, Tag> &rhs)
194 {
195 return !(lhs < rhs);
196 }
197
198 template <typename T, typename Tag>
operator +(const Number<T, Tag> &lhs, const Number<T, Tag> &rhs)199 inline Number<T, Tag> operator+(const Number<T, Tag> &lhs, const Number<T, Tag> &rhs)
200 {
201 return Number<T, Tag>(lhs.get() + rhs.get());
202 }
203
204 template <typename T, typename Tag>
operator -(const Number<T, Tag> &lhs, const Number<T, Tag> &rhs)205 inline Number<T, Tag> operator-(const Number<T, Tag> &lhs, const Number<T, Tag> &rhs)
206 {
207 return Number<T, Tag>(lhs.get() - rhs.get());
208 }
209
210 template <typename T, typename Tag, typename U,
211 typename = std::enable_if_t<meta_or<std::is_integral<U>, std::is_enum<U>>::value>>
operator ==(const Number<T, Tag> &lhs, const U &rhs)212 inline bool operator==(const Number<T, Tag> &lhs, const U &rhs)
213 {
214 return lhs.get() == rhs;
215 }
216
217 template <typename T, typename Tag, typename U,
218 typename = std::enable_if_t<meta_or<std::is_integral<U>, std::is_enum<U>>::value>>
operator ==(const U &lhs, const Number<T, Tag> &rhs)219 inline bool operator==(const U &lhs, const Number<T, Tag> &rhs)
220 {
221 return lhs == rhs.get();
222 }
223
224 template <typename T, typename Tag, typename U,
225 typename = std::enable_if_t<meta_or<std::is_integral<U>, std::is_enum<U>>::value>>
operator !=(const Number<T, Tag> &lhs, const U &rhs)226 inline bool operator!=(const Number<T, Tag> &lhs, const U &rhs)
227 {
228 return !(lhs == rhs);
229 }
230
231 template <typename T, typename Tag, typename U,
232 typename = std::enable_if_t<meta_or<std::is_integral<U>, std::is_enum<U>>::value>>
operator !=(const U &lhs, const Number<T, Tag> &rhs)233 inline bool operator!=(const U &lhs, const Number<T, Tag> &rhs)
234 {
235 return !(lhs == rhs);
236 }
237
238 template <typename T, typename Tag, typename U,
239 typename = std::enable_if_t<meta_or<std::is_integral<U>, std::is_enum<U>>::value>>
operator <(const Number<T, Tag> &lhs, const U &rhs)240 inline bool operator<(const Number<T, Tag> &lhs, const U &rhs)
241 {
242 return lhs.get() < rhs;
243 }
244
245 template <typename T, typename Tag, typename U,
246 typename = std::enable_if_t<meta_or<std::is_integral<U>, std::is_enum<U>>::value>>
operator <(const U &lhs, const Number<T, Tag> &rhs)247 inline bool operator<(const U &lhs, const Number<T, Tag> &rhs)
248 {
249 return lhs < rhs.get();
250 }
251
252 template <typename T, typename Tag, typename U,
253 typename = std::enable_if_t<meta_or<std::is_integral<U>, std::is_enum<U>>::value>>
operator <=(const Number<T, Tag> &lhs, const U &rhs)254 inline bool operator<=(const Number<T, Tag> &lhs, const U &rhs)
255 {
256 return lhs.get() <= rhs;
257 }
258
259 template <typename T, typename Tag, typename U,
260 typename = std::enable_if_t<meta_or<std::is_integral<U>, std::is_enum<U>>::value>>
operator <=(const U &lhs, const Number<T, Tag> &rhs)261 inline bool operator<=(const U &lhs, const Number<T, Tag> &rhs)
262 {
263 return lhs <= rhs.get();
264 }
265
266 template <typename T, typename Tag, typename U,
267 typename = std::enable_if_t<meta_or<std::is_integral<U>, std::is_enum<U>>::value>>
operator >(const Number<T, Tag> &lhs, const U &rhs)268 inline bool operator>(const Number<T, Tag> &lhs, const U &rhs)
269 {
270 return !(lhs <= rhs);
271 }
272
273 template <typename T, typename Tag, typename U,
274 typename = std::enable_if_t<meta_or<std::is_integral<U>, std::is_enum<U>>::value>>
operator >(const U &lhs, const Number<T, Tag> &rhs)275 inline bool operator>(const U &lhs, const Number<T, Tag> &rhs)
276 {
277 return !(lhs <= rhs);
278 }
279
280 template <typename T, typename Tag, typename U,
281 typename = std::enable_if_t<meta_or<std::is_integral<U>, std::is_enum<U>>::value>>
operator >=(const Number<T, Tag> &lhs, const U &rhs)282 inline bool operator>=(const Number<T, Tag> &lhs, const U &rhs)
283 {
284 return !(lhs < rhs);
285 }
286
287 template <typename T, typename Tag, typename U,
288 typename = std::enable_if_t<meta_or<std::is_integral<U>, std::is_enum<U>>::value>>
operator >=(const U &lhs, const Number<T, Tag> &rhs)289 inline bool operator>=(const U &lhs, const Number<T, Tag> &rhs)
290 {
291 return !(lhs < rhs);
292 }
293
294 template <typename T, typename Tag, typename U, typename = std::enable_if_t<std::is_integral<U>::value>>
operator +(const Number<T, Tag> &lhs, const U &rhs)295 inline Number<T, Tag> operator+(const Number<T, Tag> &lhs, const U &rhs)
296 {
297 return Number<T, Tag>(lhs.get() + rhs);
298 }
299
300 template <typename T, typename Tag, typename U, typename = std::enable_if_t<std::is_integral<U>::value>>
operator +(const U &lhs, const Number<T, Tag> &rhs)301 inline Number<T, Tag> operator+(const U &lhs, const Number<T, Tag> &rhs)
302 {
303 return Number<T, Tag>(lhs + rhs.get());
304 }
305
306 template <typename T, typename Tag, typename U, typename = std::enable_if_t<std::is_integral<U>::value>>
operator -(const Number<T, Tag> &lhs, const U &rhs)307 inline Number<T, Tag> operator-(const Number<T, Tag> &lhs, const U &rhs)
308 {
309 return Number<T, Tag>(lhs.get() - rhs);
310 }
311
312 template <typename T, typename Tag, typename U, typename = std::enable_if_t<std::is_integral<U>::value>>
operator -(const U &lhs, const Number<T, Tag> &rhs)313 inline Number<T, Tag> operator-(const U &lhs, const Number<T, Tag> &rhs)
314 {
315 return Number<T, Tag>(lhs - rhs.get());
316 }
317
318 template <typename T, typename Tag, typename OS>
operator <<(OS &os, const Number<T, Tag> &num)319 inline OS &operator<<(OS &os, const Number<T, Tag> &num)
320 {
321 os << num.get();
322 return os;
323 }
324
325 template <typename Type, typename T = size_t>
326 using Index = Number<T, Type>;
327 } // namespace utils
328 } // namespace maple
329
330 namespace std {
331 template <typename T, typename Type>
to_string(maple::utils::Number<T, Type> val)332 inline string to_string(maple::utils::Number<T, Type> val)
333 {
334 return std::to_string(val.get());
335 }
336
337 template <class T>
hash_combine(std::size_t &seed, const T &v)338 inline void hash_combine(std::size_t &seed, const T &v)
339 {
340 std::hash<T> hasher;
341 size_t hasecode = 0x9e3779b9;
342 size_t leftShift = 6;
343 size_t rightShift = 2;
344 seed ^= hasher(v) + hasecode + (seed << leftShift) + (seed >> rightShift);
345 }
346 } // namespace std
347 #endif // MAPLE_UTIL_INCLUDE_MPL_NUMBER_H