RESTinio
Loading...
Searching...
No Matches
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
19namespace restinio
20{
21
22namespace impl
23{
24
25//
26// check_positive_extremum
27//
29
30//
31// check_negative_extremum
32//
34
36{
37
38template< typename T, typename Storage_Type >
39[[nodiscard]]
40typename std::enable_if< std::is_signed<T>::value, bool >::type
41is_greater_than_maximum( Storage_Type v, Storage_Type maximum )
42{
43 return v > maximum;
44}
45
46// If T is unsigned type then this comparison has no sense.
47template< typename T, typename Storage_Type >
48[[nodiscard]]
49typename std::enable_if< !std::is_signed<T>::value, bool >::type
50is_greater_than_maximum( Storage_Type, Storage_Type )
51{
52 return false;
53}
54
55//
56// extremum_value
57//
58template< typename T, typename Ext >
60
61template< typename T >
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
70template< 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
77 using storage_type = std::make_unsigned_t<T>;
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 */
131template<
132 typename T,
133 int Multiplier,
134 typename Extremum_Type = check_positive_extremum >
136{
139 T,
140 Extremum_Type >;
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
150public :
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
164 const storage_type updated_value = m_current * multiplier +
165 static_cast<storage_type>(digit);
166
167 if( updated_value < m_current ||
168 is_greater_than_maximum<T>( updated_value, extremum_value::value ) )
169 m_overflow_detected = true;
170 else
171 m_current = updated_value;
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 */
Helper class for accumulating integer value during parsing it from string (with check for overflow).
void next_digit(T digit) noexcept
Try to add another digit to the accumulator.
typename extremum_value::storage_type storage_type
Type to be used for holding intermediate value.
bool overflow_detected() const noexcept
Is overflow detected during previous call to next_digit?
overflow_controlled_integer_accumulator_details::extremum_value< T, Extremum_Type > extremum_value
std::enable_if<!std::is_signed< T >::value, bool >::type is_greater_than_maximum(Storage_Type, Storage_Type)
std::enable_if< std::is_signed< T >::value, bool >::type is_greater_than_maximum(Storage_Type v, Storage_Type maximum)