1 | #pragma once |
2 | |
3 | #include <sstream> |
4 | #include <stdexcept> |
5 | #include <string> |
6 | |
7 | namespace c10 { |
8 | |
9 | // to_string, stoi and stod implementation for Android related stuff. |
10 | // Note(jiayq): Do not use the CAFFE2_TESTONLY_FORCE_STD_STRING_TEST macro |
11 | // outside testing code that lives under common_test.cc |
12 | #if defined(__ANDROID__) || defined(CAFFE2_TESTONLY_FORCE_STD_STRING_TEST) |
13 | #define CAFFE2_TESTONLY_WE_ARE_USING_CUSTOM_STRING_FUNCTIONS 1 |
14 | template <typename T> |
15 | std::string to_string(T value) { |
16 | std::ostringstream os; |
17 | os << value; |
18 | return os.str(); |
19 | } |
20 | |
21 | inline int stoi(const std::string& str, std::size_t* pos = 0) { |
22 | std::stringstream ss; |
23 | int n = 0; |
24 | ss << str; |
25 | ss >> n; |
26 | if (ss.fail()) { |
27 | // To mimic `std::stoi` and to avoid including `Exception.h`, throw |
28 | // `std::invalid_argument`. |
29 | // We can't easily detect out-of-range, so we don't use `std::out_of_range`. |
30 | throw std::invalid_argument("Not an integer" ); |
31 | } |
32 | if (pos) { |
33 | if (ss.tellg() == std::streampos(-1)) { |
34 | *pos = str.size(); |
35 | } else { |
36 | *pos = ss.tellg(); |
37 | } |
38 | } |
39 | return n; |
40 | } |
41 | |
42 | inline uint64_t stoull(const std::string& str) { |
43 | std::stringstream ss; |
44 | uint64_t n = 0; |
45 | ss << str; |
46 | ss >> n; |
47 | if (ss.fail()) { |
48 | // To mimic `std::stoull` and to avoid including `Exception.h`, throw |
49 | // `std::invalid_argument`. |
50 | // We can't easily detect out-of-range, so we don't use `std::out_of_range`. |
51 | throw std::invalid_argument("Not an unsigned 64-bit integer" ); |
52 | } |
53 | return n; |
54 | } |
55 | |
56 | inline double stod(const std::string& str, std::size_t* pos = 0) { |
57 | std::stringstream ss; |
58 | ss << str; |
59 | double val = 0; |
60 | ss >> val; |
61 | if (ss.fail()) { |
62 | // To mimic `std::stod` and to avoid including `Exception.h`, throw |
63 | // `std::invalid_argument`. |
64 | // We can't easily detect out-of-range, so we don't use `std::out_of_range`. |
65 | throw std::invalid_argument("Not a double-precision floating point number" ); |
66 | } |
67 | if (pos) { |
68 | if (ss.tellg() == std::streampos(-1)) { |
69 | *pos = str.size(); |
70 | } else { |
71 | *pos = ss.tellg(); |
72 | } |
73 | } |
74 | return val; |
75 | } |
76 | |
77 | inline long long stoll(const std::string& str, std::size_t* pos = 0) { |
78 | // std::stoll doesn't exist in our Android environment, we need to implement |
79 | // it ourselves. |
80 | std::stringstream ss; |
81 | ss << str; |
82 | long long result = 0; |
83 | ss >> result; |
84 | if (ss.fail()) { |
85 | // To mimic `std::stoll` and to avoid including `Exception.h`, throw |
86 | // `std::invalid_argument`. |
87 | // We can't easily detect out-of-range, so we don't use `std::out_of_range`. |
88 | throw std::invalid_argument("Not a long long integer" ); |
89 | } |
90 | if (pos) { |
91 | if (ss.tellg() == std::streampos(-1)) { |
92 | *pos = str.size(); |
93 | } else { |
94 | *pos = ss.tellg(); |
95 | } |
96 | } |
97 | return result; |
98 | } |
99 | |
100 | inline long long stoll(const std::string& str, size_t pos, int base) { |
101 | // std::stoll doesn't exist in our Android environment, we need to implement |
102 | // it ourselves. |
103 | std::stringstream ss; |
104 | if (str.size() > 0 && str.at(0) == '0') { |
105 | if (str.size() > 1 && (str.at(1) == 'x' || str.at(1) == 'X')) { |
106 | ss << std::hex << str; |
107 | } else { |
108 | ss << std::oct << str; |
109 | } |
110 | } else { |
111 | ss << str; |
112 | } |
113 | long long result = 0; |
114 | ss >> result; |
115 | if (ss.fail()) { |
116 | // To mimic `std::stoll` and to avoid including `Exception.h`, throw |
117 | // `std::invalid_argument`. |
118 | // We can't easily detect out-of-range, so we don't use `std::out_of_range`. |
119 | throw std::invalid_argument("Not a long long integer" ); |
120 | } |
121 | return result; |
122 | } |
123 | |
124 | #else |
125 | #define CAFFE2_TESTONLY_WE_ARE_USING_CUSTOM_STRING_FUNCTIONS 0 |
126 | using std::stod; |
127 | using std::stoi; |
128 | using std::stoll; |
129 | using std::stoull; |
130 | using std::to_string; |
131 | #endif // defined(__ANDROID__) || defined(CAFFE2_FORCE_STD_STRING_FALLBACK_TEST) |
132 | |
133 | } // namespace c10 |
134 | |
135 | #if defined(__ANDROID__) && __ANDROID_API__ < 21 && defined(__GLIBCXX__) |
136 | #include <cstdlib> |
137 | // std::strtoll isn't available on Android NDK platform < 21 when building |
138 | // with libstdc++, so bring the global version into std. |
139 | namespace std { |
140 | using ::strtoll; |
141 | } |
142 | #endif |
143 | |