RESTinio
overflow_controlled_integer_accumulator.hpp
Go to the documentation of this file.
1/*
2 * RESTinio
3 */
4
12#pragma once
13
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
35namespace overflow_controlled_integer_accumulator_details
36{
37
38template< typename T, typename Storage_Type >
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 >
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//
131template<
132 typename T,
133 int Multiplier,
134 typename Extremum_Type = check_positive_extremum >
136{
139 T,
140 Extremum_Type >;
141
143 using storage_type = typename extremum_value::storage_type;
144
148 bool m_overflow_detected{ false };
149
150public :
152
155 void
156 next_digit( T digit ) noexcept
157 {
158 using namespace overflow_controlled_integer_accumulator_details;
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
175 bool
177 {
178 return m_overflow_detected;
179 }
180
182 T
183 value() const noexcept
184 {
185 return static_cast<T>(m_current);
186 }
187};
188
189} /* namespace restinio */
190
191} /* namespace restinio */
192
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?
Detection of compiler version and absence of various features.
#define RESTINIO_NODISCARD
RESTINIO_NODISCARD auto digit() noexcept
A factory function to create a clause that expects a decimal digit, extracts it and then skips it.
constexpr underlying_uint_t maximum
The maximal allowed value for a qvalue.
Definition: basics.hpp:39
RESTINIO_NODISCARD std::enable_if< std::is_signed< T >::value, bool >::type is_greater_than_maximum(Storage_Type v, Storage_Type maximum)
#define const
Definition: zconf.h:230