BitShares-Core  7.0.2
BitShares blockchain node software and command-line wallet software
safe.hpp
Go to the documentation of this file.
1 #pragma once
3 #include <fc/reflect/reflect.hpp>
4 
5 #include <limits>
6 
7 namespace fc {
8 
9  template< typename T, std::enable_if_t< std::is_integral<T>::value, bool > = true >
10  struct safe_base
11  {
12  // Nothing here
13  };
14 
25  template<typename T>
26  struct safe : safe_base<T>
27  {
28  T value = 0;
29 
30  safe() = default;
31 
32  // Both T and V are signed
33  template< typename V, typename... Dummy, typename X = T,
34  std::enable_if_t< std::is_signed<X>::value, bool > = true,
35  std::enable_if_t< std::is_integral<V>::value, bool > = true,
36  std::enable_if_t< std::is_signed<V>::value, bool > = true >
37  static T check( V v )
38  {
39  static_assert( 0 == sizeof...(Dummy), "Unexpected template argument(s)" );
40  if( v > std::numeric_limits<T>::max() )
41  FC_CAPTURE_AND_THROW( overflow_exception, (v) );
42  if( v < std::numeric_limits<T>::min() )
44  return static_cast<T>( v );
45  }
46 
47  // Both T and V are unsigned
48  template< typename V, typename... Dummy, typename X = T,
49  std::enable_if_t< std::is_unsigned<X>::value, bool > = true,
50  std::enable_if_t< std::is_integral<V>::value, bool > = true,
51  std::enable_if_t< std::is_unsigned<V>::value, bool > = true >
52  static T check( V v )
53  {
54  static_assert( 0 == sizeof...(Dummy), "Unexpected template argument(s)" );
55  if( v > std::numeric_limits<T>::max() )
56  FC_CAPTURE_AND_THROW( overflow_exception, (v) );
57  return static_cast<T>( v );
58  }
59 
60  // T is unsigned and V is signed
61  template< typename V, typename... Dummy, typename X = T,
62  std::enable_if_t< std::is_unsigned<X>::value, bool > = true,
63  std::enable_if_t< std::is_integral<V>::value, bool > = true,
64  std::enable_if_t< std::is_signed<V>::value, bool > = true >
65  static T check( V v )
66  {
67  static_assert( 0 == sizeof...(Dummy), "Unexpected template argument(s)" );
68  if( v < 0 )
70  if( static_cast< typename std::make_unsigned_t<V> >(v) > std::numeric_limits<T>::max() )
71  FC_CAPTURE_AND_THROW( overflow_exception, (v) );
72  return static_cast<T>( v );
73  }
74 
75  // T is signed and V is unsigned
76  template< typename V, typename... Dummy, typename X = T,
77  std::enable_if_t< std::is_signed<X>::value, bool > = true,
78  std::enable_if_t< std::is_integral<V>::value, bool > = true,
79  std::enable_if_t< std::is_unsigned<V>::value, bool > = true >
80  static T check( V v )
81  {
82  static_assert( 0 == sizeof...(Dummy), "Unexpected template argument(s)" );
83  if( v > static_cast< typename std::make_unsigned_t<T> >( std::numeric_limits<T>::max() ) )
84  FC_CAPTURE_AND_THROW( overflow_exception, (v) );
85  return static_cast<T>( v );
86  }
87 
88  template< typename V >
89  safe( V v ) : value( check(v) )
90  {
91  // Nothing else to do
92  }
93 
94  template< typename V >
95  safe& operator = ( V v )
96  {
97  value = check(v);
98  return *this;
99  }
100 
101  static constexpr safe min()
102  {
103  return std::numeric_limits<T>::min();
104  }
105  static constexpr safe max()
106  {
107  return std::numeric_limits<T>::max();
108  }
109 
110  friend safe operator + ( const safe& a, const safe& b )
111  {
112  if( b.value > 0 && a.value > (std::numeric_limits<T>::max() - b.value) )
113  FC_CAPTURE_AND_THROW( overflow_exception, (a)(b) );
114  if( b.value < 0 && a.value < (std::numeric_limits<T>::min() - b.value) )
116  return safe( a.value + b.value );
117  }
118  friend safe operator - ( const safe& a, const safe& b )
119  {
120  if( b.value > 0 && a.value < (std::numeric_limits<T>::min() + b.value) )
122  if( b.value < 0 && a.value > (std::numeric_limits<T>::max() + b.value) )
123  FC_CAPTURE_AND_THROW( overflow_exception, (a)(b) );
124  return safe( a.value - b.value );
125  }
126 
127  friend safe operator * ( const safe& a, const safe& b )
128  {
129  if( a.value > 0 )
130  {
131  if( b.value > 0 )
132  {
133  if( a.value > (std::numeric_limits<T>::max() / b.value) )
134  FC_CAPTURE_AND_THROW( overflow_exception, (a)(b) );
135  }
136  else
137  {
138  if( b.value < (std::numeric_limits<T>::min() / a.value) )
140  }
141  }
142  else
143  {
144  if( b.value > 0 )
145  {
146  if( a.value < (std::numeric_limits<T>::min() / b.value) )
148  }
149  else
150  {
151  if( a.value != 0 && b.value < (std::numeric_limits<T>::max() / a.value) )
152  FC_CAPTURE_AND_THROW( overflow_exception, (a)(b) );
153  }
154  }
155 
156  return safe( a.value * b.value );
157  }
158 
159  // T is signed
160  template< typename... Dummy, typename X = T,
161  std::enable_if_t< std::is_signed<X>::value, bool > = true >
162  friend safe operator / ( const safe& a, const safe& b )
163  {
164  static_assert( 0 == sizeof...(Dummy), "Unexpected template argument(s)" );
165  if( b.value == 0 ) FC_CAPTURE_AND_THROW( divide_by_zero_exception, (a)(b) );
166  if( a.value == std::numeric_limits<T>::min() && b.value == -1 )
167  FC_CAPTURE_AND_THROW( overflow_exception, (a)(b) );
168  return safe( a.value / b.value );
169  }
170  // T is unsigned
171  template< typename... Dummy, typename X = T,
172  std::enable_if_t< std::is_unsigned<X>::value, bool > = true >
173  friend safe operator / ( const safe& a, const safe& b )
174  {
175  static_assert( 0 == sizeof...(Dummy), "Unexpected template argument(s)" );
176  if( b.value == 0 ) FC_CAPTURE_AND_THROW( divide_by_zero_exception, (a)(b) );
177  return safe( a.value / b.value );
178  }
179 
180  // T is signed
181  template< typename... Dummy, typename X = T,
182  std::enable_if_t< std::is_signed<X>::value, bool > = true >
183  friend safe operator % ( const safe& a, const safe& b )
184  {
185  static_assert( 0 == sizeof...(Dummy), "Unexpected template argument(s)" );
186  if( b.value == 0 ) FC_CAPTURE_AND_THROW( divide_by_zero_exception, (a)(b) );
187  if( a.value == std::numeric_limits<T>::min() && b.value == -1 )
188  FC_CAPTURE_AND_THROW( overflow_exception, (a)(b) );
189  return safe( a.value % b.value );
190  }
191  // T is unsigned
192  template< typename... Dummy, typename X = T,
193  std::enable_if_t< std::is_unsigned<X>::value, bool > = true >
194  friend safe operator % ( const safe& a, const safe& b )
195  {
196  static_assert( 0 == sizeof...(Dummy), "Unexpected template argument(s)" );
197  if( b.value == 0 ) FC_CAPTURE_AND_THROW( divide_by_zero_exception, (a)(b) );
198  return safe( a.value % b.value );
199  }
200 
201  // T is signed
202  template< typename... Dummy, typename X = T,
203  std::enable_if_t< std::is_signed<X>::value, bool > = true >
205  {
206  static_assert( 0 == sizeof...(Dummy), "Unexpected template argument(s)" );
207  if( value == min() ) FC_CAPTURE_AND_THROW( overflow_exception, (*this) );
208  return safe( -value );
209  }
210  // T is unsigned
211  template< typename... Dummy, typename X = T,
212  std::enable_if_t< std::is_unsigned<X>::value, bool > = true >
214  {
215  static_assert( 0 == sizeof...(Dummy), "Unexpected template argument(s)" );
216  if( value != 0 ) FC_CAPTURE_AND_THROW( underflow_exception, (*this) );
217  return safe( 0 );
218  }
219 
220  safe& operator += ( const safe& b )
221  {
222  value = (*this + b).value;
223  return *this;
224  }
225  safe& operator -= ( const safe& b )
226  {
227  value = (*this - b).value;
228  return *this;
229  }
230  safe& operator *= ( const safe& b )
231  {
232  value = (*this * b).value;
233  return *this;
234  }
235  safe& operator /= ( const safe& b )
236  {
237  value = (*this / b).value;
238  return *this;
239  }
240  safe& operator %= ( const safe& b )
241  {
242  value = (*this % b).value;
243  return *this;
244  }
245 
247  {
248  *this += 1;
249  return *this;
250  }
252  {
253  safe bak = *this;
254  *this += 1;
255  return bak;
256  }
257 
259  {
260  *this -= 1;
261  return *this;
262  }
264  {
265  safe bak = *this;
266  *this -= 1;
267  return bak;
268  }
269 
270  friend bool operator == ( const safe& a, const safe& b )
271  {
272  return a.value == b.value;
273  }
274  friend bool operator == ( const safe& a, T b )
275  {
276  return a.value == b;
277  }
278  friend bool operator == ( T a, const safe& b )
279  {
280  return a == b.value;
281  }
282 
283  friend bool operator < ( const safe& a, const safe& b )
284  {
285  return a.value < b.value;
286  }
287  friend bool operator < ( const safe& a, T b )
288  {
289  return a.value < b;
290  }
291  friend bool operator < ( T a, const safe& b )
292  {
293  return a < b.value;
294  }
295 
296  friend bool operator > ( const safe& a, const safe& b )
297  {
298  return a.value > b.value;
299  }
300  friend bool operator > ( const safe& a, T b )
301  {
302  return a.value > b;
303  }
304  friend bool operator > ( T a, const safe& b )
305  {
306  return a > b.value;
307  }
308 
309  friend bool operator != ( const safe& a, const safe& b )
310  {
311  return !(a == b);
312  }
313  friend bool operator != ( const safe& a, T b )
314  {
315  return !(a == b);
316  }
317  friend bool operator != ( T a, const safe& b )
318  {
319  return !(a == b);
320  }
321 
322  friend bool operator <= ( const safe& a, const safe& b )
323  {
324  return !(a > b);
325  }
326  friend bool operator <= ( const safe& a, T b )
327  {
328  return !(a > b);
329  }
330  friend bool operator <= ( T a, const safe& b )
331  {
332  return !(a > b);
333  }
334 
335  friend bool operator >= ( const safe& a, const safe& b )
336  {
337  return !(a < b);
338  }
339  friend bool operator >= ( const safe& a, T b )
340  {
341  return !(a < b);
342  }
343  friend bool operator >= ( T a, const safe& b )
344  {
345  return !(a < b);
346  }
347  };
348 
349 }
350 
351 FC_REFLECT_TEMPLATE( (typename T), safe<T>, (value) )
fc::safe::operator*=
safe & operator*=(const safe &b)
Definition: safe.hpp:230
fc::safe::operator=
safe & operator=(V v)
Definition: safe.hpp:95
fc::safe::operator*
friend safe operator*(const safe &a, const safe &b)
Definition: safe.hpp:127
fc::safe::operator%=
safe & operator%=(const safe &b)
Definition: safe.hpp:240
fc::safe::operator<=
friend bool operator<=(const safe &a, const safe &b)
Definition: safe.hpp:322
fc::safe::operator==
friend bool operator==(const safe &a, const safe &b)
Definition: safe.hpp:270
fc
Definition: api.hpp:15
fc::safe::operator!=
friend bool operator!=(const safe &a, const safe &b)
Definition: safe.hpp:309
fc::safe::operator/
friend safe operator/(const safe &a, const safe &b)
Definition: safe.hpp:162
fc::safe_base
Definition: safe.hpp:10
fc::safe::check
static T check(V v)
Definition: safe.hpp:37
fc::safe::operator>=
friend bool operator>=(const safe &a, const safe &b)
Definition: safe.hpp:335
FC_REFLECT_TEMPLATE
#define FC_REFLECT_TEMPLATE(TEMPLATE_ARGS, TYPE, MEMBERS)
Definition: reflect.hpp:392
reflect.hpp
Defines types and macros used to provide reflection.
fc::safe::min
static constexpr safe min()
Definition: safe.hpp:101
fc::safe::operator++
safe operator++(int)
Definition: safe.hpp:251
fc::safe::safe
safe()=default
fc::safe::operator--
safe & operator--()
Definition: safe.hpp:258
fc::safe::max
static constexpr safe max()
Definition: safe.hpp:105
fc::safe::operator>
friend bool operator>(const safe &a, const safe &b)
Definition: safe.hpp:296
fc::underflow_exception
() file_not_found_exception() parse_error_exception() invalid_arg_exception() invalid_operation_exception() key_not_found_exception() bad_cast_exception() out_of_range_exception() canceled_exception() assert_exception() eof_exception() unknown_host_exception() null_optional() aes_exception() overflow_exception() underflow_exception(divide_by_zero_exception)) namespace detail
Definition: exception.cpp:46
fc::safe::operator-
safe operator-() const
Definition: safe.hpp:204
fc::safe::operator+=
safe & operator+=(const safe &b)
Definition: safe.hpp:220
fc::safe::operator-=
safe & operator-=(const safe &b)
Definition: safe.hpp:225
exception.hpp
Defines exception's used by fc.
FC_CAPTURE_AND_THROW
#define FC_CAPTURE_AND_THROW(EXCEPTION_TYPE,...)
Definition: exception.hpp:357
fc::safe::operator--
safe operator--(int)
Definition: safe.hpp:263
fc::safe::safe
safe(V v)
Definition: safe.hpp:89
fc::safe::operator<
friend bool operator<(const safe &a, const safe &b)
Definition: safe.hpp:283
fc::safe::operator/=
safe & operator/=(const safe &b)
Definition: safe.hpp:235
fc::safe::operator++
safe & operator++()
Definition: safe.hpp:246
fc::safe::value
T value
Definition: safe.hpp:28
fc::safe::operator+
friend safe operator+(const safe &a, const safe &b)
Definition: safe.hpp:110
fc::safe::operator%
friend safe operator%(const safe &a, const safe &b)
Definition: safe.hpp:183
fc::safe
Definition: safe.hpp:26