#pragma once #include #include #include #include #include #include #include #include #include namespace orange::kv { namespace Types { enum KVVariantType { None, String, Int, Float, Ptr, Color, Uint64, KeyValues, Count, }; } using KeyValuesType = Types::KVVariantType; class KeyValues; class KeyValuesVariant { public: using KeyValuesChild = std::unique_ptr; KeyValuesVariant() { } template KeyValuesVariant(const T& arg) { Set(arg); } template KeyValuesVariant(T&& arg) { Set(Move(arg)); } ~KeyValuesVariant() { Clear(); } void Clear() { switch (m_type) { case Types::String: m_data.Destruct(); break; case Types::KeyValues: m_data.Destruct(); break; default: break; } m_type = Types::None; m_data.Clear(); } std::string GetString() const { switch (m_type) { case Types::String: return m_data.Get(); default: return ""; } } void Set(const std::string& val) { Clear(); m_type = Types::String; m_data.Construct(val); } void Set(StringView val) { Clear(); m_type = Types::String; m_data.Construct(val.data, val.data + val.size); } void Set(int32_t val) { Clear(); m_type = Types::Int; m_data.Get() = val; } void Set(int64_t val) { Clear(); m_type = Types::Int; m_data.Get() = val; } void Set(float val) { Clear(); m_type = Types::Float; m_data.Get() = val; } void Set(double val) { Clear(); m_type = Types::Float; m_data.Get() = val; } void Set(void* val) { Clear(); m_type = Types::Ptr; m_data.Get() = val; } void Set(RGBAColor32 val) { Clear(); m_type = Types::Color; m_data.Construct(val); } void Set(uint32_t val) { Clear(); m_type = Types::Uint64; m_data.Get() = val; } void Set(uint64_t val) { Clear(); m_type = Types::Uint64; m_data.Get() = val; } void Set(KeyValuesChild val) { Clear(); m_type = Types::KeyValues; m_data.Get() = Move(val); } private: KeyValuesType m_type = Types::None; Variant< std::string, int64_t, double, void*, uint64_t, RGBAColor32, KeyValuesChild> m_data; }; class KeyValues { public: static std::unique_ptr ParseFromUTF8(StringView buffer) { const char *start = buffer.begin(); const char *end = buffer.end(); return ParseChild(start, end); } private: static std::unique_ptr ParseChild(const char*& start, const char* end) { StringView range = StringView(start, end); if (start == end) return nullptr; stream::ConsumeSpace(start, end); if (*start != '{') return nullptr; auto kv = std::unique_ptr(); bool inString = false; bool fillingInValue = false; std::string key; std::string value; while (start != end) { start++; if (stream::IsStringToken(range, start)) inString = !inString; if (!inString) { if (*start == '\r') continue; if (*start == '{') { auto child = ParseChild(start, end); kv->m_children.emplace(key, Move(child)); fillingInValue = false; key.clear(); value.clear(); } if (*start == '}') { start++; break; } if (*start == ' ' || *start == '\t' || *start == '\n') { if (!fillingInValue) { fillingInValue = true; } else { kv->m_children.emplace(key, value); fillingInValue = false; key.clear(); value.clear(); } stream::ConsumeSpace(start, end); continue; } } if (fillingInValue) value += *start; else key += *start; } return kv; } std::unordered_multimap m_children; }; }