5 #include <unordered_set>
28 if (value.size() < 2 || value[0] !=
'0')
30 const char pfx =
static_cast<char>(std::tolower(
static_cast<unsigned char>(value[1])));
31 if (pfx !=
'b' && pfx !=
'o' && pfx !=
'x')
34 result.reserve(value.size());
37 for (std::size_t i = 2; i < value.size(); ++i)
38 result +=
static_cast<char>(std::toupper(
static_cast<unsigned char>(value[i])));
44 u16 enum_bit_width(
size_t count)
50 const unsigned long long max =
static_cast<unsigned long long>(count - 1);
51 return static_cast<u16>(
sizeof(
unsigned long long) * 8 - __builtin_clzll(max));
56 Result<u64> parse_bit_vector(
const std::string& value)
60 return ERR(
"empty bit-vector value");
63 if (value.size() >= 2 && value[0] ==
'0')
65 const char c = value[1];
80 return ERR(
"invalid base");
85 return ERR(
"bit-vector value '" + value +
"' has no base prefix (expected 0b, 0o, or 0x)");
87 const std::string digits = value.substr(2);
90 return ERR(
"bit-vector value '" + value +
"' has no digits after the base prefix");
95 const u64 v = std::stoull(digits, &consumed, base);
96 if (consumed != digits.size())
98 return ERR(
"bit-vector value '" + value +
"' contains non-digit characters");
102 catch (
const std::invalid_argument&)
104 return ERR(
"bit-vector value '" + value +
"' is not a valid number");
106 catch (
const std::out_of_range&)
108 return ERR(
"bit-vector value '" + value +
"' exceeds the 64-bit range");
114 bool is_logic_state_char(
char c)
116 return c ==
'0' || c ==
'1' || c ==
'X' || c ==
'Z' || c ==
'U' || c ==
'L' || c ==
'H' || c ==
'W' || c ==
'-';
125 Result<std::string> parse_logic_vector(
const std::string& value)
129 return ERR(
"empty logic-vector value");
131 if (value.size() < 2 || value[0] !=
'0')
133 return ERR(
"logic-vector value '" + value +
"' has no base prefix");
135 const char base_char = value[1];
137 std::string numeric_set;
146 numeric_set =
"01234567";
150 numeric_set =
"0123456789ABCDEF";
153 return ERR(
"logic-vector value '" + value +
"' has invalid base");
155 const std::string digits = value.substr(2);
158 return ERR(
"logic-vector value '" + value +
"' has no digits after the base prefix");
161 out.reserve(digits.size() * bits_per_digit);
162 for (
const char c : digits)
164 const bool is_numeric = numeric_set.find(c) != std::string::npos;
165 const bool is_state = is_logic_state_char(c) && c !=
'0' && c !=
'1';
166 if (!is_numeric && !is_state)
168 return ERR(
"logic-vector value '" + value +
"' contains invalid digit '" + std::string(1, c) +
"'");
172 out.append(
static_cast<size_t>(bits_per_digit), c);
176 const int n = (c >=
'A') ? (c -
'A' + 10) : (c -
'0');
177 for (
int i = bits_per_digit - 1; i >= 0; --i)
179 out += ((n >> i) & 1) ?
'1' :
'0';
187 Result<i64> parse_integer(
const std::string& value)
191 return ERR(
"empty integer value");
196 const i64 v = std::stoll(value, &consumed, 10);
197 if (consumed != value.size())
199 return ERR(
"integer value '" + value +
"' contains trailing characters");
203 catch (
const std::invalid_argument&)
205 return ERR(
"integer value '" + value +
"' is not a valid number");
207 catch (
const std::out_of_range&)
209 return ERR(
"integer value '" + value +
"' exceeds the 64-bit signed range");
214 Result<double> parse_float(
const std::string& value)
218 return ERR(
"empty float value");
223 const double v = std::stod(value, &consumed);
224 if (consumed != value.size())
226 return ERR(
"float value '" + value +
"' contains trailing characters");
230 catch (
const std::invalid_argument&)
232 return ERR(
"float value '" + value +
"' is not a valid number");
234 catch (
const std::out_of_range&)
236 return ERR(
"float value '" + value +
"' exceeds the double range");
243 Result<std::monostate> parse_time(
const std::string& value)
247 return ERR(
"empty time value");
250 while (i < value.size() && (std::isdigit(
static_cast<unsigned char>(value[i])) || value[i] ==
'.'))
256 return ERR(
"time value '" + value +
"' has no numeric prefix");
258 if (i == value.size())
260 return ERR(
"time value '" + value +
"' is missing a unit suffix");
262 const std::string num_str = value.substr(0, i);
263 const std::string unit = value.substr(i);
264 static const std::vector<std::string> valid_units = {
"fs",
"ps",
"ns",
"us",
"ms",
"s",
"min",
"h"};
265 if (std::find(valid_units.begin(), valid_units.end(), unit) == valid_units.end())
267 return ERR(
"time value '" + value +
"' has invalid unit '" + unit +
"'");
272 (void)std::stod(num_str, &consumed);
273 if (consumed != num_str.size())
275 return ERR(
"time value '" + value +
"' has non-numeric prefix '" + num_str +
"'");
278 catch (
const std::invalid_argument&)
280 return ERR(
"time value '" + value +
"' has invalid numeric prefix '" + num_str +
"'");
282 catch (
const std::out_of_range&)
284 return ERR(
"time value '" + value +
"' has numeric prefix '" + num_str +
"' out of range");
311 return default_value;
323 return ERR(
"could not create parameter of type 'Boolean': parameter name is empty");
330 param.default_value = default_value;
332 if (!default_value.empty() && !param.validate(default_value))
334 return ERR(
"could not create parameter with name '" +
name +
"' of type 'Boolean': default value '" + default_value +
"' is invalid");
344 return ERR(
"could not create parameter of type 'BitVector': parameter name is empty");
348 return ERR(
"could not create parameter with name '" +
name +
"' of type 'BitVector': size must be at least 1");
357 if (!default_value.empty() && !param.validate(param.default_value))
359 return ERR(
"could not create parameter with name '" +
name +
"' of type 'BitVector': default value '" + param.default_value +
"' is invalid");
369 return ERR(
"could not create parameter of type 'LogicVector': parameter name is empty");
373 return ERR(
"could not create parameter with name '" +
name +
"' of type 'LogicVector': size must be at least 1");
382 if (!default_value.empty() && !param.validate(param.default_value))
384 return ERR(
"could not create parameter with name '" +
name +
"' of type 'LogicVector': default value '" + param.default_value +
"' is invalid");
394 return ERR(
"could not create parameter of type 'Integer': parameter name is empty");
401 param.default_value = default_value;
403 if (!default_value.empty() && !param.validate(default_value))
405 return ERR(
"could not create parameter with name '" +
name +
"' of type 'Integer': default value '" + default_value +
"' is invalid");
415 return ERR(
"could not create parameter of type 'String': parameter name is empty");
422 param.default_value = default_value;
431 return ERR(
"could not create parameter of type 'Float': parameter name is empty");
438 param.default_value = default_value;
440 if (!default_value.empty() && !param.validate(default_value))
442 return ERR(
"could not create parameter with name '" +
name +
"' of type 'Float': default value '" + default_value +
"' is invalid");
452 return ERR(
"could not create parameter of type 'Time': parameter name is empty");
459 param.default_value = default_value;
461 if (!default_value.empty() && !param.validate(default_value))
463 return ERR(
"could not create parameter with name '" +
name +
"' of type 'Time': default value '" + default_value +
"' is invalid");
473 return ERR(
"could not create parameter of type 'Enum': parameter name is empty");
475 if (values.size() < 2)
477 return ERR(
"could not create parameter with name '" +
name +
"' of type 'Enum': at least two enum values are required");
480 std::unordered_set<std::string> seen;
481 for (
const auto& v : values)
483 if (!seen.insert(v).second)
485 return ERR(
"could not create parameter with name '" +
name +
"' of type 'Enum': duplicate enum value '" + v +
"'");
493 param.size = enum_bit_width(values.size());
494 param.enum_values = values;
495 param.default_value = default_value;
497 if (!default_value.empty() && !param.validate(default_value))
499 return ERR(
"could not create parameter with name '" +
name +
"' of type 'Enum': default value '" + param.default_value +
"' is invalid");
507 const std::string v = normalize_value(
type, value);
511 return v ==
"true" || v ==
"false";
516 auto parsed = parse_bit_vector(v);
517 if (parsed.is_error())
521 const u64 n = parsed.get();
522 return size == 64 || (n >> size) == 0;
526 if (v.size() < 3 || v[0] !=
'0')
530 const char bc = v[1];
532 std::string valid_chars;
535 case 'b': bpd = 1; valid_chars =
"01";
break;
536 case 'o': bpd = 3; valid_chars =
"01234567";
break;
537 case 'x': bpd = 4; valid_chars =
"0123456789ABCDEF";
break;
538 default:
return false;
540 const std::string digits = v.substr(2);
545 for (
char c : digits)
547 if (valid_chars.find(c) == std::string::npos)
554 while (i < digits.size() && digits[i] ==
'0')
558 if (i == digits.size())
562 const char lead = digits[i];
563 const int lead_val = (lead >=
'A') ? (lead -
'A' + 10) : (lead -
'0');
565 while ((1 << lead_bits) <= lead_val)
569 const u64 sig_bits =
static_cast<u64>(lead_bits) +
static_cast<u64>(digits.size() - i - 1) *
static_cast<u64>(bpd);
570 return sig_bits <= size;
573 auto parsed = parse_logic_vector(v);
574 if (parsed.is_error())
578 return parsed.get().size() <= size;
581 return parse_integer(v).is_ok();
587 return parse_float(v).is_ok();
590 return parse_time(v).is_ok();
593 if (std::find(enum_values.begin(), enum_values.end(), v) == enum_values.end())
605 const std::string v = normalize_value(
type, value);
617 return ERR(
"value '" + value +
"' is not a valid boolean");
620 auto parsed = parse_bit_vector(v);
621 if (parsed.is_error())
623 return ERR_APPEND(parsed.get_error(),
"value '" + value +
"' is not a valid bit-vector");
625 const u64 n = parsed.get();
626 if (size < 64 && (n >> size) != 0)
628 return ERR(
"value '" + value +
"' does not fit in " + std::to_string(size) +
" bits");
633 auto parsed = parse_integer(v);
634 if (parsed.is_error())
636 return ERR_APPEND(parsed.get_error(),
"value '" + value +
"' is not a valid integer");
638 return OK(
static_cast<u64>(parsed.get()));
644 return ERR(
"parameter of type '" + enum_to_string<Parameter::Type>(
type) +
"' has no canonical integer encoding");
647 for (
size_t i = 0; i < enum_values.size(); ++i)
649 if (enum_values[i] == value)
651 return OK(
static_cast<u64>(i));
654 return ERR(
"value '" + value +
"' is not a declared enum value");
657 return ERR(
"unknown parameter type");
662 return name == other.name &&
type == other.type && size == other.size && default_value == other.default_value && enum_values == other.enum_values;
667 return !(*
this == other);
#define ERR_APPEND(prev_error, message)
static Result< Parameter > Boolean(const std::string &name, const std::string &default_value)
bool operator!=(const Parameter &other) const
static Result< Parameter > BitVector(const std::string &name, u16 size, const std::string &default_value)
static Result< Parameter > Integer(const std::string &name, const std::string &default_value)
bool operator==(const Parameter &other) const
static Result< Parameter > String(const std::string &name, const std::string &default_value)
static Result< Parameter > LogicVector(const std::string &name, u16 size, const std::string &default_value)
const std::string & get_name() const
const std::vector< std::string > & get_enum_values() const
static Result< Parameter > Time(const std::string &name, const std::string &default_value)
static Result< Parameter > Enum(const std::string &name, const std::vector< std::string > &values, const std::string &default_value)
bool validate(const std::string &value) const
static Result< Parameter > Float(const std::string &name, const std::string &default_value)
Result< u64 > encode_as_int(const std::string &value) const
const std::string & get_default_value() const