7 #if !defined(CNL_IMPL_ROUNDING_TAGGED_CONVERT_OPERATOR_H)
8 #define CNL_IMPL_ROUNDING_TAGGED_CONVERT_OPERATOR_H
10 #include "../custom_operator/native_tag.h"
11 #include "native_rounding_tag.h"
12 #include "nearest_rounding_tag.h"
13 #include "neg_inf_rounding_tag.h"
14 #include "tie_to_pos_inf_rounding_tag.h"
17 #include <type_traits>
23 struct is_arithmetic_or_integer
25 bool, std::is_floating_point<N>::value || std::numeric_limits<N>::is_integer> {
28 template<
class N1,
class N2>
29 struct are_arithmetic_or_integer
32 is_arithmetic_or_integer<N1>::value && is_arithmetic_or_integer<N2>::value> {
37 template<
typename Source, tag SrcTag,
typename Destination>
38 requires(!_impl::is_rounding_tag<SrcTag>::value)
struct custom_operator<
40 op_value<Source, SrcTag>,
41 op_value<Destination, native_rounding_tag>> {
42 [[nodiscard]] constexpr
auto operator()(Source
const& from)
const
44 return custom_operator<
45 _impl::convert_op, op_value<Source, SrcTag>, op_value<Destination>>{}(from);
49 template<
typename Source, tag SrcTag,
typename Destination>
50 requires(!_impl::is_rounding_tag<SrcTag>::value && _impl::are_arithmetic_or_integer<Destination, Source>::value)
struct custom_operator<_impl::convert_op, op_value<Source, SrcTag>, op_value<Destination, nearest_rounding_tag>> {
51 [[nodiscard]] constexpr
auto operator()(Source
const& from)
const
54 ?
static_cast<Destination
>(
55 static_cast<long double>(from) + ((from >= Source{}) ? .5L : -.5L))
56 :
static_cast<Destination
>(from);
60 template<
typename Source, tag SrcTag,
typename Destination>
61 requires(!_impl::is_rounding_tag<SrcTag>::value && _impl::are_arithmetic_or_integer<Destination, Source>::value)
struct custom_operator<_impl::convert_op, op_value<Source, SrcTag>, op_value<Destination, tie_to_pos_inf_rounding_tag>> {
63 [[nodiscard]]
static constexpr
auto floor_residual(Source x, Source x_whole)
65 return static_cast<Destination
>((x < Source(0)) && (x < x_whole));
67 [[nodiscard]]
static constexpr
auto floor_int(Source x, Source x_whole)
69 return (x_whole -
static_cast<Source
>(floor_residual(x, x_whole)));
71 [[nodiscard]]
static constexpr
auto floor(Source x)
73 return floor_int(x,
static_cast<Source
>(
static_cast<Destination
>(x)));
77 [[nodiscard]] constexpr
auto operator()(Source
const& from)
const
80 ?
static_cast<Destination
>(
floor(from +
static_cast<Source
>(.5L)))
81 :
static_cast<Destination
>(from);
85 template<
typename Source, tag SrcTag,
typename Destination>
86 requires(!_impl::is_rounding_tag<SrcTag>::value && _impl::are_arithmetic_or_integer<Destination, Source>::value)
struct custom_operator<_impl::convert_op, op_value<Source, SrcTag>, op_value<Destination, neg_inf_rounding_tag>> {
88 [[nodiscard]]
static constexpr
auto floor_residual(Source x, Source x_whole)
90 return static_cast<Destination
>((x < Source(0)) && (x < x_whole));
92 [[nodiscard]]
static constexpr
auto floor_int(Source x, Source x_whole)
94 return (x_whole -
static_cast<Source
>(floor_residual(x, x_whole)));
96 [[nodiscard]]
static constexpr
auto floor(Source x)
98 return floor_int(x,
static_cast<Source
>(
static_cast<Destination
>(x)));
102 [[nodiscard]] constexpr
auto operator()(Source
const& from)
const
105 ?
static_cast<Destination
>(
floor(from))
106 :
static_cast<Destination
>(from);
111 template<
typename Source, rounding_tag SrcTag,
typename Destination>
112 struct custom_operator<_impl::convert_op, op_value<Source, SrcTag>, op_value<Destination>> {
113 [[nodiscard]] constexpr
auto operator()(Source
const& from)
const
115 return custom_operator<_impl::convert_op, op_value<Source>, op_value<Destination>>{}(
120 template<
typename Source, rounding_tag SrcRoundingTag,
typename Destination, rounding_tag DestRoundingTag>
121 struct custom_operator<_impl::convert_op, op_value<Source, SrcRoundingTag>, op_value<Destination, DestRoundingTag>>
122 : custom_operator<_impl::convert_op, op_value<Source>, op_value<Destination, DestRoundingTag>> {
126 #endif // CNL_IMPL_ROUNDING_TAGGED_CONVERT_OPERATOR_H