diff --git a/include/Orange/Core/Parse.h b/include/Orange/Core/Parse.h index 2ee1d60..bfe1360 100644 --- a/include/Orange/Core/Parse.h +++ b/include/Orange/Core/Parse.h @@ -68,6 +68,11 @@ namespace orange::stream return Consume(first, end, " \t"); } + inline size_t ConsumeSpaceAndNewLine(const char*& first, const char* end) + { + return Consume(first, end, " \t\r\n"); + } + template > size_t ReadOrAdvance(const char*& first, const char* end, StringView delims, size_t advancement = 0, OutArray* array = nullptr) { @@ -118,4 +123,18 @@ namespace orange::stream return true; } + + inline bool IsCPPComment(StringView fullRange, const char* first) + { + if (*first != '/') + return false; + + if (fullRange.end() == first + 1) + return false; + + if (*(first + 1) != '/') + return false; + + return true; + } } diff --git a/include/Orange/Core/Span.h b/include/Orange/Core/Span.h index 8c42a4e..1fccea3 100644 --- a/include/Orange/Core/Span.h +++ b/include/Orange/Core/Span.h @@ -3,6 +3,7 @@ #include #include #include +#include namespace orange { @@ -80,6 +81,13 @@ namespace orange : Span{str, strlen(str)} {} }; + inline std::ostream& operator << (std::ostream& os, StringView view) + { + for (size_t i = 0; i < view.size; i++) + os << view[i]; + return os; + } + struct Buffer : public BufferView { using BufferView::BufferView; diff --git a/include/Orange/Core/Vector.h b/include/Orange/Core/Vector.h index 87c182d..9478d7b 100644 --- a/include/Orange/Core/Vector.h +++ b/include/Orange/Core/Vector.h @@ -13,7 +13,7 @@ namespace orange SmallVector() {} SmallVector(size_t size) { resize(size); } - SmallVector(Span span) + SmallVector(Span span) { reserve(span.size); for (const auto& val : span) @@ -38,6 +38,7 @@ namespace orange reserve(x.size()); for (const auto& val : x) push_back(val); + return *this; } ~SmallVector() diff --git a/include/Orange/Formats/KeyValues.h b/include/Orange/Formats/KeyValues.h index 1294de7..6a066cf 100644 --- a/include/Orange/Formats/KeyValues.h +++ b/include/Orange/Formats/KeyValues.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -33,10 +34,12 @@ namespace orange::kv class KeyValues; + class KeyValuesVariant { public: using KeyValuesChild = std::unique_ptr; + using KeyValuesString = SmallVector; KeyValuesVariant() { @@ -64,7 +67,7 @@ namespace orange::kv switch (m_type) { case Types::String: - m_data.Destruct(); + m_str.clear(); break; case Types::KeyValues: m_data.Destruct(); @@ -76,19 +79,11 @@ namespace orange::kv m_data.Clear(); } - std::string GetString() const - { - switch (m_type) - { - case Types::String: - return m_data.Get(); - default: - return ""; - } - } + template + T Get() const; - 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(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; } @@ -98,11 +93,20 @@ namespace orange::kv 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< - std::string, int64_t, double, void*, @@ -120,7 +124,38 @@ namespace orange::kv 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); @@ -128,12 +163,12 @@ namespace orange::kv if (start == end) return nullptr; - stream::ConsumeSpace(start, end); + stream::ConsumeSpaceAndNewLine(start, end); if (*start != '{') return nullptr; - auto kv = std::unique_ptr(); + auto kv = std::make_unique(); bool inString = false; @@ -141,21 +176,31 @@ namespace orange::kv std::string key; std::string value; + start++; while (start != end) { - start++; if (stream::IsStringToken(range, start)) + { inString = !inString; + start++; + continue; + } if (!inString) { - if (*start == '\r') + if (stream::IsCPPComment(range, start)) + { + stream::AdvancePast(start, end, "\r\n"); + stream::ConsumeSpaceAndNewLine(start, end); continue; + } if (*start == '{') { + fprintf(stdout, "Adding block child: %s - {\n", key.c_str()); auto child = ParseChild(start, end); kv->m_children.emplace(key, Move(child)); + fprintf(stdout, "Adding block child: }\n"); fillingInValue = false; key.clear(); @@ -168,30 +213,33 @@ namespace orange::kv break; } - if (*start == ' ' || *start == '\t' || *start == '\n') + if (*start == ' ' || *start == '\t' || *start == '\n' || *start == '\r') { + fillingInValue = !fillingInValue; + if (!fillingInValue) { - fillingInValue = true; - } - else - { + fprintf(stdout, "Adding child: %s - %s\n", key.c_str(), value.c_str()); kv->m_children.emplace(key, value); - - fillingInValue = false; key.clear(); value.clear(); } + else if (*start == '\n' || *start == '\r') + { + fillingInValue = false; + } - stream::ConsumeSpace(start, end); + stream::ConsumeSpaceAndNewLine(start, end); continue; } } if (fillingInValue) - value += *start; + value.push_back(*start); else - key += *start; + key.push_back(*start); + + start++; } return kv; @@ -199,4 +247,49 @@ namespace orange::kv std::unordered_multimap m_children; }; + + template <> + inline StringView KeyValuesVariant::Get() const + { + switch (m_type) + { + case Types::String: + return m_str; + default: + return ""; + } + } + + 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]; + } } diff --git a/src/Apps/Tools/CubeTest.cpp b/src/Apps/Tools/CubeTest.cpp index 0da21d0..2df6677 100644 --- a/src/Apps/Tools/CubeTest.cpp +++ b/src/Apps/Tools/CubeTest.cpp @@ -283,6 +283,21 @@ int main(int argc, char** argv) std::cout << std::endl; #endif + auto r_vmf = fs::OpenFileIntoTextBuffer("/home/joshua/Code/Desolation/game/sdk_content/maps/hl2_sdk/sdk_phys_constraint.vmf"); + + auto r_vmfkv = kv::KeyValues::ParseFromUTF8(*r_vmf); + if (!r_vmfkv) + { + fprintf(stderr, "Parsing VMF failed!\n"); + return 1; + } + + + kv::KeyValues &vmfkv = *r_vmfkv; + + std::cout << "editorversion: " << vmfkv["versioninfo"]["editorversion"].Get() << std::endl; + + auto newVertexSlice = *pooler.AllocSlice(sizeof(StaticVertex) * r_mesh->vertexData.VertexCount(), sizeof(StaticVertex)); auto newIndexSlice = *pooler.AllocSlice(sizeof(IndexType) * r_mesh->indices.size(), sizeof(IndexType)); r_mesh->vertexData.GetStaticVertices().copy((uint8_t*)(r_buffer->ptr) + newVertexSlice.offset); diff --git a/src/Orange/Formats/KeyValues.cpp b/src/Orange/Formats/KeyValues.cpp new file mode 100644 index 0000000..8663b17 --- /dev/null +++ b/src/Orange/Formats/KeyValues.cpp @@ -0,0 +1,7 @@ +#include + +namespace orange::kv +{ + KeyValuesVariant KeyValuesVariant::s_Nothing; + KeyValues KeyValues::s_Nothing; +} diff --git a/src/Orange/meson.build b/src/Orange/meson.build index 2c8a92c..e22427e 100644 --- a/src/Orange/meson.build +++ b/src/Orange/meson.build @@ -11,6 +11,8 @@ orange_src = files([ 'Core/Filesystem.cpp', 'Core/Log.cpp', + 'Formats/KeyValues.cpp', + 'Graphics/Mesh.cpp', 'Render/Input.cpp',