27 #ifndef INCG_PHI_CORE_INTEGER_HPP 28 #define INCG_PHI_CORE_INTEGER_HPP 30 #include "phi/phi_config.hpp" 32 #if PHI_HAS_EXTENSION_PRAGMA_ONCE() 36 #include "phi/algorithm/swap.hpp" 37 #include "phi/compiler_support/constexpr.hpp" 38 #include "phi/compiler_support/inline.hpp" 39 #include "phi/compiler_support/nodiscard.hpp" 40 #include "phi/compiler_support/noexcept.hpp" 41 #include "phi/compiler_support/standard_library.hpp" 42 #include "phi/compiler_support/warning.hpp" 43 #include "phi/core/assert.hpp" 44 #include "phi/core/boolean.hpp" 45 #include "phi/forward/std/hash.hpp" 46 #include "phi/type_traits/conditional.hpp" 47 #include "phi/type_traits/enable_if.hpp" 48 #include "phi/type_traits/integral_constant.hpp" 49 #include "phi/type_traits/is_signed.hpp" 50 #include "phi/type_traits/is_unsafe_integer.hpp" 51 #include "phi/type_traits/is_unsigned.hpp" 55 DETAIL_PHI_BEGIN_NAMESPACE()
57 template <typename IntegerT>
64 template <
typename FromT,
typename ToT>
65 struct is_safe_integer_conversion
67 bool, is_unsafe_integer<FromT>::value && is_unsafe_integer<ToT>::value &&
68 ((sizeof(FromT) <= sizeof(ToT) &&
69 is_signed<FromT>::value == is_signed<ToT>::value) ||
70 (sizeof(FromT) < sizeof(ToT) && is_unsigned<FromT>::value &&
71 is_signed<ToT>::value))>
74 template <typename FromT, typename ToT>
75 using enable_safe_integer_conversion =
76 enable_if_t<is_safe_integer_conversion<FromT, ToT>::value>;
78 template <typename FromT, typename ToT>
79 using fallback_safe_integer_conversion =
80 enable_if_t<!is_safe_integer_conversion<FromT, ToT>::value>;
83 template <typename LhsT, typename RhsT>
84 struct is_safe_integer_comparison
85 : public integral_constant<bool, is_safe_integer_conversion<LhsT, RhsT>::value ||
86 is_safe_integer_conversion<RhsT, LhsT>::value>
89 template <typename LhsT, typename RhsT>
90 using enable_safe_integer_comparison =
91 enable_if_t<is_safe_integer_comparison<LhsT, RhsT>::value>;
93 template <typename LhsT, typename RhsT>
94 using fallback_safe_integer_comparison =
95 enable_if_t<!is_safe_integer_comparison<LhsT, RhsT>::value>;
98 template <typename LhsT, typename RhsT>
99 struct is_safe_integer_operation
100 : public integral_constant<bool, is_unsafe_integer<LhsT>::value &&
101 is_unsafe_integer<RhsT>::value &&
102 is_signed<LhsT>::value == is_signed<RhsT>::value>
105 template <typename LhsT, typename RhsT>
106 struct integer_result_type
107 : public enable_if<is_safe_integer_operation<LhsT, RhsT>::value,
108 conditional_t<sizeof(LhsT) < sizeof(RhsT), RhsT, LhsT>>
111 template <typename LhsT, typename RhsT>
112 using integer_result_t = typename integer_result_type<LhsT, RhsT>::type;
114 template <typename LhsT, typename RhsT>
115 using fallback_integer_result =
116 enable_if_t<is_unsafe_integer<LhsT>::value && is_unsafe_integer<RhsT>::value &&
117 is_signed<LhsT>::value != is_signed<RhsT>::value>;
120 struct signed_integer_tag
123 struct unsigned_integer_tag
126 template <typename TypeT>
127 using arithmetic_tag_for =
128 conditional_t<is_signed<TypeT>::value, signed_integer_tag, unsigned_integer_tag>;
130 template <typename TypeT>
131 PHI_ALWAYS_INLINE PHI_CONSTEXPR bool will_addition_error(signed_integer_tag , TypeT lhs,
132 TypeT rhs) PHI_NOEXCEPT
134 return rhs > TypeT(0) ? lhs > std::numeric_limits<TypeT>::max() - rhs :
135 lhs < std::numeric_limits<TypeT>::min() - rhs;
138 template <typename TypeT>
139 PHI_ALWAYS_INLINE PHI_CONSTEXPR bool will_addition_error(unsigned_integer_tag ,
140 TypeT lhs, TypeT rhs) PHI_NOEXCEPT
142 return std::numeric_limits<TypeT>::max() - rhs < lhs;
145 template <typename TypeT>
146 PHI_ALWAYS_INLINE PHI_CONSTEXPR bool will_subtraction_error(signed_integer_tag ,
147 TypeT lhs, TypeT rhs) PHI_NOEXCEPT
149 return rhs > TypeT(0) ? lhs < std::numeric_limits<TypeT>::min() + rhs :
150 lhs > std::numeric_limits<TypeT>::max() + rhs;
153 template <typename TypeT>
154 PHI_ALWAYS_INLINE PHI_CONSTEXPR bool will_subtraction_error(unsigned_integer_tag ,
155 TypeT lhs, TypeT rhs) PHI_NOEXCEPT
160 template <typename TypeT>
161 PHI_ALWAYS_INLINE PHI_CONSTEXPR bool will_multiplication_error(signed_integer_tag ,
163 TypeT rhs) PHI_NOEXCEPT
165 return lhs > TypeT(0) ?
167 lhs > std::numeric_limits<TypeT>::max() / rhs :
168 rhs < std::numeric_limits<TypeT>::min() /
171 lhs < std::numeric_limits<TypeT>::min() / rhs :
172 lhs != TypeT(0) && rhs < std::numeric_limits<TypeT>::max() /
176 template <typename TypeT>
177 PHI_ALWAYS_INLINE PHI_CONSTEXPR bool will_multiplication_error(unsigned_integer_tag ,
179 TypeT rhs) PHI_NOEXCEPT
181 return rhs != TypeT(0) && lhs > std::numeric_limits<TypeT>::max() / rhs;
184 template <typename TypeT>
185 PHI_ALWAYS_INLINE PHI_CONSTEXPR bool will_division_error(signed_integer_tag , TypeT lhs,
186 TypeT rhs) PHI_NOEXCEPT
188 return rhs == TypeT(0) || (rhs == TypeT(-1) && lhs == std::numeric_limits<TypeT>::min());
191 template <typename TypeT>
192 PHI_ALWAYS_INLINE PHI_CONSTEXPR bool will_division_error(unsigned_integer_tag ,
193 TypeT , TypeT rhs) PHI_NOEXCEPT
195 return rhs == TypeT(0);
198 template <typename TypeT>
199 PHI_ALWAYS_INLINE PHI_CONSTEXPR bool will_modulo_error(TypeT , TypeT rhs) PHI_NOEXCEPT
201 return rhs == TypeT(0);
206 PHI_GCC_SUPPRESS_WARNING_PUSH()
207 #if PHI_COMPILER_IS_ATLEAST(GCC, 10, 0, 0)
208 PHI_GCC_SUPPRESS_WARNING("-Warith-conversion")
210 PHI_GCC_SUPPRESS_WARNING("-Wconversion")
226 template <typename IntegerT>
229 static_assert(is_unsafe_integer<IntegerT>::value,
230 "[phi::integer] IntegerT must be a real integer type");
233 using this_type = integer<IntegerT>;
234 using value_type = IntegerT;
235 using limits_type = std::numeric_limits<IntegerT>;
241 template <typename TypeT, typename = detail::enable_safe_integer_conversion<TypeT, IntegerT>>
242 PHI_CONSTEXPR integer(const TypeT& val) PHI_NOEXCEPT : m_Value(val)
245 template <typename TypeT, typename = detail::enable_safe_integer_conversion<TypeT, IntegerT>>
246 PHI_ALWAYS_INLINE PHI_CONSTEXPR integer(const integer<TypeT>& val) PHI_NOEXCEPT
247 : m_Value(static_cast<TypeT>(val))
250 template <typename TypeT, typename = detail::fallback_safe_integer_conversion<TypeT, IntegerT>>
251 PHI_CONSTEXPR integer(TypeT) = delete;
255 template <typename TypeT, typename = detail::enable_safe_integer_conversion<TypeT, IntegerT>>
256 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR integer& operator=(const TypeT& val) PHI_NOEXCEPT
262 template <typename TypeT, typename = detail::enable_safe_integer_conversion<TypeT, IntegerT>>
263 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR integer& operator=(const integer<TypeT>& val)
266 m_Value = static_cast<TypeT>(val);
272 PHI_NODISCARD PHI_ALWAYS_INLINE explicit PHI_CONSTEXPR operator IntegerT() const PHI_NOEXCEPT
277 PHI_NODISCARD PHI_ALWAYS_INLINE PHI_CONSTEXPR IntegerT unsafe() const PHI_NOEXCEPT
282 PHI_NODISCARD PHI_ALWAYS_INLINE PHI_CONSTEXPR static integer<IntegerT> min() PHI_NOEXCEPT
284 return limits_type::min();
287 PHI_NODISCARD PHI_ALWAYS_INLINE PHI_CONSTEXPR static integer<IntegerT> max() PHI_NOEXCEPT
289 return limits_type::max();
292 PHI_EXTENDED_CONSTEXPR void swap(integer<IntegerT>& other) PHI_NOEXCEPT
294 phi::swap(m_Value, other.m_Value);
298 PHI_ALWAYS_INLINE PHI_CONSTEXPR integer operator+() const PHI_NOEXCEPT
303 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR integer operator-() const PHI_NOEXCEPT
305 static_assert(is_signed<IntegerT>::value, "Cannot call unary minus on unsigned integer");
307 PHI_ASSERT(m_Value != limits_type::min(), "Unary minus will overflow. Args {}", m_Value);
309 return integer(-m_Value);
312 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR integer& operator++() PHI_NOEXCEPT
314 PHI_ASSERT(!detail::will_addition_error(detail::arithmetic_tag_for<IntegerT>{}, m_Value,
316 "Operator++ will result in overflow. Args {}", m_Value);
323 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR const integer operator++(int) PHI_NOEXCEPT
330 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR integer& operator--() PHI_NOEXCEPT
332 PHI_ASSERT(!detail::will_subtraction_error(detail::arithmetic_tag_for<IntegerT>{}, m_Value,
334 "Operator-- will result in underflow. Args {}", m_Value);
341 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR const integer operator--(int) PHI_NOEXCEPT
350 template <typename TypeT, typename = detail::enable_safe_integer_conversion<TypeT, IntegerT>>
351 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR integer& operator+=(const integer<TypeT>& other)
354 PHI_ASSERT(!detail::will_addition_error<IntegerT>(detail::arithmetic_tag_for<IntegerT>{},
355 m_Value, other.unsafe()),
356 "Addition will result in overflow. Args {} + {}", m_Value, other.unsafe());
358 m_Value += other.unsafe();
362 template <typename TypeT, typename = detail::enable_safe_integer_conversion<TypeT, IntegerT>>
363 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR integer& operator+=(const TypeT& other) PHI_NOEXCEPT
365 return *this += integer<TypeT>(other);
368 template <typename TypeT, typename = detail::fallback_safe_integer_conversion<TypeT, IntegerT>>
369 integer& operator+=(integer<TypeT>) = delete;
371 template <typename TypeT, typename = detail::fallback_safe_integer_conversion<TypeT, IntegerT>>
372 integer& operator+=(TypeT) = delete;
374 template <typename TypeT, typename = detail::enable_safe_integer_conversion<TypeT, IntegerT>>
375 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR integer& operator-=(const integer<TypeT>& other)
378 PHI_ASSERT(!detail::will_subtraction_error<IntegerT>(detail::arithmetic_tag_for<IntegerT>{},
379 m_Value, other.unsafe()),
380 "Subtraction will result in underflow. Args {} - {}", m_Value, other.unsafe());
382 m_Value -= other.unsafe();
386 template <typename TypeT, typename = detail::enable_safe_integer_conversion<TypeT, IntegerT>>
387 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR integer& operator-=(const TypeT& other) PHI_NOEXCEPT
389 return *this -= integer<TypeT>(other);
392 template <typename TypeT, typename = detail::fallback_safe_integer_conversion<TypeT, IntegerT>>
393 integer& operator-=(integer<TypeT>) = delete;
395 template <typename TypeT, typename = detail::fallback_safe_integer_conversion<TypeT, IntegerT>>
396 integer& operator-=(TypeT) = delete;
398 template <typename TypeT, typename = detail::enable_safe_integer_conversion<TypeT, IntegerT>>
399 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR integer& operator*=(const integer<TypeT>& other)
402 PHI_ASSERT(!detail::will_multiplication_error<IntegerT>(
403 detail::arithmetic_tag_for<IntegerT>{}, m_Value, other.unsafe()),
404 "Multiplication will result in overflow. Args {} * {}", m_Value, other.unsafe());
406 m_Value *= other.unsafe();
410 template <typename TypeT, typename = detail::enable_safe_integer_conversion<TypeT, IntegerT>>
411 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR integer& operator*=(const TypeT& other) PHI_NOEXCEPT
413 return *this *= integer<TypeT>(other);
416 template <typename TypeT, typename = detail::fallback_safe_integer_conversion<TypeT, IntegerT>>
417 integer& operator*=(integer<TypeT>) = delete;
419 template <typename TypeT, typename = detail::fallback_safe_integer_conversion<TypeT, IntegerT>>
420 integer& operator*=(TypeT) = delete;
422 template <typename TypeT, typename = detail::enable_safe_integer_conversion<TypeT, IntegerT>>
423 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR integer& operator/=(const integer<TypeT>& other)
426 PHI_ASSERT(!detail::will_division_error<IntegerT>(detail::arithmetic_tag_for<IntegerT>{},
427 m_Value, other.unsafe()),
428 "Division error. Args {} / {}", m_Value, other.unsafe());
430 m_Value /= other.unsafe();
434 template <typename TypeT, typename = detail::enable_safe_integer_conversion<TypeT, IntegerT>>
435 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR integer& operator/=(const TypeT& other) PHI_NOEXCEPT
437 return *this /= integer<TypeT>(other);
440 template <typename TypeT, typename = detail::fallback_safe_integer_conversion<TypeT, IntegerT>>
441 integer& operator/=(integer<TypeT>) = delete;
443 template <typename TypeT, typename = detail::fallback_safe_integer_conversion<TypeT, IntegerT>>
444 integer& operator/=(TypeT) = delete;
446 template <typename TypeT, typename = detail::enable_safe_integer_conversion<TypeT, IntegerT>>
447 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR integer& operator%=(const integer<TypeT>& other)
450 PHI_ASSERT(!detail::will_modulo_error<IntegerT>(m_Value, other.unsafe()),
451 "Modulo error. Args {} % {}", m_Value, other.unsafe());
453 m_Value %= other.unsafe();
457 template <typename TypeT, typename = detail::enable_safe_integer_conversion<TypeT, IntegerT>>
458 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR integer& operator%=(const TypeT& other) PHI_NOEXCEPT
460 return *this %= integer<TypeT>(other);
463 template <typename TypeT, typename = detail::fallback_safe_integer_conversion<TypeT, IntegerT>>
464 integer& operator%=(integer<TypeT>) = delete;
466 template <typename TypeT, typename = detail::fallback_safe_integer_conversion<TypeT, IntegerT>>
467 integer& operator%=(TypeT) = delete;
473 PHI_GCC_SUPPRESS_WARNING_POP()
477 template <typename LhsT, typename RhsT,
478 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
479 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator==(const integer<LhsT>& lhs,
480 const integer<RhsT>& rhs) PHI_NOEXCEPT
482 return static_cast<LhsT>(lhs) == static_cast<RhsT>(rhs);
485 template <typename LhsT, typename RhsT,
486 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
487 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator==(const LhsT& lhs,
488 const integer<RhsT>& rhs) PHI_NOEXCEPT
490 return integer<LhsT>(lhs) == rhs;
493 template <typename LhsT, typename RhsT,
494 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
495 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator==(const integer<LhsT>& lhs,
496 const RhsT& rhs) PHI_NOEXCEPT
498 return lhs == integer<RhsT>(rhs);
501 template <typename LhsT, typename RhsT,
502 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
503 PHI_CONSTEXPR boolean operator==(integer<LhsT>, integer<RhsT>) = delete;
505 template <typename LhsT, typename RhsT,
506 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
507 PHI_CONSTEXPR boolean operator==(LhsT, integer<RhsT>) = delete;
509 template <typename LhsT, typename RhsT,
510 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
511 PHI_CONSTEXPR boolean operator==(integer<LhsT>, RhsT) = delete;
513 template <typename LhsT, typename RhsT,
514 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
515 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator!=(const integer<LhsT>& lhs,
516 const integer<RhsT>& rhs) PHI_NOEXCEPT
518 return static_cast<LhsT>(lhs) != static_cast<RhsT>(rhs);
521 template <typename LhsT, typename RhsT,
522 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
523 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator!=(const LhsT& lhs,
524 const integer<RhsT>& rhs) PHI_NOEXCEPT
526 return integer<LhsT>(lhs) != rhs;
529 template <typename LhsT, typename RhsT,
530 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
531 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator!=(const integer<LhsT>& lhs,
532 const RhsT& rhs) PHI_NOEXCEPT
534 return lhs != integer<RhsT>(rhs);
537 template <typename LhsT, typename RhsT,
538 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
539 PHI_CONSTEXPR boolean operator!=(integer<LhsT>, integer<RhsT>) = delete;
541 template <typename LhsT, typename RhsT,
542 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
543 PHI_CONSTEXPR boolean operator!=(LhsT, integer<RhsT>) = delete;
545 template <typename LhsT, typename RhsT,
546 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
547 PHI_CONSTEXPR boolean operator!=(integer<LhsT>, RhsT) = delete;
549 template <typename LhsT, typename RhsT,
550 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
551 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator<(const integer<LhsT>& lhs,
552 const integer<RhsT>& rhs) PHI_NOEXCEPT
554 return static_cast<LhsT>(lhs) < static_cast<RhsT>(rhs);
557 template <typename LhsT, typename RhsT,
558 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
559 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator<(const LhsT& lhs,
560 const integer<RhsT>& rhs) PHI_NOEXCEPT
562 return integer<LhsT>(lhs) < rhs;
565 template <typename LhsT, typename RhsT,
566 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
567 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator<(const integer<LhsT>& lhs,
568 const RhsT& rhs) PHI_NOEXCEPT
570 return lhs < integer<RhsT>(rhs);
573 template <typename LhsT, typename RhsT,
574 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
575 PHI_CONSTEXPR boolean operator<(integer<LhsT>, integer<RhsT>) = delete;
577 template <typename LhsT, typename RhsT,
578 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
579 PHI_CONSTEXPR boolean operator<(LhsT, integer<RhsT>) = delete;
581 template <typename LhsT, typename RhsT,
582 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
583 PHI_CONSTEXPR boolean operator<(integer<LhsT>, RhsT) = delete;
585 template <typename LhsT, typename RhsT,
586 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
587 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator<=(const integer<LhsT>& lhs,
588 const integer<RhsT>& rhs) PHI_NOEXCEPT
590 return static_cast<LhsT>(lhs) <= static_cast<RhsT>(rhs);
593 template <typename LhsT, typename RhsT,
594 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
595 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator<=(const LhsT& lhs,
596 const integer<RhsT>& rhs) PHI_NOEXCEPT
598 return integer<LhsT>(lhs) <= rhs;
601 template <typename LhsT, typename RhsT,
602 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
603 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator<=(const integer<LhsT>& lhs,
604 const RhsT& rhs) PHI_NOEXCEPT
606 return lhs <= integer<RhsT>(rhs);
609 template <typename LhsT, typename RhsT,
610 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
611 PHI_CONSTEXPR boolean operator<=(integer<LhsT>, integer<RhsT>) = delete;
613 template <typename LhsT, typename RhsT,
614 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
615 PHI_CONSTEXPR boolean operator<=(LhsT, integer<RhsT>) = delete;
617 template <typename LhsT, typename RhsT,
618 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
619 PHI_CONSTEXPR boolean operator<=(integer<LhsT>, RhsT) = delete;
621 template <typename LhsT, typename RhsT,
622 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
623 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator>(const integer<LhsT>& lhs,
624 const integer<RhsT>& rhs) PHI_NOEXCEPT
626 return static_cast<LhsT>(lhs) > static_cast<RhsT>(rhs);
629 template <typename LhsT, typename RhsT,
630 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
631 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator>(const LhsT& lhs,
632 const integer<RhsT>& rhs) PHI_NOEXCEPT
634 return integer<LhsT>(lhs) > rhs;
637 template <typename LhsT, typename RhsT,
638 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
639 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator>(const integer<LhsT>& lhs,
640 const RhsT& rhs) PHI_NOEXCEPT
642 return lhs > integer<RhsT>(rhs);
645 template <typename LhsT, typename RhsT,
646 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
647 PHI_CONSTEXPR boolean operator>(integer<LhsT>, integer<RhsT>) = delete;
649 template <typename LhsT, typename RhsT,
650 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
651 PHI_CONSTEXPR boolean operator>(LhsT, integer<RhsT>) = delete;
653 template <typename LhsT, typename RhsT,
654 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
655 PHI_CONSTEXPR boolean operator>(integer<LhsT>, RhsT) = delete;
657 template <typename LhsT, typename RhsT,
658 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
659 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator>=(const integer<LhsT>& lhs,
660 const integer<RhsT>& rhs) PHI_NOEXCEPT
662 return static_cast<LhsT>(lhs) >= static_cast<RhsT>(rhs);
665 template <typename LhsT, typename RhsT,
666 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
667 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator>=(const LhsT& lhs,
668 const integer<RhsT>& rhs) PHI_NOEXCEPT
670 return integer<LhsT>(lhs) >= rhs;
673 template <typename LhsT, typename RhsT,
674 typename = detail::enable_safe_integer_comparison<LhsT, RhsT>>
675 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator>=(const integer<LhsT>& lhs,
676 const RhsT& rhs) PHI_NOEXCEPT
678 return lhs >= integer<RhsT>(rhs);
681 template <typename LhsT, typename RhsT,
682 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
683 PHI_CONSTEXPR boolean operator>=(integer<LhsT>, integer<RhsT>) = delete;
685 template <typename LhsT, typename RhsT,
686 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
687 PHI_CONSTEXPR boolean operator>=(LhsT, integer<RhsT>) = delete;
689 template <typename LhsT, typename RhsT,
690 typename = detail::fallback_safe_integer_comparison<LhsT, RhsT>>
691 PHI_CONSTEXPR boolean operator>=(integer<LhsT>, RhsT) = delete;
695 template <typename LhsT, typename RhsT>
696 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR auto operator+(const integer<LhsT>& lhs,
697 const integer<RhsT>& rhs)
698 PHI_NOEXCEPT->integer<detail::integer_result_t<LhsT, RhsT>>
700 using type = detail::integer_result_t<LhsT, RhsT>;
701 PHI_ASSERT(!detail::will_addition_error(detail::arithmetic_tag_for<type>{},
702 static_cast<type
>(lhs.unsafe()),
703 static_cast<type>(rhs.unsafe())),
704 "Addition will result in overflow. Args {} + {}", lhs.unsafe(), rhs.unsafe());
706 return integer<type>(
static_cast<type
>(
static_cast<LhsT
>(lhs) + static_cast<RhsT>(rhs)));
709 template <
typename LhsT,
typename RhsT>
710 PHI_ALWAYS_INLINE PHI_CONSTEXPR
auto operator+(
const LhsT& lhs,
const integer<RhsT>& rhs)
711 PHI_NOEXCEPT->integer<detail::integer_result_t<LhsT, RhsT>>
716 template <
typename LhsT,
typename RhsT>
717 PHI_ALWAYS_INLINE PHI_CONSTEXPR
auto operator+(
const integer<LhsT>& lhs,
const RhsT& rhs)
718 PHI_NOEXCEPT->integer<detail::integer_result_t<LhsT, RhsT>>
723 template <
typename LhsT,
typename RhsT,
typename = detail::fallback_
integer_result<LhsT, RhsT>>
726 template <
typename LhsT,
typename RhsT,
typename = detail::fallback_
integer_result<LhsT, RhsT>>
729 template <
typename LhsT,
typename RhsT,
typename = detail::fallback_
integer_result<LhsT, RhsT>>
732 template <
typename LhsT,
typename RhsT>
733 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR
auto operator-(
const integer<LhsT>& lhs,
735 PHI_NOEXCEPT->integer<detail::integer_result_t<LhsT, RhsT>>
737 using type = detail::integer_result_t<LhsT, RhsT>;
738 PHI_ASSERT(!detail::will_subtraction_error(detail::arithmetic_tag_for<type>{},
739 static_cast<type
>(lhs.unsafe()),
740 static_cast<type>(rhs.unsafe())),
741 "Subtraction will result in underflow. Args {} - {}", lhs.unsafe(), rhs.unsafe());
743 return integer<type>(
static_cast<type
>(
static_cast<LhsT
>(lhs) - static_cast<RhsT>(rhs)));
746 template <
typename LhsT,
typename RhsT>
747 PHI_ALWAYS_INLINE PHI_CONSTEXPR
auto operator-(
const LhsT& lhs,
const integer<RhsT>& rhs)
748 PHI_NOEXCEPT->integer<detail::integer_result_t<LhsT, RhsT>>
753 template <
typename LhsT,
typename RhsT>
754 PHI_ALWAYS_INLINE PHI_CONSTEXPR
auto operator-(
const integer<LhsT>& lhs,
const RhsT& rhs)
755 PHI_NOEXCEPT->integer<detail::integer_result_t<LhsT, RhsT>>
760 template <
typename LhsT,
typename RhsT,
typename = detail::fallback_
integer_result<LhsT, RhsT>>
763 template <
typename LhsT,
typename RhsT,
typename = detail::fallback_
integer_result<LhsT, RhsT>>
766 template <
typename LhsT,
typename RhsT,
typename = detail::fallback_
integer_result<LhsT, RhsT>>
769 template <
typename LhsT,
typename RhsT>
770 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR
auto operator*(
const integer<LhsT>& lhs,
772 PHI_NOEXCEPT->integer<detail::integer_result_t<LhsT, RhsT>>
774 using type = detail::integer_result_t<LhsT, RhsT>;
775 PHI_ASSERT(!detail::will_multiplication_error(detail::arithmetic_tag_for<type>{},
776 static_cast<type
>(lhs.unsafe()),
777 static_cast<type>(rhs.unsafe())),
778 "Multiplication will result in overflow. Args {} * {}", lhs.unsafe(), rhs.unsafe());
780 return integer<type>(
static_cast<type
>(
static_cast<LhsT
>(lhs) * static_cast<RhsT>(rhs)));
783 template <
typename LhsT,
typename RhsT>
784 PHI_ALWAYS_INLINE PHI_CONSTEXPR
auto operator*(
const LhsT& lhs,
const integer<RhsT>& rhs)
785 PHI_NOEXCEPT->integer<detail::integer_result_t<LhsT, RhsT>>
790 template <
typename LhsT,
typename RhsT>
791 PHI_ALWAYS_INLINE PHI_CONSTEXPR
auto operator*(
const integer<LhsT>& lhs,
const RhsT& rhs)
792 PHI_NOEXCEPT->integer<detail::integer_result_t<LhsT, RhsT>>
797 template <
typename LhsT,
typename RhsT,
typename = detail::fallback_
integer_result<LhsT, RhsT>>
800 template <
typename LhsT,
typename RhsT,
typename = detail::fallback_
integer_result<LhsT, RhsT>>
803 template <
typename LhsT,
typename RhsT,
typename = detail::fallback_
integer_result<LhsT, RhsT>>
806 template <
typename LhsT,
typename RhsT>
807 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR
auto operator/(
const integer<LhsT>& lhs,
809 PHI_NOEXCEPT->integer<detail::integer_result_t<LhsT, RhsT>>
811 using type = detail::integer_result_t<LhsT, RhsT>;
812 PHI_ASSERT(!detail::will_division_error(detail::arithmetic_tag_for<type>{},
813 static_cast<type
>(lhs.unsafe()),
814 static_cast<type>(rhs.unsafe())),
815 "Division by zero/overflow. Args {} / {}", lhs.unsafe(), rhs.unsafe());
817 return integer<type>(
static_cast<type
>(
static_cast<LhsT
>(lhs) / static_cast<RhsT>(rhs)));
820 template <
typename LhsT,
typename RhsT>
821 PHI_ALWAYS_INLINE PHI_CONSTEXPR
auto operator/(
const LhsT& lhs,
const integer<RhsT>& rhs)
822 PHI_NOEXCEPT->integer<detail::integer_result_t<LhsT, RhsT>>
827 template <
typename LhsT,
typename RhsT>
828 PHI_ALWAYS_INLINE PHI_CONSTEXPR
auto operator/(
const integer<LhsT>& lhs,
const RhsT& rhs)
829 PHI_NOEXCEPT->integer<detail::integer_result_t<LhsT, RhsT>>
834 template <
typename LhsT,
typename RhsT,
typename = detail::fallback_
integer_result<LhsT, RhsT>>
837 template <
typename LhsT,
typename RhsT,
typename = detail::fallback_
integer_result<LhsT, RhsT>>
840 template <
typename LhsT,
typename RhsT,
typename = detail::fallback_
integer_result<LhsT, RhsT>>
843 template <
typename LhsT,
typename RhsT>
844 PHI_ALWAYS_INLINE PHI_EXTENDED_CONSTEXPR
auto operator%(
const integer<LhsT>& lhs,
846 PHI_NOEXCEPT->integer<detail::integer_result_t<LhsT, RhsT>>
848 using type = detail::integer_result_t<LhsT, RhsT>;
849 PHI_ASSERT(!detail::will_modulo_error(static_cast<type>(lhs.unsafe()),
850 static_cast<type>(rhs.unsafe())),
851 "Modulo by zero. Args {} % {}", lhs.unsafe(), rhs.unsafe());
853 return integer<type>(
static_cast<type
>(
static_cast<LhsT
>(lhs) % static_cast<RhsT>(rhs)));
856 template <
typename LhsT,
typename RhsT>
857 PHI_ALWAYS_INLINE PHI_CONSTEXPR
auto operator%(
const LhsT& lhs,
const integer<RhsT>& rhs)
858 PHI_NOEXCEPT->integer<detail::integer_result_t<LhsT, RhsT>>
863 template <
typename LhsT,
typename RhsT>
864 PHI_ALWAYS_INLINE PHI_CONSTEXPR
auto operator%(
const integer<LhsT>& lhs,
const RhsT& rhs)
865 PHI_NOEXCEPT->integer<detail::integer_result_t<LhsT, RhsT>>
870 template <
typename LhsT,
typename RhsT,
typename = detail::fallback_
integer_result<LhsT, RhsT>>
873 template <
typename LhsT,
typename RhsT,
typename = detail::fallback_
integer_result<LhsT, RhsT>>
876 template <
typename LhsT,
typename RhsT,
typename = detail::fallback_
integer_result<LhsT, RhsT>>
881 template <
typename CharT,
typename CharTraitsT,
typename IntegerT>
882 std::basic_istream<CharT, CharTraitsT>& operator>>(std::basic_istream<CharT, CharTraitsT>& stream,
885 IntegerT val{IntegerT(0)};
891 template <
typename CharT,
typename CharTraitsT,
typename IntegerT>
892 std::basic_ostream<CharT, CharTraitsT>& operator<<(std::basic_ostream<CharT, CharTraitsT>& stream,
895 return stream << static_cast<IntegerT>(val);
898 template <
typename IntegerT>
905 DETAIL_PHI_END_NAMESPACE()
907 DETAIL_PHI_BEGIN_STD_NAMESPACE()
909 template <
typename IntegerT>
913 phi::size_t operator()(
const phi::integer<IntegerT>& val)
const PHI_NOEXCEPT
915 return std::hash<IntegerT>()(static_cast<IntegerT>(val));
919 template <
typename IntegerT>
920 struct numeric_limits<
phi::integer<IntegerT>> :
public std::numeric_limits<IntegerT>
923 DETAIL_PHI_END_STD_NAMESPACE()
925 #endif // INCG_PHI_CORE_INTEGER_HPP Definition: integral_constant.hpp:19
A type safe integer class.
Definition: integer.hpp:58
Definition: common_type.test.cpp:195