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> (num, first, last,
79  [limit_value, limit_digit](Int& value, Int digit)
80  {
81  assert ((digit >= 0) && (digit <= 9));
82  if (value < limit_value || (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> (num, first, last,
97  [limit_value, limit_digit](Int& value, Int digit)
98  {
99  assert ((digit >= 0) && (digit <= 9));
100  if (value > limit_value || (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(std::is_signed<IntType>::value,
112  "You may only call parseSigned with a signed integral type.");
113 
114  if (first != last && *first == '-')
115  return parse_negative_integral (result, first + 1, last);
116 
117  if (first != last && *first == '+')
118  return parse_positive_integral (result, first + 1, last);
119 
120  return parse_positive_integral (result, first, last);
121 }
122 
123 template <class UIntType, class FwdIt>
124 bool
125 parseUnsigned (UIntType& result, FwdIt first, FwdIt last)
126 {
127  static_assert(std::is_unsigned<UIntType>::value,
128  "You may only call parseUnsigned with an unsigned integral type.");
129 
130  if (first != last && *first == '+')
131  return parse_positive_integral (result, first + 1, last);
132 
133  return parse_positive_integral (result, first, last);
134 }
135 
136 //------------------------------------------------------------------------------
137 
138 // These specializatons get called by the non-member functions to do the work
139 template <class Out, class In>
140 struct LexicalCast;
141 
142 // conversion to std::string
143 template <class In>
144 struct LexicalCast <std::string, In>
145 {
146  explicit LexicalCast() = default;
147 
148  template <class Arithmetic = In>
150  operator () (std::string& out, Arithmetic in)
151  {
152  out = std::to_string (in);
153  return true;
154  }
155 
156  template <class Enumeration = In>
158  operator () (std::string& out, Enumeration in)
159  {
160  out = std::to_string (
161  static_cast <std::underlying_type_t <Enumeration>> (in));
162  return true;
163  }
164 };
165 
166 // Parse std::string to number
167 template <class Out>
168 struct LexicalCast <Out, std::string>
169 {
170  explicit LexicalCast() = default;
171 
172  static_assert (std::is_integral <Out>::value,
173  "beast::LexicalCast can only be used with integral types");
174 
175  template <class Integral = Out>
177  operator () (Integral& out, std::string const& in) const
178  {
179  return parseUnsigned (out, in.begin(), in.end());
180  }
181 
182  template <class Integral = Out>
184  operator () (Integral& out, std::string const& in) const
185  {
186  return parseSigned (out, in.begin(), in.end());
187  }
188 
189  bool
190  operator () (bool& out, std::string in) const
191  {
192  // Convert the input to lowercase
193  std::transform(in.begin (), in.end (), in.begin (),
194  [](auto c)
195  {
196  return std::tolower(static_cast<unsigned char>(c));
197  });
198 
199  if (in == "1" || in == "true")
200  {
201  out = true;
202  return true;
203  }
204 
205  if (in == "0" || in == "false")
206  {
207  out = false;
208  return true;
209  }
210 
211  return false;
212  }
213 };
214 
215 //------------------------------------------------------------------------------
216 
217 // Conversion from null terminated char const*
218 template <class Out>
219 struct LexicalCast <Out, char const*>
220 {
221  explicit LexicalCast() = default;
222 
223  bool operator() (Out& out, char const* in) const
224  {
225  return LexicalCast <Out, std::string>()(out, in);
226  }
227 };
228 
229 // Conversion from null terminated char*
230 // The string is not modified.
231 template <class Out>
232 struct LexicalCast <Out, char*>
233 {
234  explicit LexicalCast() = default;
235 
236  bool operator() (Out& out, char* in) const
237  {
238  return LexicalCast <Out, std::string>()(out, in);
239  }
240 };
241 
242 #if BOOST_COMP_MSVC
243 #pragma warning(pop)
244 #endif
245 
246 } // detail
247 
248 //------------------------------------------------------------------------------
249 
254 {
255  explicit BadLexicalCast() = default;
256 };
257 
261 template <class Out, class In>
262 bool lexicalCastChecked (Out& out, In in)
263 {
264  return detail::LexicalCast <Out, In> () (out, in);
265 }
266 
273 template <class Out, class In>
274 Out lexicalCastThrow (In in)
275 {
276  Out out;
277 
278  if (lexicalCastChecked (out, in))
279  return out;
280 
281  throw BadLexicalCast ();
282 }
283 
289 template <class Out, class In>
290 Out lexicalCast (In in, Out defaultValue = Out ())
291 {
292  Out out;
293 
294  if (lexicalCastChecked (out, in))
295  return out;
296 
297  return defaultValue;
298 }
299 
300 } // beast
301 
302 #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:290
iterator
beast::BadLexicalCast
Thrown when a conversion is not possible with LexicalCast.
Definition: LexicalCast.h:253
iostream
algorithm
std::underlying_type_t
std::bad_cast
STL class.
beast::detail::LexicalCast< Out, std::string >
Definition: LexicalCast.h:168
std::enable_if_t
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:274
cstdlib
cerrno
limits
beast::lexicalCastChecked
bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
Definition: LexicalCast.h:262
std
STL namespace.
beast::BadLexicalCast::BadLexicalCast
BadLexicalCast()=default
cassert
typeinfo
beast::detail::parseUnsigned
bool parseUnsigned(UIntType &result, FwdIt first, FwdIt last)
Definition: LexicalCast.h:125
std::numeric_limits
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:140
beast
Definition: base_uint.h:582
string