Another small tweak to tokens.
This commit is contained in:
@@ -407,20 +407,20 @@ enum LuaTableType {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct LuaToken {
|
struct LuaToken {
|
||||||
public:
|
private:
|
||||||
// Convert a base36 number into a 64-bit unsigned integer. If the
|
// Convert a base36 number into a token. If the base36 number is
|
||||||
// base36 number is not valid, or if it exceeds 64 bits, then return
|
// not valid, or if it exceeds 64 bits, then return maxint, ie,
|
||||||
// nullopt. Leading zeros are not allowed. Empty string gets parsed
|
// the invalid token.
|
||||||
// as zero.
|
|
||||||
//
|
//
|
||||||
static constexpr std::optional<uint64_t> parse_base36(const char *str) {
|
static constexpr uint64_t parse(std::string_view str) {
|
||||||
uint64_t result = 0;
|
uint64_t result = 0;
|
||||||
uint64_t maxint = uint64_t(-1);
|
uint64_t maxint = uint64_t(-1);
|
||||||
|
|
||||||
// Leading zeros are not allowed.
|
// Leading zeros are not allowed.
|
||||||
// Note: Token(0) is emitted as the empty string, not as '0'.
|
if ((!str.empty()) && (str[0]=='0')) return maxint;
|
||||||
if ((*str == '0')) return std::nullopt;
|
|
||||||
while (*str) {
|
for (int i = 0; i < int(str.size()); i++) {
|
||||||
char c = *str++;
|
char c = str[i];
|
||||||
uint64_t digit = 0;
|
uint64_t digit = 0;
|
||||||
if ((c >= '0') && (c <= '9')) {
|
if ((c >= '0') && (c <= '9')) {
|
||||||
digit = uint64_t(c - '0');
|
digit = uint64_t(c - '0');
|
||||||
@@ -429,14 +429,13 @@ public:
|
|||||||
} else if ((c >= 'A') && (c <= 'Z')) {
|
} else if ((c >= 'A') && (c <= 'Z')) {
|
||||||
digit = uint64_t(c - 'A' + 10);
|
digit = uint64_t(c - 'A' + 10);
|
||||||
} else {
|
} else {
|
||||||
// Invalid digits return nullopt.
|
return maxint;
|
||||||
return std::nullopt;
|
|
||||||
}
|
}
|
||||||
// Multiply existing number by 36, then add the digit.
|
// Multiply existing number by 36, then add the digit.
|
||||||
// We have two checks to prevent integer overflow.
|
// We have two checks to prevent integer overflow.
|
||||||
if (result > (maxint / 36)) return std::nullopt;
|
if (result > (maxint / 36)) return maxint;
|
||||||
result *= 36;
|
result *= 36;
|
||||||
if (digit > (maxint - result)) return std::nullopt;
|
if (digit > (maxint - result)) return maxint;
|
||||||
result += digit;
|
result += digit;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -450,20 +449,22 @@ public:
|
|||||||
template<class T>
|
template<class T>
|
||||||
LuaToken(T arg) = delete;
|
LuaToken(T arg) = delete;
|
||||||
|
|
||||||
// Construct a token from a short string.
|
// Construct a token from a string.
|
||||||
//
|
//
|
||||||
// This is meant to be used for constants in the code.
|
// If the string is not a valid token, then this initializes the
|
||||||
// It cannot be used for runtime creation of tokens. It is
|
// token to the invalid token.
|
||||||
// limited to 10-character tokens.
|
|
||||||
//
|
//
|
||||||
// Note: using 'throw' in a consteval gives largely the
|
LuaToken(std::string_view s) : value(parse(s)) {}
|
||||||
// effect of a static_assert.
|
|
||||||
|
// Construct a token from a compile-time constant string.
|
||||||
//
|
//
|
||||||
consteval LuaToken(const char *str) : value(0) {
|
// It appears that the code below throws an exception if the
|
||||||
auto opt = parse_base36(str);
|
// string is invalid. But in reality, since this function is
|
||||||
if (!opt.has_value()) throw "not a valid token";
|
// consteval (evaluated at compile time), the error is
|
||||||
if (opt.value_or(0) > 3656158440062975) throw "token may have at most 10 characters";
|
// generated during the compilation.
|
||||||
value = opt.value_or(0);
|
//
|
||||||
|
consteval LuaToken(const char *s) : value(parse(s)) {
|
||||||
|
if (is_invalid()) throw "Invalid token";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct a token from an int64.
|
// Construct a token from an int64.
|
||||||
@@ -493,6 +494,10 @@ public:
|
|||||||
//
|
//
|
||||||
void *voidvalue() const { return (void*)value; }
|
void *voidvalue() const { return (void*)value; }
|
||||||
|
|
||||||
|
// Return true if it's the invalid token.
|
||||||
|
//
|
||||||
|
constexpr bool is_invalid() { return value == uint64_t(-1); }
|
||||||
|
|
||||||
// Convert the token to a string.
|
// Convert the token to a string.
|
||||||
//
|
//
|
||||||
// The conversion to string consists of expressing the value
|
// The conversion to string consists of expressing the value
|
||||||
|
|||||||
Reference in New Issue
Block a user