xtd 0.2.0
Loading...
Searching...
No Matches
__parse.hpp
Go to the documentation of this file.
1
3#pragma once
5#if !defined(__XTD_CORE_INTERNAL__)
6#error "Do not include this file: Internal use only"
7#endif
9
10#include "../number_styles.hpp"
11#include "../types.hpp"
12#include <locale>
13#include <limits>
14#include <string>
15#include <sstream>
16
18void __throw_parse_format_exception(const std::string& message, const char* file, xtd::uint32 line, const char* func);
19void __throw_parse_overflow_exception(const char* file, xtd::uint32 line, const char* func);
20
21template <typename char_t>
22inline std::basic_string<char_t> __parse_remove_decorations(const std::basic_string<char_t>& s, xtd::number_styles styles) {
23 std::basic_string<char_t> str(s);
25 while (str.size() > 0 && (str[0] == 9 || str[0] == 10 || str[0] == 11 || str[0] == 12 || str[0] == 13 || str[0] == 32))
26 str.erase(0, 1);
27 }
29 while (str.size() > 0 && (str[str.size() - 1] == 9 || str[str.size() - 1] == 10 || str[str.size() - 1] == 11 || str[str.size() - 1] == 12 || str[str.size() - 1] == 13 || str[str.size() - 1] == 32))
30 str.erase(str.size() - 1, 1);
31 }
32 if ((styles & xtd::number_styles::allow_currency_symbol) == xtd::number_styles::allow_currency_symbol && str.find(std::use_facet<std::moneypunct<char_t>>(std::locale()).curr_symbol()) == 0) str.erase(0, std::use_facet<std::moneypunct<char_t>>(std::locale()).curr_symbol().size());
33 if ((styles & xtd::number_styles::allow_currency_symbol) == xtd::number_styles::allow_currency_symbol && str.rfind(std::use_facet<std::moneypunct<char_t>>(std::locale()).curr_symbol()) + std::use_facet<std::moneypunct<char_t>>(std::locale()).curr_symbol().size() == str.size()) str.resize(str.size() - std::use_facet<std::moneypunct<char_t>>(std::locale()).curr_symbol().size());
34 if ((styles & xtd::number_styles::allow_binary_specifier) == xtd::number_styles::allow_binary_specifier && (str.find("0b") == 0 || str.find("0B") == 0)) str.erase(0, 2);
35 if ((styles & xtd::number_styles::allow_octal_specifier) == xtd::number_styles::allow_octal_specifier && str.find('0') == 0) str.erase(0, 1);
36 if ((styles & xtd::number_styles::allow_hex_specifier) == xtd::number_styles::allow_hex_specifier && (str.find("0x") == 0 || str.find("0X") == 0)) str.erase(0, 2);
37 return str;
38}
39
40template <typename char_t>
41inline int __parse_remove_signs(std::basic_string<char_t>& str, xtd::number_styles styles) {
42 int sign = 0;
43
44 while ((styles & xtd::number_styles::allow_leading_sign) == xtd::number_styles::allow_leading_sign && str.find('+') == 0) {
45 if (sign != 0) __throw_parse_format_exception("String contains more than one sign", __FILE__, __LINE__, __func__);
46 str = str.substr(1, str.size() - 1);
47 sign += 1;
48 }
49
50 while ((styles & xtd::number_styles::allow_leading_sign) == xtd::number_styles::allow_leading_sign && str.find('-') == 0) {
51 if (sign != 0) __throw_parse_format_exception("String contains more than one sign", __FILE__, __LINE__, __func__);
52 str = str.substr(1, str.size() - 1);
53 sign -= 1;
54 }
55
56 while ((styles & xtd::number_styles::allow_trailing_sign) == xtd::number_styles::allow_trailing_sign && str.rfind('+') + 1 == str.size()) {
57 if (sign != 0) __throw_parse_format_exception("String contains more than one sign", __FILE__, __LINE__, __func__);
58 str.pop_back();
59 sign += 1;
60 }
61
62 while ((styles & xtd::number_styles::allow_trailing_sign) == xtd::number_styles::allow_trailing_sign && str.rfind('-') + 1 == str.size()) {
63 if (sign != 0) __throw_parse_format_exception("String contains more than one sign", __FILE__, __LINE__, __func__);
64 str.pop_back();
65 sign -= 1;
66 }
67
68 while ((styles & xtd::number_styles::allow_parentheses) == xtd::number_styles::allow_parentheses && str.find('(') == 0 && str.rfind(')') + 1 == str.size()) {
69 str = str.substr(1, str.size() - 2);
70 if (sign != 0) __throw_parse_format_exception("String contains more than one sign", __FILE__, __LINE__, __func__);
71 sign -= 1;
72 }
73 return sign;
74}
75
76template <typename char_t>
77inline void __parse_check_valid_characters(const std::basic_string<char_t>& str, xtd::number_styles styles) {
78 std::basic_string<char_t> valid_characters = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
81 if ((styles & xtd::number_styles::allow_hex_specifier) == xtd::number_styles::allow_hex_specifier) valid_characters += std::basic_string<char_t> {'A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c', 'd', 'e', 'f'};
82 if ((styles & xtd::number_styles::allow_decimal_point) == xtd::number_styles::allow_decimal_point) valid_characters += std::basic_string<char_t> {std::use_facet<std::numpunct<char_t>>(std::locale()).decimal_point(), '.'};
83 if ((styles & xtd::number_styles::allow_thousands) == xtd::number_styles::allow_thousands) valid_characters += std::use_facet<std::numpunct<char_t>>(std::locale()).thousands_sep();
84 if ((styles & xtd::number_styles::allow_exponent) == xtd::number_styles::allow_exponent) valid_characters += std::basic_string<char_t> {'E', 'e', '+', '-'};
85
86 for (auto c : str) {
87 if (valid_characters.find(c) == std::basic_string<char_t>::npos)
88 __throw_parse_format_exception("invalid character found", __FILE__, __LINE__, __func__);
89 }
90
92 size_t index = str.find(std::use_facet<std::numpunct<char_t>>(std::locale()).decimal_point());
93 if (index != std::basic_string<char_t>::npos && str.find(std::use_facet<std::numpunct<char_t>>(std::locale()).decimal_point(), index + 1) != std::basic_string<char_t>::npos)
94 __throw_parse_format_exception("invalid character found", __FILE__, __LINE__, __func__);
95 }
96
98 size_t index = 1;
99 while ((index = str.find(std::use_facet<std::numpunct<char_t>>(std::locale()).thousands_sep(), index)) != std::basic_string<char_t>::npos) {
100 if (str[index - 1] == std::use_facet<std::numpunct<char_t>>(std::locale()).thousands_sep())
101 __throw_parse_format_exception("invalid character found", __FILE__, __LINE__, __func__);
102 ++index;
103 }
104 }
105
107 size_t index = str.find('+');
108 if (index == std::basic_string<char_t>::npos) index = str.find('-');
109 if (index != std::basic_string<char_t>::npos && str[index - 1] != 'e' && str[index - 1] != 'E')
110 __throw_parse_format_exception("invalid character found", __FILE__, __LINE__, __func__);
111 }
112}
113
114template <typename value_t, typename char_t>
115inline value_t __parse_floating_point(const std::basic_string<char_t>& str, int sign, xtd::number_styles styles) {
116 long double result;
118 result = std::stold(str, nullptr);
119 else {
120 std::stringstream ss(str);
121 ss.imbue(std::locale());
122 ss >> result;
123 }
124
125 result = sign < 0 ? -result : result;
126 if (result < std::numeric_limits<value_t>::lowest() || result > std::numeric_limits<value_t>::max()) __throw_parse_overflow_exception(__FILE__, __LINE__, __func__);
127 return static_cast<value_t>(result);
128}
129
130template <typename value_t, typename char_t>
131inline value_t __parse_signed(const std::basic_string<char_t>& str, int base, int sign, xtd::number_styles styles) {
132 long long result;
134 result = std::stoll(str, nullptr, base);
135 else {
136 std::stringstream ss(str);
137 ss.imbue(std::locale());
138 ss >> result;
139 }
140
141 result = sign < 0 ? -result : result;
142 if (result < std::numeric_limits<value_t>::lowest() || result > std::numeric_limits<value_t>::max()) __throw_parse_overflow_exception(__FILE__, __LINE__, __func__);
143 return static_cast<value_t>(result);
144}
145
146template <typename value_t, typename char_t>
147inline value_t __parse_unsigned(const std::basic_string<char_t>& str, int base, xtd::number_styles styles) {
148 unsigned long long result = 0;
150 result = std::stoull(str, nullptr, base);
151 else {
152 std::stringstream ss(str);
153 ss.imbue(std::locale());
154 ss >> result;
155 }
156
157 if (result > std::numeric_limits<value_t>::max()) __throw_parse_overflow_exception(__FILE__, __LINE__, __func__);
158 return static_cast<value_t>(result);
159}
160
161template <typename value_t, typename char_t>
162inline value_t __parse_floating_point_number(const std::basic_string<char_t>& s, xtd::number_styles styles, const std::locale& locale) {
163 if ((styles & xtd::number_styles::binary_number) == xtd::number_styles::binary_number) __throw_parse_format_exception("xtd::number_styles::binary_number not supported by floating point", __FILE__, __LINE__, __func__);
164 if ((styles & xtd::number_styles::octal_number) == xtd::number_styles::octal_number) __throw_parse_format_exception("xtd::number_styles::octal_number not supported by floating point", __FILE__, __LINE__, __func__);
165 if ((styles & xtd::number_styles::hex_number) == xtd::number_styles::hex_number) __throw_parse_format_exception("xtd::number_styles::hex_number not supported by floating point", __FILE__, __LINE__, __func__);
166
167 auto lower_str = s;
168 for (auto& c : lower_str)
169 c = static_cast<char>(std::tolower(c));
170 if (s == "inf") return std::numeric_limits<value_t>::infinity();
171 if (s == "-inf") return -std::numeric_limits<value_t>::infinity();
172 if (s == "nan") return std::numeric_limits<value_t>::quiet_NaN();
173
174 std::basic_string<char_t> str = __parse_remove_decorations(s, styles);
175 int sign = __parse_remove_signs(str, styles);
176
177 __parse_check_valid_characters(str, styles);
178
179 long double result;
181 result = std::stold(str, nullptr);
182 else {
183 std::stringstream ss(str);
184 ss.imbue(locale);
185 ss >> result;
186 }
187
188 result = sign < 0 ? -result : result;
189 if (result < std::numeric_limits<value_t>::lowest() || result > std::numeric_limits<value_t>::max()) __throw_parse_overflow_exception(__FILE__, __LINE__, __func__);
190 return static_cast<value_t>(result);
191}
192
193template <typename value_t, typename char_t>
194inline value_t __parse_number(const std::basic_string<char_t>& s, xtd::number_styles styles) {
195 if ((styles & xtd::number_styles::allow_binary_specifier) == xtd::number_styles::allow_binary_specifier && (styles - xtd::number_styles::binary_number) != xtd::number_styles::none) __throw_parse_format_exception("Invalid xtd::number_styles flags", __FILE__, __LINE__, __func__);
196 if ((styles & xtd::number_styles::allow_octal_specifier) == xtd::number_styles::allow_octal_specifier && (styles - xtd::number_styles::octal_number) != xtd::number_styles::none) __throw_parse_format_exception("Invalid xtd::number_styles flags", __FILE__, __LINE__, __func__);
197 if ((styles & xtd::number_styles::allow_hex_specifier) == xtd::number_styles::allow_hex_specifier && (styles - xtd::number_styles::hex_number) != xtd::number_styles::none) __throw_parse_format_exception("Invalid xtd::number_styles flags", __FILE__, __LINE__, __func__);
198
199 int base = 10;
203
204 std::basic_string<char_t> str = __parse_remove_decorations(s, styles);
205 int sign = __parse_remove_signs(str, styles);
206
207 __parse_check_valid_characters(str, styles);
208
209 if (std::is_floating_point<value_t>::value || (styles & xtd::number_styles::allow_exponent) == xtd::number_styles::allow_exponent) return __parse_floating_point<value_t>(str, sign, styles);
210 return __parse_signed<value_t>(str, base, sign, styles);
211}
212
213template <typename value_t, typename char_t>
214inline value_t __parse_unsigned_number(const std::basic_string<char_t>& s, xtd::number_styles styles) {
215 if ((styles & xtd::number_styles::allow_binary_specifier) == xtd::number_styles::allow_binary_specifier && (styles - xtd::number_styles::binary_number) != xtd::number_styles::none) __throw_parse_format_exception("Invalid xtd::number_styles flags", __FILE__, __LINE__, __func__);
216 if ((styles & xtd::number_styles::allow_octal_specifier) == xtd::number_styles::allow_octal_specifier && (styles - xtd::number_styles::octal_number) != xtd::number_styles::none) __throw_parse_format_exception("Invalid xtd::number_styles flags", __FILE__, __LINE__, __func__);
217 if ((styles & xtd::number_styles::allow_hex_specifier) == xtd::number_styles::allow_hex_specifier && (styles - xtd::number_styles::hex_number) != xtd::number_styles::none) __throw_parse_format_exception("Invalid xtd::number_styles flags", __FILE__, __LINE__, __func__);
218
219 int base = 10;
223
224 std::basic_string<char_t> str = __parse_remove_decorations(s, styles);
225 if (__parse_remove_signs(str, styles) < 0) __throw_parse_format_exception("unsigned type can't have minus sign", __FILE__, __LINE__, __func__);
226
227 __parse_check_valid_characters(str, styles);
228
229 if ((styles & xtd::number_styles::allow_exponent) == xtd::number_styles::allow_exponent) return __parse_floating_point<value_t>(str, 0, styles);
230 return __parse_unsigned<value_t>(str, base, styles);
231}
232
233template<typename value_t>
234value_t __parse_enum(const std::string& str);
uint32_t uint32
Represents a 32-bit unsigned integer.
Definition uint32.hpp:23
size_t size
Represents a size of any object in bytes.
Definition size.hpp:23
number_styles
Determines the styles permitted in numeric string arguments that are passed to the xtd::parse and xtd...
Definition number_styles.hpp:16
@ allow_thousands
Indicates that the numeric string can have group separators, such as symbols that separate hundreds f...
@ allow_decimal_point
Indicates that the numeric string can have a decimal point. If the number_styles value includes the a...
@ allow_trailing_sign
Indicates that the numeric string can have a trailing sign. Valid trailing sign characters are determ...
@ allow_leading_sign
Indicates that the numeric string can have a leading sign.
@ none
Indicates that no style elements, such as leading or trailing white space, thousands separators,...
@ allow_parentheses
Indicates that the numeric string can have one pair of parentheses enclosing the number....
@ binary_number
Indicates that the allow_leading_white, allow_trailing_white, and allow_binary_specifier styles are u...
@ allow_exponent
Indicates that the numeric string can be in exponential notation. The allow_exponent flag allows the ...
@ allow_hex_specifier
Indicates that the numeric string represents a hexadecimal value. Valid hexadecimal values include th...
@ allow_octal_specifier
Indicates that the numeric string represents a octal value. Valid octal values include the numeric di...
@ allow_leading_white
Indicates that leading white-space characters can be present in the parsed string....
@ octal_number
Indicates that the allow_leading_white, allow_trailing_white, and allow_octal_specifier styles are us...
@ allow_trailing_white
Indicates that trailing white-space characters can be present in the parsed string....
@ allow_currency_symbol
Indicates that the numeric string can contain a currency symbol. Valid currency symbols are determine...
@ hex_number
Indicates that the allow_leading_white, allow_trailing_white, and allow_hex_specifier styles are used...
@ allow_binary_specifier
Indicates that the numeric string represents a binary value. Valid binary values include the numeric ...
@ s
The S key.
@ c
The C key.