1 // Copyright (C) 2016-2020 Jonathan Müller <jonathanmueller.dev@gmail.com>
2 // This file is subject to the license terms in the LICENSE file
3 // found in the top-level directory of this distribution.
4 
5 #ifndef TYPE_SAFE_INTEGER_HPP_INCLUDED
6 #define TYPE_SAFE_INTEGER_HPP_INCLUDED
7 
8 #include <functional>
9 #include <iosfwd>
10 #include <limits>
11 #include <type_traits>
12 
13 #include <type_safe/arithmetic_policy.hpp>
14 #include <type_safe/detail/assert.hpp>
15 #include <type_safe/detail/force_inline.hpp>
16 
17 namespace type_safe
18 {
19 template <typename IntegerT, class Policy = arithmetic_policy_default>
20 class integer;
21 
22 /// \exclude
23 namespace detail
24 {
25     template <typename T>
26     struct is_integer
27     : std::integral_constant<bool, std::is_integral<T>::value && !std::is_same<T, bool>::value
28                                        && !std::is_same<T, char>::value>
29     {};
30 
31     template <typename From, typename To>
32     struct is_safe_integer_conversion
33     : std::integral_constant<bool,
34                              detail::is_integer<From>::value && detail::is_integer<To>::value
35                                  && ((sizeof(From) <= sizeof(To)
36                                       && std::is_signed<From>::value == std::is_signed<To>::value)
37                                      || (sizeof(From) < sizeof(To) && std::is_unsigned<From>::value
38                                          && std::is_signed<To>::value))>
39     {};
40 
41     template <typename From, typename To>
42     using enable_safe_integer_conversion =
43         typename std::enable_if<is_safe_integer_conversion<From, To>::value>::type;
44 
45     template <typename From, typename To>
46     using fallback_safe_integer_conversion =
47         typename std::enable_if<!is_safe_integer_conversion<From, To>::value>::type;
48 
49     template <typename A, typename B>
50     struct is_safe_integer_comparison
51     : std::integral_constant<bool, is_safe_integer_conversion<A, B>::value
52                                        || is_safe_integer_conversion<B, A>::value>
53     {};
54 
55     template <typename A, typename B>
56     using enable_safe_integer_comparison =
57         typename std::enable_if<is_safe_integer_comparison<A, B>::value>::type;
58 
59     template <typename A, typename B>
60     using fallback_safe_integer_comparison =
61         typename std::enable_if<!is_safe_integer_comparison<A, B>::value>::type;
62 
63     template <typename A, typename B>
64     struct is_safe_integer_operation
65     : std::integral_constant<bool, detail::is_integer<A>::value && detail::is_integer<B>::value
66                                        && std::is_signed<A>::value == std::is_signed<B>::value>
67     {};
68 
69     template <typename A, typename B>
70     struct integer_result_type
71     : std::enable_if<is_safe_integer_operation<A, B>::value,
72                      typename std::conditional<sizeof(A) < sizeof(B), B, A>::type>
73     {};
74 
75     template <typename A, typename B>
76     using integer_result_t = typename integer_result_type<A, B>::type;
77 
78     template <typename A, typename B>
79     using fallback_integer_result =
80         typename std::enable_if<!is_safe_integer_operation<A, B>::value>::type;
81 } // namespace detail
82 
83 /// A type safe integer class.
84 ///
85 /// This is a tiny, no overhead wrapper over a standard integer type.
86 /// It behaves exactly like the built-in types except that narrowing conversions are not allowed.
87 /// It also checks against `unsigned` under/overflow in debug mode
88 /// and marks it as undefined for the optimizer otherwise.
89 ///
90 /// A conversion is considered safe if both integer types have the same signedness
91 /// and the size of the value being converted is less than or equal to the destination size.
92 ///
93 /// \requires `IntegerT` must be an integral type except `bool` and `char` (use `signed
94 /// char`/`unsigned char`). \notes It intentionally does not provide the bitwise operations. \module
95 /// types
96 template <typename IntegerT, class Policy /* = arithmetic_policy_default*/>
97 class integer
98 {
99     static_assert(detail::is_integer<IntegerT>::value, "must be a real integer type");
100 
101 public:
102     using integer_type = IntegerT;
103 
104     //=== constructors ===//
105 #if TYPE_SAFE_DELETE_FUNCTIONS
106     /// \exclude
107     integer() = delete;
108 #endif
109 
110     /// \effects Initializes it with the given value.
111     /// \notes This function does not participate in overload resolution
112     /// if `T` is not an integer type safely convertible to this type.
113     /// \group constructor
114     /// \param 1
115     /// \exclude
116     template <typename T, typename = detail::enable_safe_integer_conversion<T, integer_type>>
integer(const T & val)117     TYPE_SAFE_FORCE_INLINE constexpr integer(const T& val) : value_(val)
118     {}
119 
120     /// \group constructor
121     /// \param 1
122     /// \exclude
123     template <typename T, typename = detail::enable_safe_integer_conversion<T, integer_type>>
integer(const integer<T,Policy> & val)124     TYPE_SAFE_FORCE_INLINE constexpr integer(const integer<T, Policy>& val)
125     : value_(static_cast<T>(val))
126     {}
127 
128 #if TYPE_SAFE_DELETE_FUNCTIONS
129     /// \exclude
130     template <typename T, typename = detail::fallback_safe_integer_conversion<T, integer_type>>
131     constexpr integer(T) = delete;
132     /// \exclude
133     template <typename T, typename = detail::fallback_safe_integer_conversion<T, integer_type>>
134     constexpr integer(const integer<T, Policy>&) = delete;
135 #endif
136 
137     //=== assignment ===//
138     /// \effects Assigns it with the given value.
139     /// \notes This function does not participate in overload resolution
140     /// if `T` is not an integer type safely convertible to this type.
141     /// \group assignment
142     /// \param 1
143     /// \exclude
144     template <typename T, typename = detail::enable_safe_integer_conversion<T, integer_type>>
operator =(const T & val)145     TYPE_SAFE_FORCE_INLINE integer& operator=(const T& val)
146     {
147         value_ = val;
148         return *this;
149     }
150 
151     /// \group assignment
152     /// \param 1
153     /// \exclude
154     template <typename T, typename = detail::enable_safe_integer_conversion<T, integer_type>>
operator =(const integer<T,Policy> & val)155     TYPE_SAFE_FORCE_INLINE integer& operator=(const integer<T, Policy>& val)
156     {
157         value_ = static_cast<T>(val);
158         return *this;
159     }
160 
161 #if TYPE_SAFE_DELETE_FUNCTIONS
162     /// \exclude
163     template <typename T, typename = detail::fallback_safe_integer_conversion<T, integer_type>>
164     constexpr integer(T) = delete;
165     /// \exclude
166     template <typename T, typename = detail::fallback_safe_integer_conversion<T, integer_type>>
167     integer& operator=(const integer<T, Policy>&) = delete;
168 #endif
169 
170     //=== conversion back ===//
171     /// \returns The stored value as the native integer type.
172     /// \group conversion
operator integer_type() const173     TYPE_SAFE_FORCE_INLINE explicit constexpr operator integer_type() const noexcept
174     {
175         return value_;
176     }
177 
178     /// \group conversion
get() const179     TYPE_SAFE_FORCE_INLINE constexpr integer_type get() const noexcept
180     {
181         return value_;
182     }
183 
184     //=== unary operators ===//
185     /// \returns The integer type unchanged.
operator +() const186     TYPE_SAFE_FORCE_INLINE constexpr integer operator+() const
187     {
188         return *this;
189     }
190 
191     /// \returns The negative integer type.
192     /// \requires The integer type must not be unsigned.
operator -() const193     TYPE_SAFE_FORCE_INLINE constexpr integer operator-() const
194     {
195         static_assert(std::is_signed<integer_type>::value,
196                       "cannot call unary minus on unsigned integer");
197         return integer(Policy::template do_multiplication(value_, integer_type(-1)));
198     }
199 
200     /// \effects Increments the integer by one.
201     /// \group increment
operator ++()202     TYPE_SAFE_FORCE_INLINE integer& operator++()
203     {
204         value_ = Policy::template do_addition(value_, integer_type(1));
205         return *this;
206     }
207 
208     /// \group increment
operator ++(int)209     TYPE_SAFE_FORCE_INLINE integer operator++(int)
210     {
211         auto res = *this;
212         ++*this;
213         return res;
214     }
215 
216     /// \effects Decrements the integer by one.
217     /// \group decrement
operator --()218     TYPE_SAFE_FORCE_INLINE integer& operator--()
219     {
220         value_ = Policy::template do_subtraction(value_, integer_type(1));
221         return *this;
222     }
223 
224     /// \group decrement
operator --(int)225     TYPE_SAFE_FORCE_INLINE integer operator--(int)
226     {
227         auto res = *this;
228         --*this;
229         return res;
230     }
231 
232 //=== compound assignment ====//
233 /// \exclude
234 #define TYPE_SAFE_DETAIL_MAKE_OP(Op)                                                               \
235     /** \group compound_assign                                                                     \
236      * \param 1                                                                                    \
237      * \exclude */                                                                                 \
238     template <typename T, typename = detail::enable_safe_integer_conversion<T, integer_type>>      \
239     TYPE_SAFE_FORCE_INLINE integer& operator Op(const T& other)                                    \
240     {                                                                                              \
241         return *this Op integer<T, Policy>(other);                                                 \
242     }                                                                                              \
243     /** \exclude */                                                                                \
244     template <typename T, typename = detail::fallback_safe_integer_conversion<T, integer_type>>    \
245     integer& operator Op(integer<T, Policy>) = delete;                                             \
246     /** \exclude */                                                                                \
247     template <typename T, typename = detail::fallback_safe_integer_conversion<T, integer_type>>    \
248     integer& operator Op(T) = delete;
249 
250     /// \effects Same as the operation on the integer type.
251     /// \notes These functions do not participate in overload resolution,
252     /// if `T` is not an integer type safely convertible to this type.
253     /// \group compound_assign Compound assignment
254     /// \param 1
255     /// \exclude
256     template <typename T, typename = detail::enable_safe_integer_conversion<T, integer_type>>
operator +=(const integer<T,Policy> & other)257     TYPE_SAFE_FORCE_INLINE integer& operator+=(const integer<T, Policy>& other)
258     {
259         value_ = Policy::template do_addition<integer_type>(value_, static_cast<T>(other));
260         return *this;
261     }
262     TYPE_SAFE_DETAIL_MAKE_OP(+=)
263 
264     /// \group compound_assign
265     /// \param 1
266     /// \exclude
267     template <typename T, typename = detail::enable_safe_integer_conversion<T, integer_type>>
operator -=(const integer<T,Policy> & other)268     TYPE_SAFE_FORCE_INLINE integer& operator-=(const integer<T, Policy>& other)
269     {
270         value_ = Policy::template do_subtraction<integer_type>(value_, static_cast<T>(other));
271         return *this;
272         return *this;
273     }
274     TYPE_SAFE_DETAIL_MAKE_OP(-=)
275 
276     /// \group compound_assign
277     /// \param 1
278     /// \exclude
279     template <typename T, typename = detail::enable_safe_integer_conversion<T, integer_type>>
operator *=(const integer<T,Policy> & other)280     TYPE_SAFE_FORCE_INLINE integer& operator*=(const integer<T, Policy>& other)
281     {
282         value_ = Policy::template do_multiplication<integer_type>(value_, static_cast<T>(other));
283         return *this;
284     }
285     TYPE_SAFE_DETAIL_MAKE_OP(*=)
286 
287     /// \group compound_assign
288     /// \param 1
289     /// \exclude
290     template <typename T, typename = detail::enable_safe_integer_conversion<T, integer_type>>
operator /=(const integer<T,Policy> & other)291     TYPE_SAFE_FORCE_INLINE integer& operator/=(const integer<T, Policy>& other)
292     {
293         value_ = Policy::template do_division<integer_type>(value_, static_cast<T>(other));
294         return *this;
295     }
296     TYPE_SAFE_DETAIL_MAKE_OP(/=)
297 
298     /// \group compound_assign
299     /// \param 1
300     /// \exclude
301     template <typename T, typename = detail::enable_safe_integer_conversion<T, integer_type>>
operator %=(const integer<T,Policy> & other)302     TYPE_SAFE_FORCE_INLINE integer& operator%=(const integer<T, Policy>& other)
303     {
304         value_ = Policy::template do_modulo<integer_type>(value_, static_cast<T>(other));
305         return *this;
306     }
307     TYPE_SAFE_DETAIL_MAKE_OP(%=)
308 
309 #undef TYPE_SAFE_DETAIL_MAKE_OP
310 
311 private:
312     integer_type value_;
313 };
314 
315 //=== operations ===//
316 /// \exclude
317 namespace detail
318 {
319     template <typename T>
320     struct make_signed
321     {
322         using type = typename std::make_signed<T>::type;
323     };
324 
325     template <typename T, class Policy>
326     struct make_signed<integer<T, Policy>>
327     {
328         using type = integer<typename std::make_signed<T>::type, Policy>;
329     };
330 
331     template <typename T>
332     struct make_unsigned
333     {
334         using type = typename std::make_unsigned<T>::type;
335     };
336 
337     template <typename T, class Policy>
338     struct make_unsigned<integer<T, Policy>>
339     {
340         using type = integer<typename std::make_unsigned<T>::type, Policy>;
341     };
342 } // namespace detail
343 
344 /// [std::make_signed]() for [ts::integer]().
345 /// \module types
346 /// \exclude target
347 template <class Integer>
348 using make_signed_t = typename detail::make_signed<Integer>::type;
349 
350 /// \returns A new integer of the corresponding signed integer type.
351 /// \requires The value of `i` must fit into signed type.
352 /// \module types
353 /// \param 1
354 /// \exclude
355 template <typename Integer,
356           typename = typename std::enable_if<detail::is_integer<Integer>::value>::type>
make_signed(const Integer & i)357 TYPE_SAFE_FORCE_INLINE constexpr make_signed_t<Integer> make_signed(const Integer& i)
358 {
359     using result_type = make_signed_t<Integer>;
360     return i <= Integer(std::numeric_limits<result_type>::max())
361                ? static_cast<result_type>(i)
362                : DEBUG_UNREACHABLE(detail::precondition_error_handler{}, "conversion "
363                                                                          "would "
364                                                                          "overflow");
365 }
366 
367 /// \returns A new [ts::integer]() of the corresponding signed integer type.
368 /// \requires The value of `i` must fit into signed type.
369 /// \module types
370 template <typename Integer, class Policy>
make_signed(const integer<Integer,Policy> & i)371 TYPE_SAFE_FORCE_INLINE constexpr make_signed_t<integer<Integer, Policy>> make_signed(
372     const integer<Integer, Policy>& i)
373 {
374     return make_signed(static_cast<Integer>(i));
375 }
376 
377 /// [std::make_unsigned]() for [ts::integer]().
378 /// \module types
379 /// \exclude target
380 template <class Integer>
381 using make_unsigned_t = typename detail::make_unsigned<Integer>::type;
382 
383 /// \returns A new integer of the corresponding unsigned integer type.
384 /// \requires The value of `i` must not be negative.
385 /// \module types
386 /// \param 1
387 /// \exclude
388 template <typename Integer,
389           typename = typename std::enable_if<detail::is_integer<Integer>::value>::type>
make_unsigned(const Integer & i)390 TYPE_SAFE_FORCE_INLINE constexpr make_unsigned_t<Integer> make_unsigned(const Integer& i)
391 {
392     using result_type = make_unsigned_t<Integer>;
393     return i >= Integer(0) ? static_cast<result_type>(i)
394                            : DEBUG_UNREACHABLE(detail::precondition_error_handler{},
395                                                "conversion would underflow");
396 }
397 
398 /// \returns A new [ts::integer]() of the corresponding unsigned integer type.
399 /// \requires The value of `i` must not be negative.
400 /// \module types
401 template <typename Integer, class Policy>
make_unsigned(const integer<Integer,Policy> & i)402 TYPE_SAFE_FORCE_INLINE constexpr make_unsigned_t<integer<Integer, Policy>> make_unsigned(
403     const integer<Integer, Policy>& i)
404 {
405     return make_unsigned(static_cast<Integer>(i));
406 }
407 
408 /// \returns The absolute value of a built-in signed integer.
409 /// It will be changed to the unsigned return type as well.
410 /// \module types
411 /// \param 1
412 /// \exclude
413 template <typename SignedInteger,
414           typename = typename std::enable_if<std::is_signed<SignedInteger>::value>::type>
abs(const SignedInteger & i)415 TYPE_SAFE_FORCE_INLINE constexpr make_unsigned_t<SignedInteger> abs(const SignedInteger& i)
416 {
417     return make_unsigned(i > 0 ? i : -i);
418 }
419 
420 /// \returns The absolute value of an [ts::integer]().
421 /// \module types
422 /// \param 2
423 /// \exclude
424 template <typename SignedInteger, class Policy,
425           typename = typename std::enable_if<std::is_signed<SignedInteger>::value>::type>
abs(const integer<SignedInteger,Policy> & i)426 TYPE_SAFE_FORCE_INLINE constexpr make_unsigned_t<integer<SignedInteger, Policy>> abs(
427     const integer<SignedInteger, Policy>& i)
428 {
429     return make_unsigned(i > 0 ? i : -i);
430 }
431 
432 /// \returns `i` unchanged.
433 /// \notes This is an optimization of `abs()` for unsigned integer types.
434 /// \module types
435 /// \param 1
436 /// \exclude
437 template <typename UnsignedInteger,
438           typename = typename std::enable_if<std::is_unsigned<UnsignedInteger>::value>::type>
abs(const UnsignedInteger & i)439 TYPE_SAFE_FORCE_INLINE constexpr UnsignedInteger abs(const UnsignedInteger& i)
440 {
441     return i;
442 }
443 
444 /// \returns `i` unchanged.
445 /// \notes This is an optimization of `abs()` for unsigned integer types.
446 /// \module types
447 /// \param 2
448 /// \exclude
449 template <typename UnsignedInteger, class Policy,
450           typename = typename std::enable_if<std::is_unsigned<UnsignedInteger>::value>::type>
abs(const integer<UnsignedInteger,Policy> & i)451 TYPE_SAFE_FORCE_INLINE constexpr integer<UnsignedInteger, Policy> abs(
452     const integer<UnsignedInteger, Policy>& i)
453 {
454     return i;
455 }
456 
457 //=== comparison ===//
458 /// \exclude
459 #define TYPE_SAFE_DETAIL_MAKE_OP(Op)                                                               \
460     /** \group int_comp                                                                            \
461      * \param 3                                                                                    \
462      * \exclude */                                                                                 \
463     template <typename A, typename B, class Policy,                                                \
464               typename = detail::enable_safe_integer_comparison<A, B>>                             \
465     TYPE_SAFE_FORCE_INLINE constexpr bool operator Op(const A& a, const integer<B, Policy>& b)     \
466     {                                                                                              \
467         return integer<A, Policy>(a) Op b;                                                         \
468     }                                                                                              \
469     /** \group int_comp                                                                            \
470      * \param 3                                                                                    \
471      * \exclude */                                                                                 \
472     template <typename A, class Policy, typename B,                                                \
473               typename = detail::enable_safe_integer_comparison<A, B>>                             \
474     TYPE_SAFE_FORCE_INLINE constexpr bool operator Op(const integer<A, Policy>& a, const B& b)     \
475     {                                                                                              \
476         return a Op integer<B, Policy>(b);                                                         \
477     }                                                                                              \
478     /** \exclude */                                                                                \
479     template <typename A, class Policy, typename B,                                                \
480               typename = detail::fallback_safe_integer_comparison<A, B>>                           \
481     constexpr bool operator Op(integer<A, Policy>, integer<B, Policy>) = delete;                   \
482     /** \exclude */                                                                                \
483     template <typename A, typename B, class Policy,                                                \
484               typename = detail::fallback_safe_integer_comparison<A, B>>                           \
485     constexpr bool operator Op(A, integer<B, Policy>) = delete;                                    \
486     /** \exclude */                                                                                \
487     template <typename A, class Policy, typename B,                                                \
488               typename = detail::fallback_safe_integer_comparison<A, B>>                           \
489     constexpr bool operator Op(integer<A, Policy>, B) = delete;
490 
491 /// \returns The result of the comparison of the stored integer value in the [ts::integer]().
492 /// \notes These functions do not participate in overload resolution
493 /// unless `A` and `B` are both integer types.
494 /// \group int_comp Comparison operators
495 /// \module types
496 /// \param 3
497 /// \exclude
498 template <typename A, typename B, class Policy,
499           typename = detail::enable_safe_integer_comparison<A, B>>
operator ==(const integer<A,Policy> & a,const integer<B,Policy> & b)500 TYPE_SAFE_FORCE_INLINE constexpr bool operator==(const integer<A, Policy>& a,
501                                                  const integer<B, Policy>& b)
502 {
503     return static_cast<A>(a) == static_cast<B>(b);
504 }
505 TYPE_SAFE_DETAIL_MAKE_OP(==)
506 
507 /// \group int_comp Comparison operators
508 /// \param 3
509 /// \exclude
510 template <typename A, typename B, class Policy,
511           typename = detail::enable_safe_integer_comparison<A, B>>
operator !=(const integer<A,Policy> & a,const integer<B,Policy> & b)512 TYPE_SAFE_FORCE_INLINE constexpr bool operator!=(const integer<A, Policy>& a,
513                                                  const integer<B, Policy>& b)
514 {
515     return static_cast<A>(a) != static_cast<B>(b);
516 }
517 TYPE_SAFE_DETAIL_MAKE_OP(!=)
518 
519 /// \group int_comp Comparison operators
520 /// \param 3
521 /// \exclude
522 template <typename A, typename B, class Policy,
523           typename = detail::enable_safe_integer_comparison<A, B>>
operator <(const integer<A,Policy> & a,const integer<B,Policy> & b)524 TYPE_SAFE_FORCE_INLINE constexpr bool operator<(const integer<A, Policy>& a,
525                                                 const integer<B, Policy>& b)
526 {
527     return static_cast<A>(a) < static_cast<B>(b);
528 }
529 TYPE_SAFE_DETAIL_MAKE_OP(<)
530 
531 /// \group int_comp Comparison operators
532 /// \param 3
533 /// \exclude
534 template <typename A, typename B, class Policy,
535           typename = detail::enable_safe_integer_comparison<A, B>>
operator <=(const integer<A,Policy> & a,const integer<B,Policy> & b)536 TYPE_SAFE_FORCE_INLINE constexpr bool operator<=(const integer<A, Policy>& a,
537                                                  const integer<B, Policy>& b)
538 {
539     return static_cast<A>(a) <= static_cast<B>(b);
540 }
541 TYPE_SAFE_DETAIL_MAKE_OP(<=)
542 
543 /// \group int_comp Comparison operators
544 /// \param 3
545 /// \exclude
546 template <typename A, typename B, class Policy,
547           typename = detail::enable_safe_integer_comparison<A, B>>
operator >(const integer<A,Policy> & a,const integer<B,Policy> & b)548 TYPE_SAFE_FORCE_INLINE constexpr bool operator>(const integer<A, Policy>& a,
549                                                 const integer<B, Policy>& b)
550 {
551     return static_cast<A>(a) > static_cast<B>(b);
552 }
553 TYPE_SAFE_DETAIL_MAKE_OP(>)
554 
555 /// \group int_comp Comparison operators
556 /// \param 3
557 /// \exclude
558 template <typename A, typename B, class Policy,
559           typename = detail::enable_safe_integer_comparison<A, B>>
operator >=(const integer<A,Policy> & a,const integer<B,Policy> & b)560 TYPE_SAFE_FORCE_INLINE constexpr bool operator>=(const integer<A, Policy>& a,
561                                                  const integer<B, Policy>& b)
562 {
563     return static_cast<A>(a) >= static_cast<B>(b);
564 }
565 TYPE_SAFE_DETAIL_MAKE_OP(>=)
566 
567 #undef TYPE_SAFE_DETAIL_MAKE_OP
568 
569 //=== binary operations ===//
570 /// \entity TYPE_SAFE_DETAIL_MAKE_OP
571 /// \exclude
572 #define TYPE_SAFE_DETAIL_MAKE_OP(Op)                                                               \
573     /** \exclude return                                                                            \
574      * \group int_binary_op */                                                                     \
575     template <typename A, typename B, class Policy>                                                \
576     TYPE_SAFE_FORCE_INLINE constexpr auto operator Op(const A& a, const integer<B, Policy>& b)     \
577         ->integer<detail::integer_result_t<A, B>, Policy>                                          \
578     {                                                                                              \
579         return integer<A, Policy>(a) Op b;                                                         \
580     }                                                                                              \
581     /** \exclude return                                                                            \
582      * \group int_binary_op */                                                                     \
583     template <typename A, class Policy, typename B>                                                \
584     TYPE_SAFE_FORCE_INLINE constexpr auto operator Op(const integer<A, Policy>& a, const B& b)     \
585         ->integer<detail::integer_result_t<A, B>, Policy>                                          \
586     {                                                                                              \
587         return a Op integer<B, Policy>(b);                                                         \
588     }                                                                                              \
589     /** \exclude */                                                                                \
590     template <typename A, typename B, class Policy,                                                \
591               typename = detail::fallback_integer_result<A, B>>                                    \
592     constexpr int operator Op(integer<A, Policy>, integer<B, Policy>) = delete;                    \
593     /** \exclude */                                                                                \
594     template <typename A, typename B, class Policy,                                                \
595               typename = detail::fallback_integer_result<A, B>>                                    \
596     constexpr int operator Op(A, integer<B, Policy>) = delete;                                     \
597     /** \exclude */                                                                                \
598     template <typename A, class Policy, typename B,                                                \
599               typename = detail::fallback_integer_result<A, B>>                                    \
600     constexpr int operator Op(integer<A, Policy>, B) = delete;
601 
602 /// \returns The result of the binary operation of the stored integer value in the [ts::integer]().
603 /// The type is a [ts::integer]() of the bigger integer type.
604 /// \notes These functions do not participate in overload resolution,
605 /// unless `A` and `B` are both integer types.
606 /// \group int_binary_op Binary operations
607 /// \module types
608 /// \exclude return
609 template <typename A, typename B, class Policy>
operator +(const integer<A,Policy> & a,const integer<B,Policy> & b)610 TYPE_SAFE_FORCE_INLINE constexpr auto operator+(const integer<A, Policy>& a,
611                                                 const integer<B, Policy>& b)
612     -> integer<detail::integer_result_t<A, B>, Policy>
613 {
614     using type = detail::integer_result_t<A, B>;
615     return Policy::template do_addition<type>(static_cast<A>(a), static_cast<B>(b));
616 }
617 TYPE_SAFE_DETAIL_MAKE_OP(+)
618 
619 /// \group int_binary_op
620 /// \exclude return
621 template <typename A, typename B, class Policy>
operator -(const integer<A,Policy> & a,const integer<B,Policy> & b)622 TYPE_SAFE_FORCE_INLINE constexpr auto operator-(const integer<A, Policy>& a,
623                                                 const integer<B, Policy>& b)
624     -> integer<detail::integer_result_t<A, B>, Policy>
625 {
626     using type = detail::integer_result_t<A, B>;
627     return Policy::template do_subtraction<type>(static_cast<A>(a), static_cast<B>(b));
628 }
629 TYPE_SAFE_DETAIL_MAKE_OP(-)
630 
631 /// \group int_binary_op
632 /// \exclude return
633 template <typename A, typename B, class Policy>
operator *(const integer<A,Policy> & a,const integer<B,Policy> & b)634 TYPE_SAFE_FORCE_INLINE constexpr auto operator*(const integer<A, Policy>& a,
635                                                 const integer<B, Policy>& b)
636     -> integer<detail::integer_result_t<A, B>, Policy>
637 {
638     using type = detail::integer_result_t<A, B>;
639     return Policy::template do_multiplication<type>(static_cast<A>(a), static_cast<B>(b));
640 }
641 TYPE_SAFE_DETAIL_MAKE_OP(*)
642 
643 /// \group int_binary_op
644 /// \exclude return
645 template <typename A, typename B, class Policy>
operator /(const integer<A,Policy> & a,const integer<B,Policy> & b)646 TYPE_SAFE_FORCE_INLINE constexpr auto operator/(const integer<A, Policy>& a,
647                                                 const integer<B, Policy>& b)
648     -> integer<detail::integer_result_t<A, B>, Policy>
649 {
650     using type = detail::integer_result_t<A, B>;
651     return Policy::template do_division<type>(static_cast<A>(a), static_cast<B>(b));
652 }
653 TYPE_SAFE_DETAIL_MAKE_OP(/)
654 
655 /// \group int_binary_op
656 /// \exclude return
657 template <typename A, typename B, class Policy>
operator %(const integer<A,Policy> & a,const integer<B,Policy> & b)658 TYPE_SAFE_FORCE_INLINE constexpr auto operator%(const integer<A, Policy>& a,
659                                                 const integer<B, Policy>& b)
660     -> integer<detail::integer_result_t<A, B>, Policy>
661 {
662     using type = detail::integer_result_t<A, B>;
663     return Policy::template do_modulo<type>(static_cast<A>(a), static_cast<B>(b));
664 }
665 TYPE_SAFE_DETAIL_MAKE_OP(%)
666 
667 #undef TYPE_SAFE_DETAIL_MAKE_OP
668 
669 //=== input/output ===/
670 /// \effects Reads an integer from the [std::istream]() and assigns it to the given [ts::integer]().
671 /// \module types
672 /// \output_section Input/output
673 template <typename Char, class CharTraits, typename IntegerT, class Policy>
operator >>(std::basic_istream<Char,CharTraits> & in,integer<IntegerT,Policy> & i)674 std::basic_istream<Char, CharTraits>& operator>>(std::basic_istream<Char, CharTraits>& in,
675                                                  integer<IntegerT, Policy>&            i)
676 {
677     IntegerT val;
678     in >> val;
679     i = val;
680     return in;
681 }
682 
683 /// \effects Converts the given [ts::integer]() to the underlying integer type and writes it to th
684 /// [std::ostream](). \module types
685 template <typename Char, class CharTraits, typename IntegerT, class Policy>
operator <<(std::basic_ostream<Char,CharTraits> & out,const integer<IntegerT,Policy> & i)686 std::basic_ostream<Char, CharTraits>& operator<<(std::basic_ostream<Char, CharTraits>& out,
687                                                  const integer<IntegerT, Policy>&      i)
688 {
689     return out << static_cast<IntegerT>(i);
690 }
691 } // namespace type_safe
692 
693 namespace std
694 {
695 /// Hash specialization for [ts::integer].
696 /// \module types
697 template <typename IntegerT, class Policy>
698 struct hash<type_safe::integer<IntegerT, Policy>>
699 {
operator ()std::hash700     std::size_t operator()(const type_safe::integer<IntegerT, Policy>& i) const noexcept
701     {
702         return std::hash<IntegerT>()(static_cast<IntegerT>(i));
703     }
704 };
705 } // namespace std
706 
707 #endif // TYPE_SAFE_INTEGER_HPP_INCLUDED
708