10 #if !defined(SG14_ELASTIC_INTEGER_H) 11 #define SG14_ELASTIC_INTEGER_H 1 13 #include <sg14/bits/number_base.h> 21 template<
int Digits,
class Narrowest>
27 namespace _elastic_integer_impl {
28 template<
int Digits,
class Narrowest>
30 static constexpr _digits_type digits = Digits;
32 static constexpr _digits_type rep_digits = _impl::max(sg14::digits<Narrowest>::value, digits);
34 using rep =
typename set_digits<Narrowest, rep_digits>::type;
35 using type = _impl::number_base<elastic_integer<Digits, Narrowest>,
rep>;
38 template<
int Digits,
class Narrowest>
39 using base_class_t =
typename base_class<Digits, Narrowest>::type;
42 template<
int Digits,
class Narrowest>
43 struct digits<
elastic_integer<Digits, Narrowest>> : std::integral_constant<_digits_type, Digits> {
44 static constexpr _digits_type value = Digits;
47 template<
int Digits,
class Narrowest, _digits_type MinNumBits>
53 template<
int Digits,
class Narrowest>
55 using type = Narrowest;
58 template<
int Digits,
class OldNarrowest,
class NewNarrowest>
64 template<
int Digits,
class Narrowest,
class Value>
69 template<
int Digits,
class Narrowest>
73 constexpr _value_type operator()(
const _value_type& i,
int base,
int exp)
const {
74 using _rep =
typename _value_type::rep;
75 return _value_type{ _impl::scale(i.data(), base, exp) };
90 template<
int Digits,
class Narrowest =
int>
91 class elastic_integer :
public _elastic_integer_impl::base_class_t<Digits, Narrowest> {
92 static_assert(Digits > 0,
"type requires positive number of digits");
93 using _base = _elastic_integer_impl::base_class_t<Digits, Narrowest>;
96 static constexpr
int digits = Digits;
102 using rep =
typename _base::rep;
114 template<class Number, _impl::enable_if_t<std::numeric_limits<Number>::is_specialized,
int> Dummy = 0>
116 : _base(static_cast<
rep>(n))
121 template<
int FromW
idth,
class FromNarrowest>
123 :_base(static_cast<
rep>(rhs.data()))
128 template<
class Integral, Integral Value,
int Exponent>
130 : _base(static_cast<
rep>(Value))
132 static_assert(!sg14::is_signed<Integral>::value || sg14::is_signed<rep>::value,
"initialization by out-of-range value");
136 template<class S, _impl::enable_if_t<std::is_floating_point<S>::value,
int> Dummy = 0>
139 _base::operator=(floating_point_to_rep(s));
145 explicit constexpr
operator S()
const 147 return static_cast<S
>(_base::data());
155 class Integral, Integral Value>
162 template<class Narrowest = int, class Integral, _impl::enable_if_t<!is_const_integer<Integral>::value,
int> Dummy = 0>
163 constexpr
auto make_elastic_integer(
const Integral& value)
164 -> decltype(
elastic_integer<std::numeric_limits<Integral>::digits, Narrowest>{value})
169 namespace _elastic_integer_impl {
173 template<
class ElasticInteger>
174 struct is_elastic_integer : std::false_type {
177 template<
int Digits,
class Narrowest>
178 struct is_elastic_integer<elastic_integer<Digits, Narrowest>> : std::true_type {
185 template<
class Lhs,
class Rhs>
186 struct are_integer_class_operands {
187 static constexpr
int integer_class = is_elastic_integer<Lhs>::value+is_elastic_integer<Rhs>::value;
188 static constexpr
int integer_or_float =
189 _impl::is_integer_or_float<Lhs>::value+_impl::is_integer_or_float<Rhs>::value;
190 static constexpr
bool value = (integer_class>=1) && (integer_or_float==2);
198 template<
int RhsDigits,
class RhsNarrowest>
204 return elastic_integer::from_data(
207 ^ ((
static_cast<rep>(~0)) >> (std::numeric_limits<rep>::digits - RhsDigits))));
211 template<
int LhsDigits,
class LhsNarrowest,
class Rhs>
212 constexpr
auto operator<<(const elastic_integer<LhsDigits, LhsNarrowest>& lhs,
const Rhs& rhs)
218 template<
class Lhs,
int RhsDigits,
class RhsNarrowest>
219 constexpr
auto operator<<(const Lhs& lhs, const elastic_integer<RhsDigits, RhsNarrowest>& rhs)
220 -> decltype(lhs << 0)
222 return lhs << rhs.data();
226 template<
int LhsDigits,
class LhsNarrowest,
class Rhs>
233 template<
class Lhs,
int RhsDigits,
class RhsNarrowest>
235 -> decltype(lhs >> 0)
237 return lhs >> rhs.data();
244 template<
int FromDigits,
class FromNarrowest,
int OtherDigits,
class OtherNarrowest,
245 _impl::enable_if_t<FromDigits!=OtherDigits || !std::is_same<FromNarrowest, OtherNarrowest>::value, std::nullptr_t> Dummy =
nullptr>
246 constexpr
auto cast_to_common_type(
249 -> decltype(
static_cast<_impl::common_type_t<
252 return static_cast<_impl::common_type_t<
257 template<
class Operator,
int LhsDigits,
class LhsNarrowest,
int RhsDigits,
class RhsNarrowest,
258 #if defined(__GNUG__) 259 bool Enable = Operator::is_comparison>
261 enable_if_t<Operator::is_comparison>...>
263 constexpr
auto operate(
267 -> decltype(op(cast_to_common_type(lhs, rhs), cast_to_common_type(rhs, lhs)))
269 return op(cast_to_common_type(lhs, rhs), cast_to_common_type(rhs, lhs));
272 template<
class Operator,
int Digits,
class Narrowest,
273 class = enable_if_t<Operator::is_comparison>>
276 -> decltype(op(lhs.data(), rhs.data()))
278 return op(lhs.data(), rhs.data());
289 template<
class Operation,
class LhsTraits,
class RhsTraits>
292 template<
class LhsTraits,
class RhsTraits>
293 struct policy<_impl::add_op, LhsTraits, RhsTraits> {
294 static constexpr
int digits = _impl::max(LhsTraits::digits, RhsTraits::digits)+1;
295 static constexpr
bool is_signed = LhsTraits::is_signed || RhsTraits::is_signed;
298 template<
class LhsTraits,
class RhsTraits>
299 struct policy<_impl::subtract_op, LhsTraits, RhsTraits> {
300 static constexpr
int digits = _impl::max(LhsTraits::digits, RhsTraits::digits) + (LhsTraits::is_signed | RhsTraits::is_signed);
301 static constexpr
bool is_signed =
true;
304 template<
class LhsTraits,
class RhsTraits>
305 struct policy<_impl::multiply_op, LhsTraits, RhsTraits> {
306 static constexpr
int contribution(
int operand_digits) {
return operand_digits == 1 ? 0 : operand_digits; }
307 static constexpr
int digits = max(1, contribution(LhsTraits::digits)+contribution(RhsTraits::digits));
308 static constexpr
bool is_signed = LhsTraits::is_signed || RhsTraits::is_signed;
311 template<
class LhsTraits,
class RhsTraits>
312 struct policy<_impl::divide_op, LhsTraits, RhsTraits> {
313 static constexpr
int digits = LhsTraits::digits;
314 static constexpr
bool is_signed = LhsTraits::is_signed || RhsTraits::is_signed;
317 template<
class LhsTraits,
class RhsTraits>
318 struct policy<_impl::bitwise_or_op, LhsTraits, RhsTraits> {
319 static constexpr
int digits = _impl::max(LhsTraits::digits, RhsTraits::digits);
320 static constexpr
bool is_signed = LhsTraits::is_signed || RhsTraits::is_signed;
323 template<
class LhsTraits,
class RhsTraits>
324 struct policy<_impl::bitwise_and_op, LhsTraits, RhsTraits> {
325 static constexpr
int digits = _impl::min(LhsTraits::digits, RhsTraits::digits);
326 static constexpr
bool is_signed = LhsTraits::is_signed || RhsTraits::is_signed;
329 template<
class LhsTraits,
class RhsTraits>
330 struct policy<_impl::bitwise_xor_op, LhsTraits, RhsTraits> {
331 static constexpr
int digits = _impl::max(LhsTraits::digits, RhsTraits::digits);
332 static constexpr
bool is_signed = LhsTraits::is_signed || RhsTraits::is_signed;
338 template<
class OperationTag,
int LhsDigits,
class LhsNarrowest,
int RhsDigits,
class RhsNarrowest,
339 class = enable_if_t<OperationTag::is_arithmetic>>
340 struct operate_params {
343 using lhs_traits = std::numeric_limits<lhs>;
344 using rhs_traits = std::numeric_limits<rhs>;
346 using policy =
typename _impl::policy<OperationTag, lhs_traits, rhs_traits>;
348 using lhs_rep =
typename lhs::rep;
349 using rhs_rep =
typename rhs::rep;
350 using rep_result =
typename _impl::op_result<OperationTag, lhs_rep, rhs_rep>;
352 static constexpr _digits_type narrowest_width = _impl::max(
353 digits<LhsNarrowest>::value + sg14::is_signed<LhsNarrowest>::value,
354 digits<RhsNarrowest>::value + sg14::is_signed<RhsNarrowest>::value);
355 using narrowest = set_digits_t<_impl::make_signed_t<rep_result, policy::is_signed>, narrowest_width-policy::is_signed>;
362 template<
class Operator,
int LhsDigits,
class LhsNarrowest,
int RhsDigits,
class RhsNarrowest,
363 #if defined(__GNUG__) 364 bool Enable = Operator::is_arithmetic>
366 enable_if_t<Operator::is_arithmetic>...>
368 constexpr
auto operate(
372 ->
typename operate_params<Operator, LhsDigits, LhsNarrowest, RhsDigits, RhsNarrowest>::result_type
374 using result_type =
typename operate_params<Operator, LhsDigits, LhsNarrowest, RhsDigits, RhsNarrowest>::result_type;
375 return result_type::from_data(
376 static_cast<typename result_type::rep>(op(
377 static_cast<result_type>(lhs).data(),
378 static_cast<result_type>(rhs).data())));
383 template<
int RhsDigits,
class RhsNarrowest>
388 return result_type::from_data(-static_cast<result_type>(rhs).data());
392 template<
int RhsDigits,
class RhsNarrowest>
397 return result_type::from_data(static_cast<result_type>(rhs).data());
402 template<
int LhsDigits,
class LhsNarrowest,
int RhsDigits,
class RhsNarrowest>
405 sg14::_impl::max(LhsDigits, RhsDigits),
406 sg14::_impl::common_signedness_t<LhsNarrowest, RhsNarrowest>>;
409 template<
int LhsDigits,
class LhsNarrowest,
class Rhs>
410 struct common_type<sg14::
elastic_integer<LhsDigits, LhsNarrowest>, Rhs>
411 : common_type<sg14::elastic_integer<LhsDigits, LhsNarrowest>, sg14::elastic_integer<std::numeric_limits<Rhs>::digits, Rhs>> {
414 template<
class Lhs,
int RhsDigits,
class RhsNarrowest>
415 struct common_type<Lhs, sg14::
elastic_integer<RhsDigits, RhsNarrowest>>
416 : common_type<sg14::elastic_integer<std::numeric_limits<Lhs>::digits, Lhs>, sg14::elastic_integer<RhsDigits, RhsNarrowest>> {
422 namespace _elastic_integer_impl {
427 template<
class Rep,
bool IsSigned>
431 struct lowest<Rep, true> {
432 constexpr Rep operator()(
const Rep& max)
const noexcept
439 struct lowest<Rep, false> {
440 constexpr Rep operator()(
const Rep&)
const noexcept
447 template<
int Digits,
class Narrowest>
449 : numeric_limits<Narrowest> {
451 using _narrowest_numeric_limits = numeric_limits<Narrowest>;
453 using _rep =
typename _value_type::rep;
454 using _rep_numeric_limits = numeric_limits<_rep>;
456 static constexpr _rep _rep_max() noexcept
458 return _rep_numeric_limits::max() >> (_rep_numeric_limits::digits-digits);
462 static constexpr
int digits = Digits;
464 static constexpr _value_type min() noexcept
466 return _value_type::from_data(1);
469 static constexpr _value_type max() noexcept
471 return _value_type::from_data(_rep_max());
474 static constexpr _value_type lowest() noexcept
476 return _elastic_integer_impl::lowest<_rep, _narrowest_numeric_limits::is_signed>()(_rep_max());
481 #endif // SG14_ELASTIC_INTEGER_H constexpr elastic_integer(const_integer< Integral, Value, Digits, Exponent >)
constructor taking an integral constant
Definition: elastic_integer.h:129
literal integer type that encodes its width in bits within its type
Definition: elastic_integer.h:22
constexpr elastic_integer(const elastic_integer< FromWidth, FromNarrowest > &rhs)
constructor taking an elastic_integer type
Definition: elastic_integer.h:122
elastic_integer & operator=(S s)
copy assignment operator taking a floating-point type
Definition: elastic_integer.h:137
a compile-time-only integer type like a std::integral_constant with arithmetic support ...
Definition: const_integer.h:98
constexpr elastic_integer(Number n)
construct from numeric type
Definition: elastic_integer.h:115
typename _base::rep rep
the actual type used to store the value; closely related to Narrowest but may be a different width ...
Definition: elastic_integer.h:102
constexpr elastic_integer(const elastic_integer &rhs)
common copy constructor
Definition: elastic_integer.h:108
Narrowest narrowest
alias to template parameter, Narrowest
Definition: elastic_integer.h:99
study group 14 of the C++ working group
Definition: const_integer.h:22