rippled
LexicalCast.h
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of Beast: https://github.com/vinniefalco/Beast
4  Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 
20 #ifndef BEAST_MODULE_CORE_TEXT_LEXICALCAST_H_INCLUDED
21 #define BEAST_MODULE_CORE_TEXT_LEXICALCAST_H_INCLUDED
22 
23 #include <algorithm>
24 #include <cassert>
25 #include <cerrno>
26 #include <cstdlib>
27 #include <iostream>
28 #include <iterator>
29 #include <limits>
30 #include <string>
31 #include <type_traits>
32 #include <typeinfo>
33 #include <utility>
34 
35 #include <boost/predef.h>
36 
37 namespace beast {
38 
39 namespace detail {
40 
41 #if BOOST_COMP_MSVC
42 #pragma warning(push)
43 #pragma warning(disable : 4800)
44 #pragma warning(disable : 4804)
45 #endif
46 
47 template <class Int, class FwdIt, class Accumulator>
48 bool
49 parse_integral(Int& num, FwdIt first, FwdIt last, Accumulator accumulator)
50 {
51  num = 0;
52 
53  if (first == last)
54  return false;
55 
56  while (first != last)
57  {
58  auto const c = *first++;
59  if (c < '0' || c > '9')
60  return false;
61  if (!accumulator(num, Int(c - '0')))
62  return false;
63  }
64 
65  return true;
66 }
67 
68 template <class Int, class FwdIt>
69 bool
70 parse_negative_integral(Int& num, FwdIt first, FwdIt last)
71 {
72  Int limit_value = std::numeric_limits<Int>::min() / 10;
73  Int limit_digit = std::numeric_limits<Int>::min() % 10;
74 
75  if (limit_digit < 0)
76  limit_digit = -limit_digit;
77 
78  return parse_integral<Int>(
79  num, first, last, [limit_value, limit_digit](Int& value, Int digit) {
80  assert((digit >= 0) && (digit <= 9));
81  if (value < limit_value ||
82  (value == limit_value && digit > limit_digit))
83  return false;
84  value = (value * 10) - digit;
85  return true;
86  });
87 }
88 
89 template <class Int, class FwdIt>
90 bool
91 parse_positive_integral(Int& num, FwdIt first, FwdIt last)
92 {
93  Int limit_value = std::numeric_limits<Int>::max() / 10;
94  Int limit_digit = std::numeric_limits<Int>::max() % 10;
95 
96  return parse_integral<Int>(
97  num, first, last, [limit_value, limit_digit](Int& value, Int digit) {
98  assert((digit >= 0) && (digit <= 9));
99  if (value > limit_value ||
100  (value == limit_value && digit > limit_digit))
101  return false;
102  value = (value * 10) + digit;
103  return true;
104  });
105 }
106 
107 template <class IntType, class FwdIt>
108 bool
109 parseSigned(IntType& result, FwdIt first, FwdIt last)
110 {
111  static_assert(
113  "You may only call parseSigned with a signed integral type.");
114 
115  if (first != last && *first == '-')
116  return parse_negative_integral(result, first + 1, last);
117 
118  if (first != last && *first == '+')
119  return parse_positive_integral(result, first + 1, last);
120 
121  return parse_positive_integral(result, first, last);
122 }
123 
124 template <class UIntType, class FwdIt>
125 bool
126 parseUnsigned(UIntType& result, FwdIt first, FwdIt last)
127 {
128  static_assert(
130  "You may only call parseUnsigned with an unsigned integral type.");
131 
132  if (first != last && *first == '+')
133  return parse_positive_integral(result, first + 1, last);
134 
135  return parse_positive_integral(result, first, last);
136 }
137 
138 //------------------------------------------------------------------------------
139 
140 // These specializatons get called by the non-member functions to do the work
141 template <class Out, class In>
142 struct LexicalCast;
143 
144 // conversion to std::string
145 template <class In>
146 struct LexicalCast<std::string, In>
147 {
148  explicit LexicalCast() = default;
149 
150  template <class Arithmetic = In>
152  operator()(std::string& out, Arithmetic in)
153  {
154  out = std::to_string(in);
155  return true;
156  }
157 
158  template <class Enumeration = In>
160  operator()(std::string& out, Enumeration in)
161  {
162  out = std::to_string(
163  static_cast<std::underlying_type_t<Enumeration>>(in));
164  return true;
165  }
166 };
167 
168 // Parse std::string to number
169 template <class Out>
170 struct LexicalCast<Out, std::string>
171 {
172  explicit LexicalCast() = default;
173 
174  static_assert(
176  "beast::LexicalCast can only be used with integral types");
177 
178  template <class Integral = Out>
180  operator()(Integral& out, std::string const& in) const
181  {
182  return parseUnsigned(out, in.begin(), in.end());
183  }
184 
185  template <class Integral = Out>
187  operator()(Integral& out, std::string const& in) const
188  {
189  return parseSigned(out, in.begin(), in.end());
190  }
191 
192  bool
193  operator()(bool& out, std::string in) const
194  {
195  // Convert the input to lowercase
196  std::transform(in.begin(), in.end(), in.begin(), [](auto c) {
197  return std::tolower(static_cast<unsigned char>(c));
198  });
199 
200  if (in == "1" || in == "true")
201  {
202  out = true;
203  return true;
204  }
205 
206  if (in == "0" || in == "false")
207  {
208  out = false;
209  return true;
210  }
211 
212  return false;
213  }
214 };
215 
216 //------------------------------------------------------------------------------
217 
218 // Conversion from null terminated char const*
219 template <class Out>
220 struct LexicalCast<Out, char const*>
221 {
222  explicit LexicalCast() = default;
223 
224  bool
225  operator()(Out& out, char const* in) const
226  {
227  return LexicalCast<Out, std::string>()(out, in);
228  }
229 };
230 
231 // Conversion from null terminated char*
232 // The string is not modified.
233 template <class Out>
234 struct LexicalCast<Out, char*>
235 {
236  explicit LexicalCast() = default;
237 
238  bool
239  operator()(Out& out, char* in) const
240  {
241  return LexicalCast<Out, std::string>()(out, in);
242  }
243 };
244 
245 #if BOOST_COMP_MSVC
246 #pragma warning(pop)
247 #endif
248 
249 } // namespace detail
250 
251 //------------------------------------------------------------------------------
252 
257 {
258  explicit BadLexicalCast() = default;
259 };
260 
264 template <class Out, class In>
265 bool
266 lexicalCastChecked(Out& out, In in)
267 {
268  return detail::LexicalCast<Out, In>()(out, in);
269 }
270 
277 template <class Out, class In>
278 Out
280 {
281  Out out;
282 
283  if (lexicalCastChecked(out, in))
284  return out;
285 
286  throw BadLexicalCast();
287 }
288 
294 template <class Out, class In>
295 Out
296 lexicalCast(In in, Out defaultValue = Out())
297 {
298  Out out;
299 
300  if (lexicalCastChecked(out, in))
301  return out;
302 
303  return defaultValue;
304 }
305 
306 } // namespace beast
307 
308 #endif
beast::detail::parse_integral
bool parse_integral(Int &num, FwdIt first, FwdIt last, Accumulator accumulator)
Definition: LexicalCast.h:49
std::is_signed
std::is_unsigned
std::string
STL class.
utility
beast::detail::parse_positive_integral
bool parse_positive_integral(Int &num, FwdIt first, FwdIt last)
Definition: LexicalCast.h:91
beast::lexicalCast
Out lexicalCast(In in, Out defaultValue=Out())
Convert from one type to another.
Definition: LexicalCast.h:296
iterator
beast::BadLexicalCast
Thrown when a conversion is not possible with LexicalCast.
Definition: LexicalCast.h:256
beast::detail::LexicalCast< Out, char * >::operator()
bool operator()(Out &out, char *in) const
Definition: LexicalCast.h:239
iostream
algorithm
std::underlying_type_t
std::bad_cast
STL class.
beast::detail::LexicalCast< Out, std::string >
Definition: LexicalCast.h:170
beast::detail::LexicalCast< Out, std::string >::operator()
std::enable_if_t< std::is_signed< Integral >::value, bool > operator()(Integral &out, std::string const &in) const
Definition: LexicalCast.h:187
std::enable_if_t
beast::detail::LexicalCast< Out, std::string >::operator()
std::enable_if_t< std::is_unsigned< Integral >::value, bool > operator()(Integral &out, std::string const &in) const
Definition: LexicalCast.h:180
beast::detail::LexicalCast< std::string, In >::operator()
std::enable_if_t< std::is_arithmetic< Arithmetic >::value, bool > operator()(std::string &out, Arithmetic in)
Definition: LexicalCast.h:152
std::to_string
T to_string(T... args)
beast::detail::parseSigned
bool parseSigned(IntType &result, FwdIt first, FwdIt last)
Definition: LexicalCast.h:109
std::is_integral
std::transform
T transform(T... args)
beast::lexicalCastThrow
Out lexicalCastThrow(In in)
Convert from one type to another, throw on error.
Definition: LexicalCast.h:279
beast::detail::LexicalCast< Out, char const * >::operator()
bool operator()(Out &out, char const *in) const
Definition: LexicalCast.h:225
beast::detail::LexicalCast< Out, std::string >::operator()
bool operator()(bool &out, std::string in) const
Definition: LexicalCast.h:193
std::numeric_limits::min
T min(T... args)
beast::detail::LexicalCast< std::string, In >::operator()
std::enable_if_t< std::is_enum< Enumeration >::value, bool > operator()(std::string &out, Enumeration in)
Definition: LexicalCast.h:160
cstdlib
cerrno
limits
beast::lexicalCastChecked
bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
Definition: LexicalCast.h:266
std
STL namespace.
beast::BadLexicalCast::BadLexicalCast
BadLexicalCast()=default
cassert
typeinfo
std::numeric_limits::max
T max(T... args)
beast::detail::parseUnsigned
bool parseUnsigned(UIntType &result, FwdIt first, FwdIt last)
Definition: LexicalCast.h:126
type_traits
beast::detail::parse_negative_integral
bool parse_negative_integral(Int &num, FwdIt first, FwdIt last)
Definition: LexicalCast.h:70
beast::detail::LexicalCast
Definition: LexicalCast.h:142
beast
Definition: base_uint.h:641
string