#pragma once #include #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; using KeyValuesString = SmallVector; 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_str.clear(); break; case Types::KeyValues: m_data.Destruct(); break; default: break; } m_type = Types::None; m_data.Clear(); } template T Get() const; operator StringView(); operator int64_t(); operator int32_t(); operator float(); operator double(); operator void*(); operator RGBAColor32(); operator uint32_t(); operator uint64_t(); void Set(const std::string& val) { Clear(); m_type = Types::String; m_str = KeyValuesString{ StringView{ val } }; } void Set(StringView val) { Clear(); m_type = Types::String; m_str = KeyValuesString{ val }; } 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); } KeyValuesVariant& operator [](const char *string); const KeyValuesVariant& operator [](const char *string) const; static KeyValuesVariant& GetEmptyValue() { return s_Nothing; } private: static KeyValuesVariant s_Nothing; KeyValuesType m_type = Types::None; KeyValuesString m_str; Variant< 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); } static KeyValues& Nothing() { return s_Nothing; } KeyValuesVariant& operator [](const char *string) { auto iter = m_children.find(string); if (iter == m_children.end()) { std::cerr << "Returning KeyValuesVariant empty value: " << string << std::endl; return KeyValuesVariant::GetEmptyValue(); } return iter->second; } const KeyValuesVariant& operator [] (const char *string) const { auto iter = m_children.find(string); if (iter == m_children.end()) { std::cerr << "Returning KeyValuesVariant empty value: " << string << std::endl; return KeyValuesVariant::GetEmptyValue(); } return iter->second; } private: static KeyValues s_Nothing; static std::unique_ptr ParseChild(const char*& start, const char* end) { StringView range = StringView(start, end); if (start == end) return nullptr; stream::ConsumeSpaceAndNewLine(start, end); if (*start != '{') return nullptr; auto kv = std::make_unique(); bool inString = false; bool fillingInValue = false; std::string key; std::string value; start++; while (start != end) { if (stream::IsStringToken(range, start)) { inString = !inString; start++; continue; } if (!inString) { if (stream::IsCPPComment(range, start)) { stream::AdvancePast(start, end, stream::NewlineDelimiters); stream::ConsumeSpaceAndNewLine(start, end); 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 (stream::IsWhitespace(*start) || stream::IsNewLine(*start)) { fillingInValue = !fillingInValue; if (!fillingInValue) { kv->m_children.emplace(key, value); key.clear(); value.clear(); } else if (stream::IsNewLine(*start)) { fillingInValue = false; } stream::ConsumeSpaceAndNewLine(start, end); continue; } } if (fillingInValue) value.push_back(*start); else key.push_back(*start); start++; } return kv; } std::unordered_multimap m_children; }; template <> inline StringView KeyValuesVariant::Get() const { switch (m_type) { case Types::String: return m_str; default: return ""; } } // todo josh: // make the ::Get variant return a result // return un-resulted version of that with the // operators template <> inline int64_t KeyValuesVariant::Get() const { switch (m_type) { case Types::String: return *stream::Parse(m_str); default: return 0; } } template <> inline int32_t KeyValuesVariant::Get() const { return Get(); } template <> inline float KeyValuesVariant::Get() const { switch (m_type) { case Types::String: return *stream::Parse(m_str); default: return 0; } } template <> inline KeyValues& KeyValuesVariant::Get() const { switch (m_type) { case Types::KeyValues: { auto value = m_data.Get().get(); if (value) return *value; } [[fallthrough]]; default: return KeyValues::Nothing(); } } inline KeyValuesVariant& KeyValuesVariant::operator [](const char *string) { if (m_type != Types::KeyValues) abort(); return Get()[string]; } inline const KeyValuesVariant& KeyValuesVariant::operator [](const char *string) const { if (m_type != Types::KeyValues) abort(); return Get()[string]; } inline KeyValuesVariant::operator StringView() { return Get(); } inline KeyValuesVariant::operator int64_t() { return Get(); } inline KeyValuesVariant::operator int32_t() { return Get(); } inline KeyValuesVariant::operator float() { return Get(); } inline KeyValuesVariant::operator double() { return Get(); } inline KeyValuesVariant::operator void*() { return Get(); } inline KeyValuesVariant::operator RGBAColor32() { return Get(); } inline KeyValuesVariant::operator uint32_t() { return Get(); } inline KeyValuesVariant::operator uint64_t() { return Get(); } }