RESTinio
overflow_controlled_integer_accumulator.hpp
Go to the documentation of this file.
1 /*
2  * RESTinio
3  */
4 
5 /*!
6  * @file
7  * @brief Helper for parsing integer values.
8  *
9  * @since v.0.6.2
10  */
11 
12 #pragma once
13 
14 #include <restinio/compiler_features.hpp>
15 
16 #include <type_traits>
17 #include <limits>
18 
19 namespace restinio
20 {
21 
22 namespace impl
23 {
24 
25 //
26 // check_positive_extremum
27 //
29 
30 //
31 // check_negative_extremum
32 //
34 
36 {
37 
38 template< typename T, typename Storage_Type >
39 [[nodiscard]]
40 typename std::enable_if< std::is_signed<T>::value, bool >::type
42 {
43  return v > maximum;
44 }
45 
46 // If T is unsigned type then this comparison has no sense.
47 template< typename T, typename Storage_Type >
48 [[nodiscard]]
49 typename std::enable_if< !std::is_signed<T>::value, bool >::type
51 {
52  return false;
53 }
54 
55 //
56 // extremum_value
57 //
58 template< typename T, typename Ext >
60 
61 template< typename T >
62 struct extremum_value< T, check_positive_extremum >
63 {
64  using storage_type = std::make_unsigned_t<T>;
65 
66  static constexpr storage_type value = static_cast<storage_type>(
67  std::numeric_limits<T>::max() );
68 };
69 
70 template< typename T >
72 {
73  static_assert( std::is_signed<T>::value,
74  "extremum_value<T, check_negative_extremum> is defined only "
75  "for signed numeric types" );
76 
78 
79  static constexpr storage_type value = static_cast<storage_type>(
80  std::numeric_limits<T>::min() );
81 
82  static_assert(
83  value == (static_cast<storage_type>(std::numeric_limits<T>::max()) + 1u),
84  "The integer representation is expected to be two's complement" );
85 };
86 
87 } /* namespace overflow_controlled_integer_accumulator_details */
88 
89 //
90 // overflow_controlled_integer_accumulator_t
91 //
92 /*!
93  * @brief Helper class for accumulating integer value during parsing
94  * it from string (with check for overflow).
95  *
96  * Usage example:
97  * @code
98  int parse_int(string_view_t str) {
99  overflow_controlled_integer_accumulator_t<int> acc;
100  for(const auto ch : str) {
101  if(!is_digit(ch))
102  throw not_a_digit(ch);
103  acc.next_digit(ch);
104  if(acc.overflow_detected())
105  throw too_big_value();
106  }
107  return acc.value();
108  }
109  * @endcode
110  *
111  * @note
112  * Since v.0.6.6 it can be used for parcing not only decinal numbers,
113  * but also numbers with base of @a Multiplier.
114  *
115  * @note
116  * Since v.0.6.6 it can be used for parsing digits of negative decimal
117  * numbers. In that case it should be used like that:
118  * @code
119  * char ch = next_char();
120  * if('-' == ch) {
121  * // Digits of negative number should be extracted.
122  * overflow_controlled_integer_accumulator_t<
123  * int,
124  * check_negative_extremum > acc;
125  * ...
126  * }
127  * @endcode
128  *
129  * @since v.0.6.2
130  */
131 template<
132  typename T,
133  int Multiplier,
134  typename Extremum_Type = check_positive_extremum >
136 {
137  using extremum_value =
139  T,
141 
142  //! Type to be used for holding intermediate value.
144 
145  //! The current value of the accumulator.
147  //! Overflow detection flag.
148  bool m_overflow_detected{ false };
149 
150 public :
151  //! Try to add another digit to the accumulator.
152  /*!
153  * Value of the accumulator will be changed only if there is no overflow.
154  */
155  void
156  next_digit( T digit ) noexcept
157  {
159 
160  constexpr storage_type multiplier{
161  static_cast<storage_type>(Multiplier)
162  };
163 
165  static_cast<storage_type>(digit);
166 
167  if( updated_value < m_current ||
169  m_overflow_detected = true;
170  else
172  }
173 
174  //! Is overflow detected during previous call to next_digit?
175  bool
176  overflow_detected() const noexcept
177  {
178  return m_overflow_detected;
179  }
180 
181  //! Get the current accumulator value.
182  T
183  value() const noexcept
184  {
185  return static_cast<T>(m_current);
186  }
187 };
188 
189 } /* namespace restinio */
190 
191 } /* namespace restinio */
bool overflow_detected() const noexcept
Is overflow detected during previous call to next_digit?
std::enable_if< std::is_same< Parameter_Container, query_string_params_t >::value||std::is_same< Parameter_Container, router::route_params_t >::value, std::optional< Value_Type > >::type opt_value(const Parameter_Container &params, string_view_t key)
Gets the value of a parameter specified by key wrapped in std::optional<Value_Type> if parameter exis...
Definition: value_or.hpp:64
void next_digit(T digit) noexcept
Try to add another digit to the accumulator.
std::enable_if< !std::is_signed< T >::value, bool >::type is_greater_than_maximum(Storage_Type, Storage_Type)
Helper class for accumulating integer value during parsing it from string (with check for overflow)...