145 lines
4.5 KiB
C++
145 lines
4.5 KiB
C++
#pragma once
|
|
|
|
#include <cerrno>
|
|
#include <cstdlib>
|
|
#include <map>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <variant>
|
|
#include <vector>
|
|
|
|
class DaliValue {
|
|
public:
|
|
using Array = std::vector<DaliValue>;
|
|
using Object = std::map<std::string, DaliValue>;
|
|
|
|
using Variant = std::variant<std::monostate, bool, int64_t, double, std::string, Array, Object>;
|
|
|
|
DaliValue() = default;
|
|
DaliValue(std::nullptr_t) : value_(std::monostate{}) {}
|
|
DaliValue(bool v) : value_(v) {}
|
|
DaliValue(int v) : value_(static_cast<int64_t>(v)) {}
|
|
DaliValue(int64_t v) : value_(v) {}
|
|
DaliValue(double v) : value_(v) {}
|
|
DaliValue(const char* v) : value_(std::string(v)) {}
|
|
DaliValue(std::string v) : value_(std::move(v)) {}
|
|
DaliValue(Array v) : value_(std::move(v)) {}
|
|
DaliValue(Object v) : value_(std::move(v)) {}
|
|
|
|
bool isNull() const { return std::holds_alternative<std::monostate>(value_); }
|
|
bool isBool() const { return std::holds_alternative<bool>(value_); }
|
|
bool isInt() const { return std::holds_alternative<int64_t>(value_); }
|
|
bool isDouble() const { return std::holds_alternative<double>(value_); }
|
|
bool isString() const { return std::holds_alternative<std::string>(value_); }
|
|
bool isArray() const { return std::holds_alternative<Array>(value_); }
|
|
bool isObject() const { return std::holds_alternative<Object>(value_); }
|
|
|
|
std::optional<bool> asBool() const {
|
|
if (isBool()) return std::get<bool>(value_);
|
|
if (isInt()) return std::get<int64_t>(value_) != 0;
|
|
if (isString()) {
|
|
const auto& s = std::get<std::string>(value_);
|
|
if (s == "true" || s == "TRUE" || s == "1") return true;
|
|
if (s == "false" || s == "FALSE" || s == "0") return false;
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::optional<int> asInt() const {
|
|
if (isInt()) return static_cast<int>(std::get<int64_t>(value_));
|
|
if (isDouble()) return static_cast<int>(std::get<double>(value_));
|
|
if (isString()) {
|
|
const auto& s = std::get<std::string>(value_);
|
|
if (s.empty()) {
|
|
return std::nullopt;
|
|
}
|
|
char* end = nullptr;
|
|
errno = 0;
|
|
const long parsed = std::strtol(s.c_str(), &end, 10);
|
|
if (errno != 0 || end == s.c_str() || *end != '\0') {
|
|
return std::nullopt;
|
|
}
|
|
return static_cast<int>(parsed);
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::optional<double> asDouble() const {
|
|
if (isDouble()) return std::get<double>(value_);
|
|
if (isInt()) return static_cast<double>(std::get<int64_t>(value_));
|
|
if (isString()) {
|
|
const auto& s = std::get<std::string>(value_);
|
|
if (s.empty()) {
|
|
return std::nullopt;
|
|
}
|
|
char* end = nullptr;
|
|
errno = 0;
|
|
const double parsed = std::strtod(s.c_str(), &end);
|
|
if (errno != 0 || end == s.c_str() || *end != '\0') {
|
|
return std::nullopt;
|
|
}
|
|
return parsed;
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::optional<std::string> asString() const {
|
|
if (isString()) return std::get<std::string>(value_);
|
|
if (isBool()) return std::get<bool>(value_) ? "true" : "false";
|
|
if (isInt()) return std::to_string(std::get<int64_t>(value_));
|
|
if (isDouble()) return std::to_string(std::get<double>(value_));
|
|
return std::nullopt;
|
|
}
|
|
|
|
const Array* asArray() const {
|
|
if (!isArray()) return nullptr;
|
|
return &std::get<Array>(value_);
|
|
}
|
|
|
|
const Object* asObject() const {
|
|
if (!isObject()) return nullptr;
|
|
return &std::get<Object>(value_);
|
|
}
|
|
|
|
Array* asArray() {
|
|
if (!isArray()) return nullptr;
|
|
return &std::get<Array>(value_);
|
|
}
|
|
|
|
Object* asObject() {
|
|
if (!isObject()) return nullptr;
|
|
return &std::get<Object>(value_);
|
|
}
|
|
|
|
const Variant& variant() const { return value_; }
|
|
Variant& variant() { return value_; }
|
|
|
|
private:
|
|
Variant value_;
|
|
};
|
|
|
|
inline const DaliValue* getObjectValue(const DaliValue::Object& obj, const std::string& key) {
|
|
const auto it = obj.find(key);
|
|
if (it == obj.end()) return nullptr;
|
|
return &it->second;
|
|
}
|
|
|
|
inline std::optional<int> getObjectInt(const DaliValue::Object& obj, const std::string& key) {
|
|
const auto* v = getObjectValue(obj, key);
|
|
if (!v) return std::nullopt;
|
|
return v->asInt();
|
|
}
|
|
|
|
inline std::optional<bool> getObjectBool(const DaliValue::Object& obj, const std::string& key) {
|
|
const auto* v = getObjectValue(obj, key);
|
|
if (!v) return std::nullopt;
|
|
return v->asBool();
|
|
}
|
|
|
|
inline std::optional<std::string> getObjectString(const DaliValue::Object& obj,
|
|
const std::string& key) {
|
|
const auto* v = getObjectValue(obj, key);
|
|
if (!v) return std::nullopt;
|
|
return v->asString();
|
|
}
|