6
6
7
7
namespace fly ::detail {
8
8
9
+ /* *
10
+ * Concept that is satisfied if the provided character is a valid literal for the provided base.
11
+ */
12
+ template <std::size_t Base, char Literal>
13
+ concept ValidLiteralForBase = (Literal == ' \' ' ) ||
14
+ ((Base == 2 ) && ((Literal >= ' 0' ) && (Literal <= ' 1' ))) ||
15
+ ((Base == 8 ) && ((Literal >= ' 0' ) && (Literal <= ' 7' ))) ||
16
+ ((Base == 10 ) && ((Literal >= ' 0' ) && (Literal <= ' 9' ))) ||
17
+ ((Base == 16 ) && ((Literal >= ' 0' ) && (Literal <= ' 9' ))) ||
18
+ ((Base == 16 ) && ((Literal >= ' A' ) && (Literal <= ' F' ))) ||
19
+ ((Base == 16 ) && ((Literal >= ' a' ) && (Literal <= ' f' )));
20
+
21
+ /* *
22
+ * Concept that is satisfied if the provided value fits within the limits of the desired type to be
23
+ * converted to.
24
+ */
25
+ template <typename From, typename To, From Value>
26
+ concept ValueWithinLimits = requires
27
+ {
28
+ requires (Value >= std::numeric_limits<To>::min ());
29
+ requires (Value <= std::numeric_limits<To>::max ());
30
+ };
31
+
9
32
/* *
10
33
* Structures to recursively aggregate the value of an integer literal as it is being parsed.
11
34
*
@@ -14,7 +37,11 @@ namespace fly::detail {
14
37
* @tparam Literals Variadic list of characters to parse.
15
38
*/
16
39
template <typename T, T Base, char ... Literals>
40
+ // clang-format off
41
+ // Formatter disabled because it doesn't handle this constraint well.
42
+ requires (ValidLiteralForBase<Base, Literals> && ...)
17
43
struct Aggregator ;
44
+ // clang-format on
18
45
19
46
// Specialization to convert the current character being parsed to an integer and recurse on the
20
47
// remainder of the characters.
@@ -36,15 +63,6 @@ struct Aggregator<T, Base, Digit, Literals...>
36
63
*/
37
64
static constexpr T parse_and_validate_literal ()
38
65
{
39
- constexpr bool literal_is_valid_for_base =
40
- ((Base == 2 ) && ((Digit >= ' 0' ) && (Digit <= ' 1' ))) ||
41
- ((Base == 8 ) && ((Digit >= ' 0' ) && (Digit <= ' 7' ))) ||
42
- ((Base == 10 ) && ((Digit >= ' 0' ) && (Digit <= ' 9' ))) ||
43
- ((Base == 16 ) && ((Digit >= ' 0' ) && (Digit <= ' 9' ))) ||
44
- ((Base == 16 ) && ((Digit >= ' A' ) && (Digit <= ' F' ))) ||
45
- ((Base == 16 ) && ((Digit >= ' a' ) && (Digit <= ' f' )));
46
- static_assert (literal_is_valid_for_base, " Invalid literal for base" );
47
-
48
66
if constexpr ((Digit >= ' A' ) && (Digit <= ' F' ))
49
67
{
50
68
return static_cast <T>(Digit) - static_cast <T>(' A' ) + 0xA ;
@@ -137,7 +155,7 @@ struct Parser<T, '0', 'X', Literals...> : ParserBase<T, 16, Literals...>
137
155
};
138
156
139
157
/* *
140
- * Validate that a value can be converted to a desired type and perform that conversion
158
+ * Validate that a value can be converted to a desired type and perform that conversion.
141
159
*
142
160
* @tparam From The current integer literal type.
143
161
* @tparam To The desired integer literal type.
@@ -146,11 +164,9 @@ struct Parser<T, '0', 'X', Literals...> : ParserBase<T, 16, Literals...>
146
164
* @return The converted integer literal.
147
165
*/
148
166
template <typename From, typename To, From Value>
167
+ requires ValueWithinLimits<From, To, Value>
149
168
constexpr To validate_and_convert ()
150
169
{
151
- static_assert (Value >= std::numeric_limits<To>::min (), " Literal overflow" );
152
- static_assert (Value <= std::numeric_limits<To>::max (), " Literal overflow" );
153
-
154
170
return static_cast <To>(Value);
155
171
}
156
172
0 commit comments