From 5fcef94559fb998022ad312842be55da550c5476 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Wed, 18 Jan 2023 08:39:29 +0000 Subject: [PATCH] Initial work on KV parser --- include/Orange/Core/Parse.h | 20 +++ include/Orange/Core/Span.h | 10 +- include/Orange/Core/Variant.h | 18 ++- include/Orange/Formats/KeyValues.h | 202 +++++++++++++++++++++++++++++ include/Orange/Graphics/Color.h | 56 ++++++++ include/Orange/Graphics/Mesh.h | 2 +- src/Apps/Tools/CubeTest.cpp | 3 +- src/Orange/Graphics/Mesh.cpp | 4 +- 8 files changed, 307 insertions(+), 8 deletions(-) create mode 100644 include/Orange/Formats/KeyValues.h create mode 100644 include/Orange/Graphics/Color.h diff --git a/include/Orange/Core/Parse.h b/include/Orange/Core/Parse.h index 35eeb17..2ee1d60 100644 --- a/include/Orange/Core/Parse.h +++ b/include/Orange/Core/Parse.h @@ -98,4 +98,24 @@ namespace orange::stream { return ReadOrAdvance(first, end, delims, 1); } + + inline bool IsStringToken(StringView fullRange, const char* first) + { + if (*first != '"') + return false; + + // Make sure we are in-range for the checks below. + if (fullRange.begin() == first || fullRange.begin() == first - 1) + return true; + + // Handle \\" + if (*(first - 2) == '\\') + return true; + + // Hanle \" + if (*(first - 1) == '\\') + return false; + + return true; + } } diff --git a/include/Orange/Core/Span.h b/include/Orange/Core/Span.h index fe8116a..8c42a4e 100644 --- a/include/Orange/Core/Span.h +++ b/include/Orange/Core/Span.h @@ -1,15 +1,20 @@ #pragma once #include -#include +#include +#include namespace orange { template struct Span { + Span(std::nullptr_t) : data(nullptr), size(0) {} + Span(T* data, size_t size) : data(data), size(size) {} + Span(T* begin, T* end) : data(begin), size(uintptr_t(end) - uintptr_t(begin)) {} + template Span(T (&array)[Count]) : data(array), size(Count) {} @@ -68,6 +73,9 @@ namespace orange { using Span::Span; + StringView(const std::string& string) + : Span(string.data(), string.length()) {} + StringView(const char* str) : Span{str, strlen(str)} {} }; diff --git a/include/Orange/Core/Variant.h b/include/Orange/Core/Variant.h index d54a746..fab7283 100644 --- a/include/Orange/Core/Variant.h +++ b/include/Orange/Core/Variant.h @@ -2,6 +2,7 @@ #include #include +#include namespace orange { @@ -11,7 +12,7 @@ namespace orange public: static constexpr size_t MaxElementSize = Max({sizeof(Types)...}); static constexpr size_t Alignment = Max({alignof(Types)...}); - + explicit Variant() { } @@ -19,13 +20,24 @@ namespace orange template Variant(Args&&... args) { - Construct(Forward(args)...); + Construct(Forward(args)...); } template void Construct(Args&&... args) { - new (Ptr()) T(Forward(args)...); + new (Ptr()) T(Forward(args)...); + } + + template + void Destruct() + { + Ptr()->~T(); + } + + void Clear() + { + std::memset(&data, 0, sizeof(data)); } template T* Ptr() { return reinterpret_cast (data.data); } diff --git a/include/Orange/Formats/KeyValues.h b/include/Orange/Formats/KeyValues.h new file mode 100644 index 0000000..1294de7 --- /dev/null +++ b/include/Orange/Formats/KeyValues.h @@ -0,0 +1,202 @@ +#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; + }; +} diff --git a/include/Orange/Graphics/Color.h b/include/Orange/Graphics/Color.h new file mode 100644 index 0000000..a417091 --- /dev/null +++ b/include/Orange/Graphics/Color.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include +#include + +namespace orange +{ + + template + struct RGBAColor + { + static constexpr T NormalizedMinValue = T{}; + static constexpr T NormalizedMaxValue = T{ std::is_floating_point::value ? 1.0 : std::numeric_limits::max() }; + static constexpr T PackScale = NormalizedMaxValue / T{ 255 }; + + explicit RGBAColor(T r, T g, T b, T a) + : r{r}, g{g}, b{b}, a{a} + { + } + + explicit RGBAColor(T r, T g, T b) + : RGBAColor{ r, g, b, NormalizedMaxValue } + { + } + + explicit RGBAColor(uint32_t rgba) + : RGBAColor{ ((rgba >> 24u) & 0xFFu) * PackScale, + ((rgba >> 16u) & 0xFFu) * PackScale, + ((rgba >> 8u) & 0xFFu) * PackScale, + ((rgba >> 0u) & 0xFFu) * PackScale } + { + } + + uint32_t pack() + { + return uint32_t{ std::clamp(r / PackScale, T{ 0 }, T { 255 }) } << 24u | + uint32_t{ std::clamp(g / PackScale, T{ 0 }, T { 255 }) } << 16u | + uint32_t{ std::clamp(b / PackScale, T{ 0 }, T { 255 }) } << 8u | + uint32_t{ std::clamp(a / PackScale, T{ 0 }, T { 255 }) } << 0u; + } + + union + { + std::array data; + struct + { + T r, g, b, a; + }; + }; + }; + + using RGBAColor32 = RGBAColor; + using RGBAColorFloat = RGBAColor; + +} \ No newline at end of file diff --git a/include/Orange/Graphics/Mesh.h b/include/Orange/Graphics/Mesh.h index 98ecafb..5006cad 100644 --- a/include/Orange/Graphics/Mesh.h +++ b/include/Orange/Graphics/Mesh.h @@ -57,7 +57,7 @@ namespace orange return GetSkinnedVertices(); break; default: - return BufferView{ nullptr, 0 }; + return BufferView{ nullptr }; } } diff --git a/src/Apps/Tools/CubeTest.cpp b/src/Apps/Tools/CubeTest.cpp index b8c3fbb..0da21d0 100644 --- a/src/Apps/Tools/CubeTest.cpp +++ b/src/Apps/Tools/CubeTest.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -481,7 +482,7 @@ int main(int argc, char** argv) .depthFormat = depthFormat, .enableDepthTest = false, .enableDepthWrites = false, - .vertexAttributes = Span(nullptr, 0), + .vertexAttributes = Span(nullptr), }); #pragma endregion diff --git a/src/Orange/Graphics/Mesh.cpp b/src/Orange/Graphics/Mesh.cpp index 07c6c05..dc9b7c3 100644 --- a/src/Orange/Graphics/Mesh.cpp +++ b/src/Orange/Graphics/Mesh.cpp @@ -29,8 +29,8 @@ namespace orange std::unordered_map indexTracker; - const char* obj = buffer.data; - const char* end = buffer.data + buffer.size; + const char* obj = buffer.begin(); + const char* end = buffer.end(); while (obj != end) { SmallVector element;