7 #if !defined(SG14_number_base_H) 8 #define SG14_number_base_H 1 10 #include <sg14/auxiliary/const_integer.h> 11 #include <sg14/bits/common.h> 12 #include <sg14/num_traits.h> 15 #include <type_traits> 19 template<
class Derived,
class Rep>
23 using _derived = Derived;
25 number_base() =
default;
27 constexpr number_base(
const rep& r)
31 number_base& operator=(
const T& r) {
33 return static_cast<Derived&
>(*this);
36 explicit constexpr
operator bool()
const 38 return static_cast<bool>(_rep);
41 constexpr
const rep& data()
const 46 static constexpr Derived from_data(
const rep& r)
61 template<
class Derived,
class Enable =
void>
62 struct is_class_derived_from_number_base : std::false_type {};
64 template<
class Derived>
65 struct is_class_derived_from_number_base<
67 enable_if_t<
std::is_base_of<number_base<Derived, typename Derived::rep>, Derived>::value>>
74 template<
class T,
class Enable =
void>
75 struct is_derived_from_number_base : std::false_type {};
77 template<
class Derived>
78 struct is_derived_from_number_base<Derived, enable_if_t<std::is_class<Derived>::value>>
79 : is_class_derived_from_number_base<Derived> { };
84 template<
class Former,
class Latter>
86 static constexpr
bool value =
87 (std::is_floating_point<Former>::value && !std::is_floating_point<Latter>::value)
88 || (is_derived_from_number_base<Former>::value &&
89 !(is_derived_from_number_base<Latter>::value
90 || std::is_floating_point<Latter>::value));
98 class Operator,
class Lhs,
class RhsDerived,
class RhsRep,
99 enable_if_t <precedes<Lhs, RhsDerived>::value, std::nullptr_t> =
nullptr>
100 constexpr
auto operate(
const Lhs& lhs,
const number_base<RhsDerived, RhsRep>& rhs, Operator op)
101 -> decltype(op(lhs, static_cast<Lhs>(static_cast<const RhsDerived&>(rhs))))
103 return op(lhs, static_cast<Lhs>(static_cast<const RhsDerived&>(rhs)));
108 class Operator,
class LhsDerived,
class LhsRep,
class Rhs,
109 enable_if_t <precedes<Rhs, LhsDerived>::value, std::nullptr_t> =
nullptr>
110 constexpr
auto operate(
const number_base<LhsDerived, LhsRep>& lhs,
const Rhs& rhs, Operator op)
111 -> decltype(op(static_cast<Rhs>(static_cast<const LhsDerived&>(lhs)), rhs))
113 return op(static_cast<Rhs>(static_cast<const LhsDerived&>(lhs)), rhs);
118 class Operator,
class Lhs,
class RhsDerived,
class RhsRep,
119 enable_if_t <precedes<RhsDerived, Lhs>::value, std::nullptr_t> =
nullptr>
120 constexpr
auto operate(
const Lhs& lhs,
const number_base<RhsDerived, RhsRep>& rhs, Operator op)
121 -> decltype(op(_impl::from_value<RhsDerived>(lhs), static_cast<const RhsDerived&>(rhs))) {
122 return op(from_value<RhsDerived>(lhs), static_cast<const RhsDerived&>(rhs));
127 class Operator,
class LhsDerived,
class LhsRep,
class Rhs,
128 enable_if_t <precedes<LhsDerived, Rhs>::value, std::nullptr_t> =
nullptr>
129 constexpr
auto operate(
const number_base<LhsDerived, LhsRep>& lhs,
const Rhs& rhs, Operator op)
130 -> decltype(op(static_cast<const LhsDerived &>(lhs), from_value<LhsDerived>(rhs)))
132 return op(static_cast<const LhsDerived &>(lhs), from_value<LhsDerived>(rhs));
136 template<
class Operator,
class RhsDerived,
class RhsRep>
137 constexpr
auto operate(
const number_base<RhsDerived, RhsRep>& rhs, Operator op)
138 -> decltype(op(rhs.data()))
140 return op(rhs.data());
148 template<class Lhs, class Rhs, class = enable_if_t <is_derived_from_number_base<Lhs>::value>>
149 auto operator+=(Lhs& lhs,
const Rhs& rhs)
150 -> decltype(lhs = lhs + rhs)
152 return lhs = lhs + rhs;
155 template<class Lhs, class Rhs, class = enable_if_t <is_derived_from_number_base<Lhs>::value>>
156 auto operator-=(Lhs& lhs,
const Rhs& rhs)
157 -> decltype(lhs = lhs - rhs)
159 return lhs = lhs - rhs;
162 template<class Lhs, class Rhs, class = enable_if_t <is_derived_from_number_base<Lhs>::value>>
163 auto operator*=(Lhs& lhs,
const Rhs& rhs)
164 -> decltype(lhs = lhs * rhs)
166 return lhs = lhs * rhs;
169 template<class Lhs, class Rhs, class = enable_if_t <is_derived_from_number_base<Lhs>::value>>
170 auto operator/=(Lhs& lhs,
const Rhs& rhs)
171 -> decltype(lhs = lhs / rhs)
173 return lhs = lhs / rhs;
178 template<
class RhsDerived,
class RhsRep>
179 constexpr
auto operator+(
const number_base<RhsDerived, RhsRep>& rhs)
180 -> decltype(operate(rhs, plus_tag))
182 return operate(rhs, plus_tag);
185 template<
class RhsDerived,
class RhsRep>
186 constexpr
auto operator-(
const number_base<RhsDerived, RhsRep>& rhs)
187 -> decltype(operate(rhs, minus_tag))
189 return operate(rhs, minus_tag);
194 template<
class Lhs,
class Rhs>
195 constexpr
auto operator+(
const Lhs& lhs,
const Rhs& rhs)
196 -> decltype(operate(lhs, rhs, add_tag))
198 return operate(lhs, rhs, add_tag);
201 template<
class Lhs,
class Rhs>
202 constexpr
auto operator-(
const Lhs& lhs,
const Rhs& rhs)
203 -> decltype(operate(lhs, rhs, subtract_tag))
205 return operate(lhs, rhs, subtract_tag);
208 template<
class Lhs,
class Rhs>
209 constexpr
auto operator*(
const Lhs& lhs,
const Rhs& rhs)
210 -> decltype(operate(lhs, rhs, multiply_tag))
212 return operate(lhs, rhs, multiply_tag);
215 template<
class Lhs,
class Rhs>
216 constexpr
auto operator/(
const Lhs& lhs,
const Rhs& rhs)
217 -> decltype(operate(lhs, rhs, divide_tag))
219 return operate(lhs, rhs, divide_tag);
224 template<
class Lhs,
class Rhs>
225 constexpr
auto operator|(
const Lhs& lhs,
const Rhs& rhs)
226 -> decltype(operate(lhs, rhs, bitwise_or_tag))
228 return operate(lhs, rhs, bitwise_or_tag);
231 template<
class Lhs,
class Rhs>
232 constexpr
auto operator&(
const Lhs& lhs,
const Rhs& rhs)
233 -> decltype(operate(lhs, rhs, bitwise_and_tag))
235 return operate(lhs, rhs, bitwise_and_tag);
238 template<
class Lhs,
class Rhs>
239 constexpr
auto operator^(
const Lhs& lhs,
const Rhs& rhs)
240 -> decltype(operate(lhs, rhs, bitwise_xor_tag))
242 return operate(lhs, rhs, bitwise_xor_tag);
247 template<
class Lhs,
class Rhs>
248 constexpr
auto operator==(
const Lhs& lhs,
const Rhs& rhs)
249 -> decltype(operate(lhs, rhs, equal_tag))
251 return operate(lhs, rhs, equal_tag);
254 template<
class Lhs,
class Rhs>
255 constexpr
auto operator!=(
const Lhs& lhs,
const Rhs& rhs)
256 -> decltype(operate(lhs, rhs, not_equal_tag))
258 return operate(lhs, rhs, not_equal_tag);
261 template<
class Lhs,
class Rhs>
262 constexpr
auto operator<(
const Lhs& lhs,
const Rhs& rhs)
263 -> decltype(operate(lhs, rhs, less_than_tag))
265 return operate(lhs, rhs, less_than_tag);
268 template<
class Lhs,
class Rhs>
269 constexpr
auto operator>(
const Lhs& lhs,
const Rhs& rhs)
270 -> decltype(operate(lhs, rhs, greater_than_tag))
272 return operate(lhs, rhs, greater_than_tag);
275 template<
class Lhs,
class Rhs>
276 constexpr
auto operator<=(
const Lhs& lhs,
const Rhs& rhs)
277 -> decltype(operate(lhs, rhs, less_than_or_equal_tag))
279 return operate(lhs, rhs, less_than_or_equal_tag);
282 template<
class Lhs,
class Rhs>
283 constexpr
auto operator>=(
const Lhs& lhs,
const Rhs& rhs)
284 -> decltype(operate(lhs, rhs, greater_than_or_equal_tag))
286 return operate(lhs, rhs, greater_than_or_equal_tag);
293 template<
class Number>
294 struct is_composite<Number, _impl::enable_if_t<_impl::is_derived_from_number_base<Number>::value>> : std::true_type {
298 template<
class Number>
301 template<
class Number>
302 using get_rep_t =
typename get_rep<Number>::type;
306 template<
class Number,
class NewRep,
class Enable =
void>
309 template<
class Number,
class NewRep>
310 using set_rep_t =
typename set_rep<Number, NewRep>::type;
313 template<
class Number>
314 struct make_signed<Number, _impl::enable_if_t<_impl::is_derived_from_number_base<Number>::value>> {
315 using type = _impl::set_rep_t<Number, make_signed_t<_impl::get_rep_t<Number>>>;
318 template<
class Number>
319 struct make_unsigned<Number, _impl::enable_if_t<_impl::is_derived_from_number_base<Number>::value>> {
320 using type = _impl::set_rep_t<Number, make_unsigned_t<_impl::get_rep_t<Number>>>;
323 template<
class Number>
324 struct from_rep<Number, _impl::enable_if_t<_impl::is_derived_from_number_base<Number>::value>> {
326 constexpr
auto operator()(
const Rep &rep)
const -> Number {
327 return Number::from_data(static_cast<typename Number::rep>(rep));
331 template<
class Number>
332 struct to_rep<Number, _impl::enable_if_t<_impl::is_derived_from_number_base<Number>::value>> {
333 constexpr
auto operator()(
const typename Number::_derived& number)
const 334 -> decltype(number.data()){
335 return number.data();
339 template<
class Derived,
class Rep>
340 struct scale<_impl::number_base<Derived, Rep>> {
341 template<
class Input>
342 constexpr Rep operator()(
const Input &i,
int base,
int exp)
const {
344 ? _impl::to_rep(i) / _num_traits_impl::pow<Rep>(base, -exp)
345 : _impl::to_rep(i) * _num_traits_impl::pow<Rep>(base, exp);
354 template<
class Derived,
class Rep>
355 struct numeric_limits<
sg14::_impl::number_base<Derived, Rep>>
356 : numeric_limits<Rep> {
358 using _value_type = Derived;
359 using _rep =
typename _value_type::rep;
360 using _rep_numeric_limits = numeric_limits<_rep>;
364 static constexpr _value_type min() noexcept
366 return _value_type::from_data(_rep_numeric_limits::min());
369 static constexpr _value_type max() noexcept
371 return _value_type::from_data(_rep_numeric_limits::max());
374 static constexpr _value_type lowest() noexcept
376 return _value_type::from_data(_rep_numeric_limits::lowest());
379 static constexpr _value_type epsilon() noexcept
381 return _value_type::from_data(_rep_numeric_limits::round_error());
384 static constexpr _value_type round_error() noexcept
386 return static_cast<_value_type
>(_rep_numeric_limits::round_error());
389 static constexpr _value_type infinity() noexcept
391 return static_cast<_value_type
>(_rep_numeric_limits::infinity());
394 static constexpr _value_type quiet_NaN() noexcept
396 return static_cast<_value_type
>(_rep_numeric_limits::quiet_NaN());
399 static constexpr _value_type signaling_NaN() noexcept
401 return static_cast<_value_type
>(_rep_numeric_limits::signaling_NaN());
404 static constexpr _value_type denorm_min() noexcept
406 return static_cast<_value_type
>(_rep_numeric_limits::denorm_min());
411 #endif // SG14_NUMBER_BASE_H
study group 14 of the C++ working group
Definition: const_integer.h:22