Apache Mesos
numify.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_NUMIFY_HPP__
14 #define __STOUT_NUMIFY_HPP__
15 
16 #include <sstream>
17 #include <string>
18 
19 #include <boost/lexical_cast.hpp>
20 
21 #include "error.hpp"
22 #include "none.hpp"
23 #include "option.hpp"
24 #include "result.hpp"
25 #include "strings.hpp"
26 #include "try.hpp"
27 
28 template <typename T>
29 Try<T> numify(const std::string& s)
30 {
31  // Since even with a `0x` prefix `boost::lexical_cast` cannot always
32  // cast all hexadecimal numbers on all platforms (parsing of some
33  // floating point literals seems to work e.g., on macOS, but fails on
34  // some Linuxes), we have to workaround this issue here. We also
35  // process negative hexadecimal numbers `-0x` here to keep it
36  // consistent with non-hexadecimal numbers.
37  bool maybeHex = false;
38 
39  if (strings::startsWith(s, "0x") || strings::startsWith(s, "0X") ||
40  strings::startsWith(s, "-0x") || strings::startsWith(s, "-0X")) {
41  maybeHex = true;
42 
43  // We disallow hexadecimal floating point numbers.
44  if (strings::contains(s, ".") || strings::contains(s, "p")) {
45  return Error("Failed to convert '" + s + "' to number");
46  }
47  }
48 
49  try {
50  return boost::lexical_cast<T>(s);
51  } catch (const boost::bad_lexical_cast&) {
52  // Try to parse hexadecimal numbers by hand if `boost::lexical_cast` failed.
53  if (maybeHex) {
54  T result;
55  std::stringstream ss;
56  // Process negative hexadecimal numbers.
57  if (strings::startsWith(s, "-")) {
58  ss << std::hex << s.substr(1);
59  ss >> result;
60  // NOTE: Negating `result` is safe even if `T` is an unsigned
61  // integer type, because the C++ standard defines the result
62  // to be modulo 2^n in that case.
63  //
64  // numify<T>("-1") == std::numeric_limits<T>::max();
65  //
66  // Disabled unary negation warning for all types.
67 #ifdef __WINDOWS__
68 #pragma warning(disable:4146)
69 #endif
70  result = -result;
71 #ifdef __WINDOWS__
72 #pragma warning(default:4146)
73 #endif
74  } else {
75  ss << std::hex << s;
76  ss >> result;
77  }
78  // Make sure we really hit the end of the string.
79  if (!ss.fail() && ss.eof()) {
80  return result;
81  }
82  }
83 
84  return Error("Failed to convert '" + s + "' to number");
85  }
86 }
87 
88 
89 template <typename T>
90 Try<T> numify(const char* s)
91 {
92  return numify<T>(std::string(s));
93 }
94 
95 
96 template <typename T>
98 {
99  if (s.isSome()) {
100  Try<T> t = numify<T>(s.get());
101  if (t.isSome()) {
102  return t.get();
103  } else if (t.isError()) {
104  return Error(t.error());
105  }
106  }
107 
108  return None();
109 }
110 
111 #endif // __STOUT_NUMIFY_HPP__
Definition: errorbase.hpp:36
T & get()&
Definition: try.hpp:73
Definition: check.hpp:33
Definition: check.hpp:30
bool isSome() const
Definition: option.hpp:115
Try< T > numify(const std::string &s)
Definition: numify.hpp:29
bool contains(const std::string &s, const std::string &substr)
Definition: strings.hpp:423
bool isSome() const
Definition: try.hpp:70
const T & get() const &
Definition: option.hpp:118
static Try error(const E &e)
Definition: try.hpp:42
Definition: none.hpp:27
bool isError() const
Definition: try.hpp:71
bool startsWith(const std::string &s, const std::string &prefix)
Definition: strings.hpp:381