10 #if !defined(SG14_NUMERIC_TRAITS) 11 #define SG14_NUMERIC_TRAITS 1 13 #if !defined(SG14_GODBOLT_ORG) 15 #include "bits/limits.h" 16 #include "bits/type_traits.h" 25 using _digits_type = int;
30 template<
class T,
class Enable =
void>
31 struct is_composite : std::false_type {
32 static_assert(!std::is_reference<T>::value,
"T is a reference");
33 static_assert(!std::is_const<T>::value,
"T is const");
34 static_assert(!std::is_volatile<T>::value,
"T is volatile");
37 #if (__cplusplus > 201402L) 39 constexpr
auto is_composite_v = is_composite<T>::value;
42 namespace _num_traits_impl {
46 template<
class ... Args>
50 struct are_composite<> : std::false_type {
53 template<
class ArgHead,
class ... ArgTail>
54 struct are_composite<ArgHead, ArgTail...>
55 : std::integral_constant<bool, is_composite<typename std::decay<ArgHead>::type>::value || are_composite<ArgTail...>::value> {
61 template<_digits_type MinNumDigits,
class Smaller,
class T>
62 struct enable_for_range
63 : std::enable_if<MinNumDigits <= std::numeric_limits<T>::digits &&
64 std::numeric_limits<Smaller>::digits < MinNumDigits> {
67 template<_digits_type MinNumDigits, class Smallest>
68 struct enable_for_range<MinNumDigits, void, Smallest>
69 : std::enable_if<MinNumDigits <= std::numeric_limits<Smallest>::digits> {
72 template<_digits_type MinNumDigits, class Smaller, class T>
73 using enable_for_range_t = typename enable_for_range<MinNumDigits, Smaller, T>::type;
78 template<_digits_type MinNumDigits, class Enable = void>
79 struct set_digits_signed;
81 template<_digits_type MinNumDigits>
82 struct set_digits_signed<MinNumDigits, enable_for_range_t<MinNumDigits, void, std::int8_t>> {
83 using type = std::int8_t;
86 template<_digits_type MinNumDigits>
87 struct set_digits_signed<MinNumDigits, enable_for_range_t<MinNumDigits, std::int8_t, std::int16_t>> {
88 using type = std::int16_t;
91 template<_digits_type MinNumDigits>
92 struct set_digits_signed<MinNumDigits, enable_for_range_t<MinNumDigits, std::int16_t, std::int32_t>> {
93 using type = std::int32_t;
96 template<_digits_type MinNumDigits>
97 struct set_digits_signed<MinNumDigits, enable_for_range_t<MinNumDigits, std::int32_t, std::int64_t>> {
98 using type = std::int64_t;
101 #if defined(SG14_INT128_ENABLED)
102 template<_digits_type MinNumDigits>
103 struct set_digits_signed<MinNumDigits, enable_for_range_t<MinNumDigits, std::int64_t, SG14_INT128>> {
104 using type = SG14_INT128;
111 template<_digits_type MinNumDigits, class Enable = void>
112 struct set_digits_unsigned;
114 template<_digits_type MinNumDigits>
115 struct set_digits_unsigned<MinNumDigits, enable_for_range_t<MinNumDigits, void, std::uint8_t>> {
116 using type = std::uint8_t;
119 template<_digits_type MinNumDigits>
120 struct set_digits_unsigned<MinNumDigits, enable_for_range_t<MinNumDigits, std::uint8_t, std::uint16_t>> {
121 using type = std::uint16_t;
124 template<_digits_type MinNumDigits>
125 struct set_digits_unsigned<MinNumDigits, enable_for_range_t<MinNumDigits, std::uint16_t, std::uint32_t>> {
126 using type = std::uint32_t;
129 template<_digits_type MinNumDigits>
130 struct set_digits_unsigned<MinNumDigits, enable_for_range_t<MinNumDigits, std::uint32_t, std::uint64_t>> {
131 using type = std::uint64_t;
134 #if defined(SG14_INT128_ENABLED)
135 template<_digits_type MinNumDigits>
136 struct set_digits_unsigned<MinNumDigits, enable_for_range_t<MinNumDigits, std::uint64_t, SG14_UINT128>> {
137 using type = SG14_UINT128;
144 template<class Integer, _digits_type MinNumDigits>
145 using set_digits_integer = typename std::conditional<
146 std::numeric_limits<Integer>::is_signed,
147 set_digits_signed<MinNumDigits>,
148 set_digits_unsigned<MinNumDigits>>::type;
154 template<class T, class Enable = void>
155 struct digits : std::integral_constant<_digits_type, std::numeric_limits<T>::digits> {
158 #if (__cplusplus > 201402L)
160 constexpr _digits_type digits_v = digits<T>::value;
166 template<class T, _digits_type Digits, class Enable = void>
169 template<class T, _digits_type Digits>
170 struct set_digits<T, Digits, _impl::enable_if_t<std::is_integral<T>::value>>
171 : _num_traits_impl::set_digits_integer<T, Digits> {
174 #if defined(SG14_INT128_ENABLED)
175 template<_digits_type Digits>
176 struct set_digits<SG14_INT128, Digits>
177 : _num_traits_impl::set_digits_integer<signed, Digits> {
180 template<_digits_type Digits>
181 struct set_digits<SG14_UINT128, Digits>
182 : _num_traits_impl::set_digits_integer<unsigned, Digits> {
186 template<class T, _digits_type Digits>
187 using set_digits_t = typename set_digits<T, Digits>::type;
193 struct is_signed : std::integral_constant<bool, std::numeric_limits<T>::is_signed> {
199 template<class, class = void>
203 struct make_signed<T, _impl::enable_if_t<std::is_integral<T>::value>> : std::make_signed<T> {
207 using make_signed_t = typename make_signed<T>::type;
212 template<class, class = void>
213 struct make_unsigned;
216 struct make_unsigned<T, _impl::enable_if_t<std::is_integral<T>::value>> : std::make_unsigned<T> {
219 #if defined(SG14_INT128_ENABLED)
222 struct make_unsigned<SG14_INT128> {
223 using type = SG14_UINT128;
226 struct make_unsigned<SG14_UINT128> {
227 using type = SG14_UINT128;
231 struct make_signed<SG14_INT128> {
232 using type = SG14_INT128;
235 struct make_signed<SG14_UINT128> {
236 using type = SG14_INT128;
241 using make_unsigned_t = typename make_unsigned<T>::type;
247 template<class T, bool IsSigned = true>
251 struct make_signed<T, true> : ::sg14::make_signed<T> {
255 struct make_signed<T, false> : ::sg14::make_unsigned<T> {
258 template<class T, bool IsSigned>
259 using make_signed_t = typename make_signed<T, IsSigned>::type;
264 template<class T1, class T2>
265 struct common_signedness {
266 static constexpr bool _are_signed = std::numeric_limits<T1>::is_signed | std::numeric_limits<T2>::is_signed;
268 using type = typename std::common_type<make_signed_t<T1, _are_signed>,
269 make_signed_t<T2, _are_signed>>::type;
272 template<class T1, class T2>
273 using common_signedness_t = typename common_signedness<T1, T2>::type;
278 template<class T, class Enable = void>
279 struct unsigned_or_float;
282 struct unsigned_or_float<T, enable_if_t<std::numeric_limits<T>::is_iec559>> {
287 struct unsigned_or_float<T, enable_if_t<!std::numeric_limits<T>::is_iec559>> : make_unsigned<T> {
291 using unsigned_or_float_t = typename unsigned_or_float<T>::type;
293 template<class Encompasser, class Encompassed, class Enable = void>
294 struct encompasses_lower;
296 template<class Encompasser, class Encompassed>
297 struct encompasses_lower<Encompasser, Encompassed,
298 enable_if_t<std::numeric_limits<Encompasser>::is_signed
299 && std::numeric_limits<Encompassed>::is_signed>> {
300 static constexpr bool value = std::numeric_limits<Encompasser>::lowest()
301 <= std::numeric_limits<Encompassed>::lowest();
304 template<class Encompasser, class Encompassed>
305 struct encompasses_lower<Encompasser, Encompassed,
306 enable_if_t<!std::numeric_limits<Encompassed>::is_signed>> : std::true_type {
309 template<class Encompasser, class Encompassed>
310 struct encompasses_lower<Encompasser, Encompassed,
311 enable_if_t<!std::numeric_limits<Encompasser>::is_signed
312 && std::numeric_limits<Encompassed>::is_signed>> : std::false_type {
316 template<class Encompasser, class Encompassed>
318 static constexpr bool _lower = encompasses_lower<Encompasser, Encompassed>::value;
319 static constexpr bool _upper =
320 static_cast<unsigned_or_float_t<Encompasser>>(std::numeric_limits<Encompasser>::max())
321 >= static_cast<unsigned_or_float_t<Encompassed>>(std::numeric_limits<Encompassed>::max());
323 static constexpr bool value = _lower && _upper;
330 struct is_integer_or_float : std::integral_constant<
332 std::numeric_limits<T>::is_integer || std::numeric_limits<T>::is_iec559> {
339 template<class Number, class Enable = void>
341 constexpr Number operator()(const Number &number) const {
348 template<class Number, class Enable = void>
349 constexpr auto to_rep(const Number &number)
350 -> decltype(sg14::to_rep<Number>()(number)) {
351 return sg14::to_rep<Number>()(number);
358 template<class Number, class Enable = void>
361 constexpr Number operator()(const Rep &rep) const {
363 return static_cast<Number>(rep);
368 template<class Number, class Rep>
369 constexpr auto from_rep(const Rep &rep)
370 -> decltype(sg14::from_rep<Number>()(rep)) {
371 return sg14::from_rep<Number>()(rep);
379 template<
class Result,
class F,
class ... Args,
380 _impl::enable_if_t<!_num_traits_impl::are_composite<Args ...>::value,
int> dummy = 0>
381 constexpr Result for_rep(F f, Args &&...args) {
382 return f(std::forward<Args>(args)...);
385 template<
class Result,
class F,
class ... Args,
386 _impl::enable_if_t<_num_traits_impl::are_composite<Args ...>::value,
int> dummy = 0>
387 constexpr Result for_rep(F f, Args &&...args) {
388 return for_rep<Result>(f, _impl::to_rep<typename std::decay<Args>::type>(std::forward<Args>(args))...);
395 template<
class Number,
class Value,
class Enable =
void>
398 template<
class Number,
class Value>
399 struct from_value<Number, Value, _impl::enable_if_t<std::is_integral<Number>::value>> {
403 template<
class Number,
class Value>
404 using from_value_t =
typename from_value<Number, Value>::type;
407 template<
class Number,
class Value>
408 constexpr
auto from_value(
const Value &value)
409 -> sg14::from_value_t<Number, Value> {
417 namespace _num_traits_impl {
419 using scale_result_type = decltype(std::declval<T>() * std::declval<T>());
422 constexpr scale_result_type<T> pown(
int base,
int exp) {
424 ? pown<T>(base, exp - 1) *
static_cast<scale_result_type<T>
>(base)
425 : static_cast<scale_result_type<T>>(1);
429 constexpr scale_result_type<T> pow2(
int exp) {
430 return scale_result_type<T>{1} << exp;
434 constexpr scale_result_type<T> pow(
int base,
int exp) {
435 return (base == 2) ? pow2<T>(exp) : pown<T>(base, exp);
441 constexpr
auto operator()(
const T &i,
int base,
int exp)
const 442 -> _num_traits_impl::scale_result_type<T> {
443 return _impl::from_rep<_num_traits_impl::scale_result_type<T>>(
445 ? _impl::to_rep<T>(i) / _num_traits_impl::pow<T>(base, -exp)
446 : _impl::to_rep<T>(i) * _num_traits_impl::pow<T>(base, exp));
452 constexpr
auto scale(
const T &i,
int base,
int exp)
453 -> decltype(sg14::scale<T>()(i, base, exp)) {
454 return sg14::scale<T>()(i, base, exp);
459 #endif // SG14_NUMERIC_TRAITS study group 14 of the C++ working group
Definition: const_integer.h:22