Mercurial > code
comparison cpp/to_int/to_int.hpp @ 626:64884a4de16a
to_int: initial import
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 26 Oct 2017 19:45:00 +0200 |
parents | |
children | b327391f6a62 |
comparison
equal
deleted
inserted
replaced
625:dccaf66c8b9f | 626:64884a4de16a |
---|---|
1 /* | |
2 * to_int.hpp -- safely convert string to integers | |
3 * | |
4 * Copyright (c) 2016-2017 David Demelier <markand@malikania.fr> | |
5 * | |
6 * Permission to use, copy, modify, and/or distribute this software for any | |
7 * purpose with or without fee is hereby granted, provided that the above | |
8 * copyright notice and this permission notice appear in all copies. | |
9 * | |
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 | |
19 #ifndef TO_INT_HPP | |
20 #define TO_INT_HPP | |
21 | |
22 /** | |
23 * \file to_int.hpp | |
24 * \brief Safely convert string to integers. | |
25 */ | |
26 | |
27 #include <cassert> | |
28 #include <limits> | |
29 #include <sstream> | |
30 #include <stdexcept> | |
31 #include <string> | |
32 #include <type_traits> | |
33 | |
34 /** | |
35 * \cond HIDDEN_SYMBOLS | |
36 */ | |
37 | |
38 namespace detail { | |
39 | |
40 std::invalid_argument make_invalid_argument(const std::string& str) | |
41 { | |
42 std::ostringstream oss; | |
43 | |
44 oss << "invalid number '" << str << "'"; | |
45 | |
46 return std::invalid_argument(oss.str()); | |
47 } | |
48 | |
49 template <typename T> | |
50 std::out_of_range make_out_of_range(const std::string& str, T min, T max) | |
51 { | |
52 std::ostringstream oss; | |
53 | |
54 oss << "number '" << str << "' is out of range "; | |
55 oss << min << ".." << max; | |
56 | |
57 return std::out_of_range(oss.str()); | |
58 } | |
59 | |
60 } // !detail | |
61 | |
62 /** | |
63 * \endcond | |
64 */ | |
65 | |
66 /** | |
67 * Convert the given string into a signed integer. | |
68 * | |
69 * \param str the string to convert | |
70 * \param min the minimum value allowed | |
71 * \param max the maximum value allowed | |
72 * \throw std::invalid_argument if the number was not parsed | |
73 * \throw std::out_or_range if the argument is out of the specified range | |
74 */ | |
75 template <typename T = int> | |
76 T to_int(const std::string& str, T min = std::numeric_limits<T>::min(), T max = std::numeric_limits<T>::max()) | |
77 { | |
78 static_assert(std::is_signed<T>::value, "must be signed"); | |
79 | |
80 char* end; | |
81 auto v = std::strtoll(str.c_str(), &end, 10); | |
82 | |
83 if (*end != '\0') | |
84 throw detail::make_invalid_argument(str); | |
85 if (v < min || v > max) | |
86 throw detail::make_out_of_range(str, min, max); | |
87 | |
88 return static_cast<T>(v); | |
89 } | |
90 | |
91 /** | |
92 * Convert the given string into an unsigned integer. | |
93 * | |
94 * In contrast to the [std::strtoull][strtoull] function, this functions | |
95 * verifies if the string starts with minus sign and throws an exception if any. | |
96 * | |
97 * Note, for this you need to have a trimmed string which contains no leading | |
98 * whitespaces. | |
99 * | |
100 * \pre string must be trimmed | |
101 * \param str the string to convert | |
102 * \param min the minimum value allowed | |
103 * \param max the maximum value allowed | |
104 * \throw std::invalid_argument if the number was not parsed | |
105 * \throw std::out_or_range if the argument is out of the specified range | |
106 * | |
107 * [strtoull]: http://en.cppreference.com/w/cpp/string/byte/strtoul | |
108 */ | |
109 template <typename T = unsigned> | |
110 T to_uint(const std::string& str, T min = std::numeric_limits<T>::min(), T max = std::numeric_limits<T>::max()) | |
111 { | |
112 static_assert(std::is_unsigned<T>::value, "must be unsigned"); | |
113 | |
114 assert(str.empty() || !std::isspace(str[0])); | |
115 | |
116 if (str.size() > 0U && str[0] == '-') | |
117 throw detail::make_out_of_range(str, min, max); | |
118 | |
119 char* end; | |
120 auto v = std::strtoull(str.c_str(), &end, 10); | |
121 | |
122 if (*end != '\0') | |
123 throw detail::make_invalid_argument(str); | |
124 if (v < min || v > max) | |
125 throw detail::make_out_of_range(str, min, max); | |
126 | |
127 return v; | |
128 } | |
129 | |
130 #endif // !TO_INT_HPP |