10
10
#ifndef CPROVER_UTIL_STRING2INT_H
11
11
#define CPROVER_UTIL_STRING2INT_H
12
12
13
+ #include " narrow.h"
14
+ #include " optional.h"
13
15
#include < string>
16
+ #include < type_traits>
14
17
15
18
// These check that the string is indeed a valid number,
16
19
// and fail an assertion otherwise.
@@ -30,4 +33,85 @@ long long int unsafe_string2signedlonglong(const std::string &str, int base=10);
30
33
long long unsigned int unsafe_string2unsignedlonglong (
31
34
const std::string &str, int base=10 );
32
35
36
+ // if we had a `resultt` á la Boost.Outcome (https://ned14.github.io/outcome/)
37
+ // we could also return the reason why the conversion failed
38
+
39
+ // / Convert string to integer as per stoi, but return nullopt when
40
+ // / stoi would throw
41
+ optionalt<int > string2optional_int (const std::string &, int base = 10 );
42
+
43
+ // / Convert string to unsigned similar to the stoul or stoull functions,
44
+ // / return nullopt when the conversion fails.
45
+ // / Note: Unlike stoul or stoull negative inputs are disallowed
46
+ optionalt<unsigned >
47
+ string2optional_unsigned (const std::string &, int base = 10 );
48
+
49
+ // / Convert string to size_t similar to the stoul or stoull functions,
50
+ // / return nullopt when the conversion fails.
51
+ // / Note: Unlike stoul or stoull negative inputs are disallowed
52
+ optionalt<std::size_t >
53
+ string2optional_size_t (const std::string &, int base = 10 );
54
+
55
+ // / convert string to signed long long if T is signed
56
+ template <typename T>
57
+ auto string2optional_base (const std::string &str, int base) ->
58
+ typename std::enable_if<std::is_signed<T>::value, long long>::type
59
+ {
60
+ static_assert (
61
+ sizeof (T) <= sizeof (long long ),
62
+ " this works under the assumption that long long is the largest type we try "
63
+ " to convert" );
64
+ return std::stoll (str, nullptr , base);
65
+ }
66
+
67
+ // / convert string to unsigned long long if T is unsigned
68
+ template <typename T>
69
+ auto string2optional_base (const std::string &str, int base) ->
70
+ typename std::enable_if<std::is_unsigned<T>::value, unsigned long long>::type
71
+ {
72
+ static_assert (
73
+ sizeof (T) <= sizeof (unsigned long long ),
74
+ " this works under the assumption that long long is the largest type we try "
75
+ " to convert" );
76
+ if (str.find (' -' ) != std::string::npos)
77
+ {
78
+ throw std::out_of_range{
79
+ " unsigned conversion behaves a bit strangely with negative values, "
80
+ " therefore we disable it" };
81
+ }
82
+ return std::stoull (str, nullptr , base);
83
+ }
84
+
85
+ // / attempt a given conversion, return nullopt if the conversion fails
86
+ // / with out_of_range or invalid_argument
87
+ template <typename do_conversiont>
88
+ auto wrap_string_conversion (do_conversiont do_conversion)
89
+ -> optionalt<decltype(do_conversion())>
90
+ {
91
+ try
92
+ {
93
+ return do_conversion ();
94
+ }
95
+ catch (const std::invalid_argument &)
96
+ {
97
+ return nullopt ;
98
+ }
99
+ catch (const std::out_of_range &)
100
+ {
101
+ return nullopt ;
102
+ }
103
+ }
104
+
105
+ // / convert a string to an integer, given the base of the representation
106
+ // / works with signed and unsigned integer types smaller than
107
+ // / (unsigned) long long
108
+ // / does not accept negative inputs when the result type is unsigned
109
+ template <typename T>
110
+ optionalt<T> string2optional (const std::string &str, int base)
111
+ {
112
+ return wrap_string_conversion ([&]() {
113
+ return narrow_or_throw_out_of_range<T>(string2optional_base<T>(str, base));
114
+ });
115
+ }
116
+
33
117
#endif // CPROVER_UTIL_STRING2INT_H
0 commit comments