15#include <boost/lexical_cast.hpp>
19#include "sparta/utils/Utils.hpp"
64static const uint32_t DEFAULT_RADIX = 10;
73static const std::vector<RadixPrefix>
prefixes = {
74 {{
"0x",
"0X"}, 16,
"0123456789abcdefABCDEF"},
75 {{
"0b",
"0B"}, 2,
"01"},
76 {{
"0"}, 8,
"01234567"}
88 "kI",
"KI"}, 1_u64<<10},
90 "mI",
"MI"}, 1_u64<<20},
91 {{
"gi",
"Gi",
"bi",
"Bi",
92 "gI",
"GI",
"bI",
"BI"}, 1_u64<<30},
94 "tI",
"TI"}, 1_u64<<40},
96 "pI",
"PI"}, 1_u64<<50},
102 {{
"m",
"M"}, 1000000},
103 {{
"g",
"G",
"b",
"B"}, 1000000000},
104 {{
"t",
"T"}, 1000000000000},
105 {{
"p",
"P"}, 1000000000000000}
168 bool allow_recursion=
true,
169 bool allow_prefix=
true) {
170 (void) allow_recursion;
172 T result = lexicalCast<T>(s, 0);
173 end_pos = std::string::npos;
185inline std::string
parseNumericString(
const std::string& s,
size_t pos,
const char* digits,
size_t& after_numeric) {
186 std::string raw_value_chars = digits;
188 after_numeric = s.find_first_not_of(raw_value_chars, pos);
190 if(after_numeric == pos){
195 if(after_numeric == std::string::npos){
196 numeric = s.substr(pos);
198 numeric = s.substr(pos, after_numeric - pos);
202 for(
const char* pc =
WHITESPACE; *pc !=
'\0'; ++pc) {
203 std::string to_replace;
214 bool allow_recursion,
219 pos = s.find_first_not_of(WHITESPACE);
220 if(pos == std::string::npos){
226 std::string fractional;
227 size_t suffix_pos = pos;
231 uint32_t radix = DEFAULT_RADIX;
232 const char* digits = DECIMAL_DIGITS;
235 bool found_prefix =
false;
236 for(
auto & prefix : prefixes) {
237 for(
auto & str : prefix.options) {
238 size_t prefix_pos = s.find(str, pos);
239 if(prefix_pos == pos) {
247 size_t spec_suffix_pos;
248 numeric = parseNumericString(s, prefix_pos + strlen(str), prefix.digits, spec_suffix_pos);
249 if(numeric.size() != 0){
250 radix = prefix.radix;
251 digits = prefix.digits;
252 pos = suffix_pos = spec_suffix_pos;
267 if(numeric.size() == 0){
270 if(numeric.size() == 0){
271 throw SpartaException(
"Unable to parse a numeric value from substring \"")
272 << s.substr(pos) <<
"\" within full string \"" << s
273 <<
"\" for smart lexical casting";
281 size_t decimal_pos = numeric.find(
'.');
282 if(decimal_pos != std::string::npos){
283 if(decimal_pos == numeric.size() - 1){
284 throw SpartaException(
"Encountered \".\" at the end of a numeric portion (\"") << numeric
285 <<
"\") of a string \"" << s <<
"\"";
287 fractional = numeric.substr(decimal_pos + 1);
288 numeric = numeric.substr(0, decimal_pos);
296 if(numeric.find_first_not_of(WHITESPACE) != std::string::npos) {
298 value = lexicalCast<uint64_t>(numeric, radix);
301 if(pos == std::string::npos){
302 if(fractional.size() != 0){
303 throw SpartaException(
"Encountered a fractional value: \"") << numeric <<
"\" . \""
304 << fractional <<
"\" but no suffix was found, so this cannot possibly represent "
305 " an integer. Found in \"" << s <<
"\"";
320 size_t after_suffix_pos = pos;
321 uint64_t suffix_multiplier = 0;
323 for(
auto & str : suffix.options) {
324 auto tmp = s.find(str, pos);
328 suffix_multiplier = suffix.mult;
329 after_suffix_pos = tmp + strlen(str);
333 if(suffix_multiplier != 0){
338 if(suffix_multiplier == 0){
339 suffix_multiplier = 1;
343 value *= suffix_multiplier;
346 if(fractional.size() != 0){
349 uint32_t ten_div = 10;
350 for(
auto ch : fractional){
351 uint64_t frac = (ch -
'0');
353 frac *= suffix_multiplier;
355 throw SpartaException(
"Encountered a fractional value: \"") << numeric <<
"\" . \""
356 << fractional <<
"\" but suffix multipler was only " << suffix_multiplier
357 <<
", so this fraction does not represent and integer. Fraction should "
358 "not have a 1/" << ten_div <<
" place. Found in \"" << s <<
"\"";
368 if(after_suffix_pos != std::string::npos){
369 uint64_t addition = smartLexicalCast<uint64_t>(s.substr(after_suffix_pos),
378 end_pos = after_suffix_pos;
381 if(end_pos != std::string::npos){
382 size_t garbage_pos = s.find_first_not_of(WHITESPACE, end_pos);
383 if(garbage_pos != std::string::npos) {
384 throw SpartaException(
"Found non-'whitespace' grabage character '") << s[garbage_pos]
385 <<
"' after suffix (at or after char " << end_pos <<
") in string being "\
386 "smart-lexically-cast: \"" << s <<
"\"";
397 bool allow_recursion,
399 uint64_t val = smartLexicalCast<uint64_t>(s, end_pos, allow_recursion, allow_prefix);
400 if(val >= (1_u64 << 32)){
401 throw SpartaException(
"Could not lexically cast \"") << s <<
"\" to a uint32_t because it "
402 "contained a value this type could not contain: " << val;
404 return (uint32_t)val;
410 bool allow_recursion,
412 uint64_t val = smartLexicalCast<uint64_t>(s, end_pos, allow_recursion, allow_prefix);
413 if(val >= (1_u64 << 16)){
414 throw SpartaException(
"Could not lexically cast \"") << s <<
"\" to a uint32_t because it "
415 "contained a value this type could not contain: " << val;
417 return (uint16_t)val;
423 bool allow_recursion,
425 uint64_t val = smartLexicalCast<uint64_t>(s, end_pos, allow_recursion, allow_prefix);
426 if(val >= (1_u64 << 8)){
427 throw SpartaException(
"Could not lexically cast \"") << s <<
"\" to a uint32_t because it "
428 "contained a value this type could not contain: " << val;
436 bool allow_recursion,
439 size_t after_neg_pos = 0;
440 size_t neg_pos = s.find_first_not_of(WHITESPACE);
442 if(neg_pos != std::string::npos){
443 if(s[neg_pos] ==
'-'){
445 after_neg_pos = neg_pos + 1;
450 uint64_t val = smartLexicalCast<uint64_t>(s.substr(after_neg_pos), end_pos, allow_recursion, allow_prefix);
451 if((negate ==
false && val >= (1_u64 << 63))
452 || (negate ==
true && val > (1_u64 << 63))) {
453 throw SpartaException(
"Could not lexically cast \"") << s <<
"\" to a int64_t because it "
454 "contained a value this type could not contain: " << val;
456 int64_t signed_val = val;
466 bool allow_recursion,
468 int64_t val = smartLexicalCast<int64_t>(s, end_pos, allow_recursion, allow_prefix);
469 if(val >= (1_64 << 31)
470 || val < -(1_64 << 31)){
471 throw SpartaException(
"Could not lexically cast \"") << s <<
"\" to a int32_t because it "
472 "contained a value larger than this type could not contain: " << val;
480 bool allow_recursion,
482 int64_t val = smartLexicalCast<int64_t>(s, end_pos, allow_recursion, allow_prefix);
483 if(val >= (1_64 << 16)
484 || val < -(1_64 << 16)){
485 throw SpartaException(
"Could not lexically cast \"") << s <<
"\" to a int16_t because it "
486 "contained a value this type could not contain: " << val;
494 bool allow_recursion,
496 int64_t val = smartLexicalCast<int64_t>(s, end_pos, allow_recursion, allow_prefix);
497 if(val >= (1_64 << 8)
498 || val < -(1_64 << 8)){
499 throw SpartaException(
"Could not lexically cast \"") << s <<
"\" to a int8_t because it "
500 "contained a value this type could not contain: " << val;
508 bool allow_recursion,
510 (void) allow_recursion;
513 utils::ValidValue<double> dbl_value;
517 dbl_value = boost::lexical_cast<double>(s);
518 }
catch (
const boost::bad_lexical_cast &) {
519 throw SpartaException(
"Could not lexically cast \"") << s <<
"\" to a double";
522 end_pos = std::string::npos;
523 return dbl_value.getValue();
String-to-value helpers and string formatting helpers.
static const char * DECIMAL_DIGITS
All decimal (base 10) digits allowed and '.'.
static const std::vector< Modifier > suffixes
Suffixes supported.
static const char * WHITESPACE
All whitespace characters allowed.
static const std::vector< RadixPrefix > prefixes
Radixes supported.
std::string parseNumericString(const std::string &s, size_t pos, const char *digits, size_t &after_numeric)
Parse and return a numeric string from after a certain position in an input string.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
Exception class for all of Sparta.
File that defines a ValidValue.
Macros for handling exponential backoff.
T smartLexicalCast(const ParameterBase *p, const std::string &s, size_t &end_pos, bool allow_recursion=true, bool allow_prefix=true)
smartLexicalCast wrapper with parameter information added to exceptions
uint32_t replaceSubstring(std::string &s, const std::string &from, const std::string &to)
Replaces within a string 's' all instances of some string 'from' with 'to'.
Modifier instance - Associates some suffix strings (e.g. "b") with a semantic (e.g....
std::vector< const char * > options
Suffix strings identifying this modifier (case sensitive)
uint64_t mult
Multiplier applied to the value when this modifier is found.
Prefix instance - Associates some prefix strings (e.g. "0x") with a radix and a set of allowed digit ...
const char *const digits
Valid digits in a number following this prefix.
const uint32_t radix
Radix associated with this prefix.
const std::vector< const char * > options
Prefix strings identifying this prefix (case sensitive)