fixed_point (deprecated)  rev.2
Binary Fixed-Point Arithmetic Library in C++
const_integer.h
1 
2 // Copyright John McFarlane 2015 - 2016.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file ../LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
9 
10 #if !defined(SG14_CONST_INTEGER_H)
11 #define SG14_CONST_INTEGER_H 1
12 
13 #include <sg14/auxiliary/numeric.h>
14 #include <sg14/bits/common.h>
15 
16 #include <cstdint>
17 
18 #if defined(SG14_EXCEPTIONS_ENABLED)
19 #include <stdexcept>
20 #endif
21 
22 namespace sg14 {
23  namespace _const_integer_impl {
24 
26  // sg14::_impl::digits_to_integral_constant
27  //
28  // return intrgral_constant given string of digits
29 
30  constexpr std::intmax_t combine(int, std::intmax_t p)
31  {
32  return p;
33  }
34 
35  template<class... TT>
36  constexpr std::intmax_t combine(int base, std::intmax_t val, int p0, TT... pp)
37  {
38  return combine(base, val * base + p0, pp...);
39  }
40 
41  constexpr int parse_dec(char C)
42  {
43 #if defined(SG14_EXCEPTIONS_ENABLED)
44  return (C>='0' && C<='9')
45  ? C-'0'
46  : throw std::out_of_range("only decimal digits are allowed");
47 #else
48  return C-'0';
49 #endif
50  }
51 
52  constexpr int parse_hex(char C) {
53  return (C >= '0' && C <= '9')
54  ? C - '0'
55  : (C >= 'a' && C <= 'f')
56  ? C - 'a'
57  : (C >= 'A' && C <= 'F')
58  ? C - 'A'
59 #if defined(SG14_EXCEPTIONS_ENABLED)
60  : throw std::out_of_range("only decimal digits are allowed")
61 #else
62  : 0
63 #endif
64  ;
65  }
66 
67  template<char... Digits>
68  struct digits_to_integral {
69  static constexpr std::intmax_t value = combine(10, 0, parse_dec(Digits)...);
70  };
71 
72  template<char... Digits>
73  struct digits_to_integral<'0', 'x', Digits...> {
74  static constexpr std::intmax_t value = combine(16, 0, parse_hex(Digits)...);
75  };
76 
77  template<char... Digits>
78  struct digits_to_integral<'0', 'X', Digits...> {
79  static constexpr std::intmax_t value = combine(16, 0, parse_hex(Digits)...);
80  };
81  }
82 
84  // sg14::const_integer
85 
92 
93  template<
94  class Integral,
95  Integral Value,
96  int Digits = used_bits(Value),
97  int Exponent = trailing_bits(Value)>
98  class const_integer {
99  public:
100  using value_type = Integral;
101  static constexpr value_type value = Value;
102 
103  template<class T>
104  constexpr explicit operator T() const { return value; }
105 
106  static constexpr int digits = Digits;
107  static_assert(
108  digits == used_bits(Value),
109  "defaulted non-type template parameters should not be specified explicitly");
110 
111  static constexpr int exponent = Exponent;
112  static_assert(
113  exponent == trailing_bits(Value),
114  "defaulted non-type template parameters should not be specified explicitly");
115  };
116 
118  // sg14::const_integer arithmetic operator overloads
119 
120  namespace _const_integer_impl {
121  template<class Lhs, class Rhs, class Type>
122  struct enable_if_op;
123 
124  template<
125  class LhsIntegral, LhsIntegral LhsValue, int LhsDigits, int LhsExponent,
126  class RhsIntegral, RhsIntegral RhsValue, int RhsDigits, int RhsExponent,
127  class Type>
128  struct enable_if_op<
129  const_integer<LhsIntegral, LhsValue, LhsDigits, LhsExponent>,
130  const_integer<RhsIntegral, RhsValue, RhsDigits, RhsExponent>,
131  Type> {
132  using type = Type;
133  };
134 
135  template<
136  class LhsIntegral, LhsIntegral LhsValue, int LhsDigits, int LhsExponent,
137  class Rhs,
138  class Type>
139  struct enable_if_op<
140  const_integer<LhsIntegral, LhsValue, LhsDigits, LhsExponent>,
141  Rhs,
142  Type> {
143  using type = Type;
144  };
145 
146  template<
147  class Lhs,
148  class RhsIntegral, RhsIntegral RhsValue, int RhsDigits, int RhsExponent,
149  class Type>
150  struct enable_if_op<
151  Lhs,
152  const_integer<RhsIntegral, RhsValue, RhsDigits, RhsExponent>,
153  Type> {
154  using type = Type;
155  };
156 
157  // Lhs OP const_integer
158  template<
159  class Operator,
160  class Lhs,
161  class RhsIntegral, RhsIntegral RhsValue, int RhsDigits, int RhsExponent,
162  class = _impl::enable_if_t<std::is_integral<Lhs>::value>>
163  constexpr auto operate(
164  const Lhs& lhs,
166  Operator op)
167  -> decltype(op(lhs, RhsValue)) {
168  return op(lhs, RhsValue);
169  }
170 
171  // const_integer OP Lhs
172  template<
173  class Operator,
174  class LhsIntegral, LhsIntegral LhsValue, int LhsDigits, int LhsExponent,
175  class Rhs,
176  class = _impl::enable_if_t<std::is_integral<Rhs>::value, int>>
177  constexpr auto operate(
179  const Rhs& rhs,
180  Operator op)
181  -> decltype(op(LhsValue, rhs)) {
182  return op(LhsValue, rhs);
183  }
184 
185  // const_integer OP const_integer
186  template<
187  class Operator,
188  class LhsIntegral, LhsIntegral LhsValue, int LhsDigits, int LhsExponent,
189  class RhsIntegral, RhsIntegral RhsValue, int RhsDigits, int RhsExponent>
190  constexpr auto operate(
193  Operator)
194  -> decltype(const_integer<_impl::op_result<Operator, LhsIntegral, RhsIntegral>, Operator()(LhsValue, RhsValue)>{}) {
195  return const_integer<_impl::op_result<Operator, LhsIntegral, RhsIntegral>, Operator()(LhsValue, RhsValue)>{};
196  }
197  }
198 
199  template<class Lhs, class Rhs, typename _const_integer_impl::enable_if_op<Lhs, Rhs, int>::type dummy = 0>
200  constexpr auto operator+(const Lhs& lhs, const Rhs& rhs)
201  -> decltype(_const_integer_impl::operate(lhs, rhs, _impl::add_tag))
202  {
203  return _const_integer_impl::operate(lhs, rhs, _impl::add_tag);
204  }
205 
206  template<class Lhs, class Rhs, typename _const_integer_impl::enable_if_op<Lhs, Rhs, int>::type dummy = 0>
207  constexpr auto operator-(const Lhs& lhs, const Rhs& rhs)
208  -> decltype(_const_integer_impl::operate(lhs, rhs, _impl::subtract_tag))
209  {
210  return _const_integer_impl::operate(lhs, rhs, _impl::subtract_tag);
211  }
212 
213  template<class Lhs, class Rhs, typename _const_integer_impl::enable_if_op<Lhs, Rhs, int>::type dummy = 0>
214  constexpr auto operator*(const Lhs& lhs, const Rhs& rhs)
215  -> decltype(_const_integer_impl::operate(lhs, rhs, _impl::multiply_tag))
216  {
217  return _const_integer_impl::operate(lhs, rhs, _impl::multiply_tag);
218  }
219 
220  template<class Lhs, class Rhs, typename _const_integer_impl::enable_if_op<Lhs, Rhs, int>::type dummy = 0>
221  constexpr auto operator/(const Lhs& lhs, const Rhs& rhs)
222  -> decltype(_const_integer_impl::operate(lhs, rhs, _impl::divide_tag))
223  {
224  return _const_integer_impl::operate(lhs, rhs, _impl::divide_tag);
225  }
226 
228  // sg14::const_integer comparison operator overloads
229 
230  namespace _const_integer_impl {
231  // const_integer OP const_integer
232  template<
233  class Operator,
234  class LhsIntegral, LhsIntegral LhsValue, int LhsDigits, int LhsExponent,
235  class RhsIntegral, RhsIntegral RhsValue, int RhsDigits, int RhsExponent>
236  constexpr auto compare(
239  Operator op)
240  -> decltype(op(LhsValue, RhsValue))
241  {
242  return op(LhsValue, RhsValue);
243  }
244  }
245 
246  template<class Lhs, class Rhs, typename _const_integer_impl::enable_if_op<Lhs, Rhs, int>::type dummy = 0>
247  constexpr auto operator==(const Lhs& lhs, const Rhs& rhs)
248  -> decltype(_const_integer_impl::compare(lhs, rhs, _impl::equal_tag))
249  {
250  return _const_integer_impl::compare(lhs, rhs, _impl::equal_tag);
251  }
252 
253 #if ! defined(_MSC_VER) || (_MSC_VER > 1900)
254  template<class RhsIntegral, RhsIntegral RhsValue>
255  constexpr const_integer<decltype(-RhsValue), -RhsValue>
256  operator-(const_integer<RhsIntegral, RhsValue>) noexcept
257  {
258  return const_integer<decltype(-RhsValue), -RhsValue>{};
259  }
260 #endif
261 
263  // sg14::const_integer type traits
264 
265  template<class T>
266  struct is_const_integer : std::false_type {};
267 
268  template<class Integral, Integral Value>
269  struct is_const_integer<const_integer<Integral, Value>> : std::true_type {};
270 
272  // sg14::literals - literal wrapper for std::integral_constant
273  //
274  // http://codereview.stackexchange.com/a/51576/26421
275 
276  namespace literals {
277  template<char... Digits>
278  constexpr auto operator "" _c()
279  -> const_integer<std::intmax_t, _const_integer_impl::digits_to_integral<Digits...>::value>
280  {
281  return {};
282  }
283  }
284 }
285 namespace std {
287  // std::common_type<const_integer<>, ...>
288 
289  template<class Integral, Integral Value, int Digits, int Zeros, class Rhs>
290  struct common_type<sg14::const_integer<Integral, Value, Digits, Zeros>, Rhs>
291  : common_type<Integral, Rhs> {
292  };
293 
294  template<class Lhs, class Integral, Integral Value, int Digits, int Zeros>
295  struct common_type<Lhs, sg14::const_integer<Integral, Value, Digits, Zeros>>
296  : common_type<Lhs, Integral> {
297  };
298 
300  // std::numeric_limits<const_integer<>>
301 
302  template<class Integral, Integral Value, int Digits, int Zeros>
303  struct numeric_limits<sg14::const_integer<Integral, Value, Digits, Zeros>>
304  : numeric_limits<Integral> {
306  static constexpr int digits = Digits;
307  };
308 }
309 
310 #endif // SG14_CONST_INTEGER_H
STL namespace.
a compile-time-only integer type like a std::integral_constant with arithmetic support ...
Definition: const_integer.h:98
study group 14 of the C++ working group
Definition: const_integer.h:22