sots-engine/src/mars/text/value.h

64 lines
2.5 KiB
C++

// mars::text -- lazily typed tokens for the flat tuning tables.
//
// A token is the raw bytes of one whitespace-delimited item (or the inside of
// a "quoted string"). Nothing is converted at parse time; kind() classifies a
// bareword the way the game data reads it (int / float / true|false / word)
// and the as_*() accessors convert on demand. Quoted tokens are always
// strings, even when they look numeric ("8" stays "8").
#pragma once
#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
namespace mars::text {
enum class ValueKind {
Int, // [+-]?digits
Float, // [+-]?(d+.d* | .d+ | d+)([eE][+-]?d+)? (and not Int)
Bool, // true / false, any case
Bareword, // any other unquoted token
String // a "quoted" token
};
// Classification of an unquoted token.
ValueKind classify(std::string_view bareword);
bool looks_like_int(std::string_view s);
bool looks_like_float(std::string_view s);
// Conversions; nullopt when the text does not have the requested shape
// (or, for parse_int, does not fit in 64 bits).
std::optional<std::int64_t> parse_int(std::string_view s);
std::optional<double> parse_float(std::string_view s); // accepts Int or Float shapes
std::optional<bool> parse_bool(std::string_view s);
struct Token {
std::string text;
bool quoted = false;
ValueKind kind() const { return quoted ? ValueKind::String : classify(text); }
std::optional<std::int64_t> as_int() const { return quoted ? std::nullopt : parse_int(text); }
std::optional<double> as_float() const { return quoted ? std::nullopt : parse_float(text); }
std::optional<bool> as_bool() const { return quoted ? std::nullopt : parse_bool(text); }
};
// A colour written as "r g b" or "r g b a" (any numeric components; the data
// uses 0-255 ints). a defaults to 1 when absent. `components` is 3 or 4.
struct Color {
double r = 0, g = 0, b = 0, a = 1;
int components = 0;
};
std::optional<Color> parse_color(std::string_view s);
// ASCII helpers shared by the readers (the data is cp1252; high bytes are
// never whitespace and never case-folded).
inline bool is_space(char c) {
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f';
}
std::string_view strip(std::string_view s);
std::string_view lstrip(std::string_view s);
std::string fold_case(std::string_view s); // ASCII lower-case copy
bool equals_fold(std::string_view a, std::string_view b); // ASCII case-insensitive
} // namespace mars::text