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