From d234e352570eefbad0353f7a19c288e60fe167a8 Mon Sep 17 00:00:00 2001 From: Matthew Asplund Date: Sat, 21 Sep 2024 12:17:00 -0700 Subject: [PATCH] Enable linux tests (#265) * Use sequential map * Enable tests --- Source/Client/Core/Recipe.sml | 2 +- .../Source/LocalUserConfig/LocalUserConfig.h | 10 +- .../Core/Source/LocalUserConfig/SDKConfig.h | 21 +-- Source/Client/Core/Source/Module.cpp | 1 + .../Core/Source/PackageLock/PackageLock.h | 14 +- Source/Client/Core/Source/Recipe/Recipe.h | 30 ++-- Source/Client/Core/Source/Recipe/RecipeSML.h | 6 +- .../Client/Core/Source/Recipe/RecipeValue.h | 2 +- Source/Client/Core/Source/Recipe/RootRecipe.h | 8 +- Source/Client/Core/Source/SML/SML.h | 14 +- Source/Client/Core/Source/SML/SMLParser.cpp | 11 +- Source/Client/Core/Source/Utils/SequenceMap.h | 147 ++++++++++++++++++ .../Build/BuildEvaluateEngineTests.h | 6 +- .../Core/UnitTests/Build/MockEvaluateEngine.h | 8 +- .../Core/UnitTests/Recipe/RecipeSMLTests.h | 4 +- 15 files changed, 207 insertions(+), 77 deletions(-) create mode 100644 Source/Client/Core/Source/Utils/SequenceMap.h diff --git a/Source/Client/Core/Recipe.sml b/Source/Client/Core/Recipe.sml index b70e52af5..a116371ae 100644 --- a/Source/Client/Core/Recipe.sml +++ b/Source/Client/Core/Recipe.sml @@ -16,7 +16,7 @@ Source: [ ] Dependencies: { Build: [ - # 'mwasplund|Soup.Test.Cpp@0' + 'mwasplund|Soup.Test.Cpp@0' ] Runtime: [ 'mwasplund|Opal@0' diff --git a/Source/Client/Core/Source/LocalUserConfig/LocalUserConfig.h b/Source/Client/Core/Source/LocalUserConfig/LocalUserConfig.h index 8636c237f..5dd767995 100644 --- a/Source/Client/Core/Source/LocalUserConfig/LocalUserConfig.h +++ b/Source/Client/Core/Source/LocalUserConfig/LocalUserConfig.h @@ -86,15 +86,15 @@ namespace Soup::Core private: bool HasValue(std::string_view key) { - return _table.contains(key.data()); + return _table.Contains(key.data()); } - RecipeValue& GetValue(std::string_view key) + const RecipeValue& GetValue(std::string_view key) const { - auto findItr = _table.find(key.data()); - if (findItr != _table.end()) + const RecipeValue* value; + if ( _table.TryGet(key.data(), value)) { - return findItr->second; + return *value; } else { diff --git a/Source/Client/Core/Source/LocalUserConfig/SDKConfig.h b/Source/Client/Core/Source/LocalUserConfig/SDKConfig.h index b149e85ed..cb9d73711 100644 --- a/Source/Client/Core/Source/LocalUserConfig/SDKConfig.h +++ b/Source/Client/Core/Source/LocalUserConfig/SDKConfig.h @@ -119,28 +119,15 @@ namespace Soup::Core private: bool HasValue(std::string_view key) const { - return _table.contains(key.data()); + return _table.Contains(key.data()); } const RecipeValue& GetValue(std::string_view key) const { - auto findItr = _table.find(key.data()); - if (findItr != _table.end()) + const RecipeValue* value; + if ( _table.TryGet(key.data(), value)) { - return findItr->second; - } - else - { - throw std::runtime_error("Requested recipe value does not exist in the root table."); - } - } - - RecipeValue& GetValue(std::string_view key) - { - auto findItr = _table.find(key.data()); - if (findItr != _table.end()) - { - return findItr->second; + return *value; } else { diff --git a/Source/Client/Core/Source/Module.cpp b/Source/Client/Core/Source/Module.cpp index 338ed7136..80b9aa269 100644 --- a/Source/Client/Core/Source/Module.cpp +++ b/Source/Client/Core/Source/Module.cpp @@ -103,6 +103,7 @@ using namespace Opal; #define CLIENT_CORE_IMPLEMENTATION +#include "Utils/SequenceMap.h" #include "Build/RecipeBuildLocationManager.h" #include "Build/BuildEngine.h" #include "LocalUserConfig/LocalUserConfigExtensions.h" diff --git a/Source/Client/Core/Source/PackageLock/PackageLock.h b/Source/Client/Core/Source/PackageLock/PackageLock.h index 9fd054c96..f353d3d72 100644 --- a/Source/Client/Core/Source/PackageLock/PackageLock.h +++ b/Source/Client/Core/Source/PackageLock/PackageLock.h @@ -180,15 +180,15 @@ namespace Soup::Core private: bool HasValue(const RecipeTable& table, std::string_view key) const { - return table.contains(key.data()); + return table.Contains(key.data()); } const RecipeValue& GetValue(const RecipeTable& table, std::string_view key) const { - auto findItr = table.find(key.data()); - if (findItr != table.end()) + const RecipeValue* value; + if (table.TryGet(key.data(), value)) { - return findItr->second; + return *value; } else { @@ -198,10 +198,10 @@ namespace Soup::Core RecipeValue& GetValue(RecipeTable& table, std::string_view key) { - auto findItr = table.find(key.data()); - if (findItr != table.end()) + RecipeValue* value; + if (table.TryGet(key.data(), value)) { - return findItr->second; + return *value; } else { diff --git a/Source/Client/Core/Source/Recipe/Recipe.h b/Source/Client/Core/Source/Recipe/Recipe.h index fc4df8d29..d2fbd2b45 100644 --- a/Source/Client/Core/Source/Recipe/Recipe.h +++ b/Source/Client/Core/Source/Recipe/Recipe.h @@ -232,15 +232,15 @@ namespace Soup::Core bool HasValue(const RecipeTable& table, std::string_view key) const { - return table.contains(key.data()); + return table.Contains(key.data()); } const RecipeValue& GetValue(const RecipeTable& table, std::string_view key) const { - auto findItr = table.find(key.data()); - if (findItr != table.end()) + const RecipeValue* value; + if (table.TryGet(key.data(), value)) { - return findItr->second; + return *value; } else { @@ -250,10 +250,10 @@ namespace Soup::Core RecipeValue& GetValue(RecipeTable& table, std::string_view key) { - auto findItr = table.find(key.data()); - if (findItr != table.end()) + RecipeValue* value; + if (table.TryGet(key.data(), value)) { - return findItr->second; + return *value; } else { @@ -263,10 +263,10 @@ namespace Soup::Core RecipeValue& SetValue(RecipeTable& table, std::string_view key, RecipeValue&& value) { - auto [insertIterator, wasInserted] = table.insert_or_assign(key.data(), std::move(value)); + auto [wasInserted, valueReference] = table.TryInsert(key.data(), std::move(value)); if (wasInserted) { - return insertIterator->second; + return *valueReference; } else { @@ -276,22 +276,22 @@ namespace Soup::Core RecipeValue& EnsureTableValue(RecipeTable& table, std::string_view key) { - auto findItr = table.find(key.data()); - if (findItr != table.end()) + RecipeValue* value; + if (table.TryGet(key.data(), value)) { - if (findItr->second.GetType() != RecipeValueType::Table) + if (value->GetType() != RecipeValueType::Table) { throw std::runtime_error("The recipe already has a non-table dependencies property"); } - return findItr->second; + return *value; } else { - auto [insertIterator, wasInserted] = table.emplace(key.data(), RecipeValue(RecipeTable())); + auto [wasInserted, valueReference] = table.TryInsert(key.data(), RecipeValue(RecipeTable())); if (wasInserted) { - return insertIterator->second; + return *valueReference; } else { diff --git a/Source/Client/Core/Source/Recipe/RecipeSML.h b/Source/Client/Core/Source/Recipe/RecipeSML.h index 44f936bbd..e51b5674d 100644 --- a/Source/Client/Core/Source/Recipe/RecipeSML.h +++ b/Source/Client/Core/Source/Recipe/RecipeSML.h @@ -119,7 +119,7 @@ namespace Soup::Core for (const auto& [key, value] : source.GetValue()) { auto recipeValue = Parse(value); - target.emplace(key, std::move(recipeValue)); + target.Insert(key, std::move(recipeValue)); } } @@ -162,11 +162,11 @@ namespace Soup::Core static SMLTable Build(const RecipeTable& table) { - auto result = std::unordered_map(); + auto result = SequenceMap(); for (const auto& [key, value] : table) { - result.emplace(key, Build(value)); + result.Insert(key, Build(value)); } return SMLTable(std::move(result)); diff --git a/Source/Client/Core/Source/Recipe/RecipeValue.h b/Source/Client/Core/Source/Recipe/RecipeValue.h index 52ac6443b..9a31ddf3b 100644 --- a/Source/Client/Core/Source/Recipe/RecipeValue.h +++ b/Source/Client/Core/Source/Recipe/RecipeValue.h @@ -11,7 +11,7 @@ namespace Soup::Core { class RecipeValue; using RecipeList = std::vector; - using RecipeTable = std::unordered_map; + using RecipeTable = SequenceMap; enum class RecipeValueType { diff --git a/Source/Client/Core/Source/Recipe/RootRecipe.h b/Source/Client/Core/Source/Recipe/RootRecipe.h index 19c05e6b8..23b87158d 100644 --- a/Source/Client/Core/Source/Recipe/RootRecipe.h +++ b/Source/Client/Core/Source/Recipe/RootRecipe.h @@ -79,15 +79,15 @@ namespace Soup::Core private: bool HasValue(std::string_view key) const { - return _table.contains(key.data()); + return _table.Contains(key.data()); } const RecipeValue& GetValue(std::string_view key) const { - auto findItr = _table.find(key.data()); - if (findItr != _table.end()) + const RecipeValue* value; + if (_table.TryGet(key.data(), value)) { - return findItr->second; + return *value; } else { diff --git a/Source/Client/Core/Source/SML/SML.h b/Source/Client/Core/Source/SML/SML.h index 5baadb7bb..ab86d0feb 100644 --- a/Source/Client/Core/Source/SML/SML.h +++ b/Source/Client/Core/Source/SML/SML.h @@ -26,34 +26,34 @@ namespace Soup::Core class SMLTable { + private: + SequenceMap _value; + public: SMLTable() : _value() { } - SMLTable(std::unordered_map value) : + SMLTable(SequenceMap value) : _value(std::move(value)) { } bool Contains(const std::string& key) const { - return _value.contains(key); + return _value.Contains(key); } const SMLValue& operator[](const std::string& key) const { - return _value.at(key); + return _value[key]; } - const std::unordered_map& GetValue() const + const SequenceMap& GetValue() const { return _value; } - - private: - std::unordered_map _value; }; class SMLArray diff --git a/Source/Client/Core/Source/SML/SMLParser.cpp b/Source/Client/Core/Source/SML/SMLParser.cpp index 41d4c5698..09544afe1 100644 --- a/Source/Client/Core/Source/SML/SMLParser.cpp +++ b/Source/Client/Core/Source/SML/SMLParser.cpp @@ -47,7 +47,6 @@ module; # include #ifndef _WIN32 // TODO: MSVC BUG # include -# include # include #endif @@ -413,7 +412,7 @@ class SMLParser : public SML::Lexer bool TryParse() { - std::unordered_map table; + SequenceMap table; if (TryParseTableContents(table)) { // Verify we are at the end of the content @@ -577,7 +576,7 @@ class SMLParser : public SML::Lexer bool TryParseTable(SMLTable& table) { - std::unordered_map tableValues; + SequenceMap tableValues; if (TryParseTableContents(tableValues)) { // Verify we are at the end of the content @@ -593,7 +592,7 @@ class SMLParser : public SML::Lexer } } - bool TryParseTableContents(std::unordered_map& tableValues) + bool TryParseTableContents(SequenceMap& tableValues) { // Odd move next to allow for optional extra delimiter checks at end MoveNext(); @@ -614,7 +613,7 @@ class SMLParser : public SML::Lexer if (!tableValue.has_value()) return true; - tableValues.emplace(std::move(key), std::move(tableValue.value())); + tableValues.Insert(std::move(key), std::move(tableValue.value())); // Check for zero or more optional values while (true) @@ -640,7 +639,7 @@ class SMLParser : public SML::Lexer return true; } - tableValues.emplace(std::move(key), std::move(tableValue.value())); + tableValues.Insert(std::move(key), std::move(tableValue.value())); } } diff --git a/Source/Client/Core/Source/Utils/SequenceMap.h b/Source/Client/Core/Source/Utils/SequenceMap.h new file mode 100644 index 000000000..1d5f5e67b --- /dev/null +++ b/Source/Client/Core/Source/Utils/SequenceMap.h @@ -0,0 +1,147 @@ +// +// Copyright (c) Soup. All rights reserved. +// + +#pragma once + +namespace Soup::Core +{ + /// + /// A special map that is mutated as a vector + /// + export template + class SequenceMap + { + private: + using raw_data = std::vector>; + raw_data _data; + + public: + /// + /// Initialize a new instance of the SequenceMap class + /// + SequenceMap() : + _data() + { + } + + SequenceMap(SequenceMap&& other) : + _data(std::move(other._data)) + { + } + + SequenceMap(const SequenceMap& other) : + _data(other._data) + { + } + + SequenceMap(std::initializer_list> init) : + _data(init) + { + } + + ~SequenceMap() + { + } + + bool Contains(const TKey& key) const + { + for (const auto& entry : _data) + { + if (entry.first == key) + return true; + } + + return false; + } + + void Insert(const TKey& key, TValue value) + { + auto [wasInserted, valueReference] = TryInsert(key, std::move(value)); + if (!wasInserted) + { + throw std::runtime_error("Key already exists"); + } + } + + std::pair TryInsert(TKey key, TValue value) + { + if (Contains(key)) + { + return std::make_pair(false, nullptr); + } + else + { + _data.push_back(std::make_pair(std::move(key), std::move(value))); + auto& valueReference = _data[_data.size() - 1]; + return std::make_pair(true, &valueReference.second);; + } + } + + bool TryGet(const TKey key, TValue*& value) + { + for (auto& entry : _data) + { + if (entry.first == key) + { + value = &entry.second; + return true; + } + } + + value = nullptr; + return false; + } + + bool TryGet(const TKey key, const TValue*& value) const + { + for (const auto& entry : _data) + { + if (entry.first == key) + { + value = &entry.second; + return true; + } + } + + value = nullptr; + return false; + } + + raw_data::const_iterator begin() const + { + return _data.begin(); + } + raw_data::const_iterator end() const + { + return _data.end(); + } + + /// + /// Equality operator + /// + bool operator ==(const SequenceMap& rhs) const + { + return _data == rhs._data; + } + + const TValue& operator[](const TKey& key) const + { + const TValue* value; + if (TryGet(key, value)) + { + return *value; + } + else + { + throw new std::runtime_error("Missing key"); + } + } + + SequenceMap& operator=(const SequenceMap& other) + { + _data = other._data; + return *this; + } + }; +} diff --git a/Source/Client/Core/UnitTests/Build/BuildEvaluateEngineTests.h b/Source/Client/Core/UnitTests/Build/BuildEvaluateEngineTests.h index fb9a99c15..ca8771a72 100644 --- a/Source/Client/Core/UnitTests/Build/BuildEvaluateEngineTests.h +++ b/Source/Client/Core/UnitTests/Build/BuildEvaluateEngineTests.h @@ -1259,7 +1259,7 @@ namespace Soup::Core::UnitTests temporaryDirectory, globalAllowedReadAccess, globalAllowedWriteAccess); - (ranOperations); + (void)ranOperations; }); Assert::AreEqual( @@ -1396,7 +1396,7 @@ namespace Soup::Core::UnitTests temporaryDirectory, globalAllowedReadAccess, globalAllowedWriteAccess); - (ranOperations); + (void)ranOperations; }); Assert::AreEqual( @@ -1533,7 +1533,7 @@ namespace Soup::Core::UnitTests temporaryDirectory, globalAllowedReadAccess, globalAllowedWriteAccess); - (ranOperations); + (void)ranOperations; }); Assert::AreEqual( diff --git a/Source/Client/Core/UnitTests/Build/MockEvaluateEngine.h b/Source/Client/Core/UnitTests/Build/MockEvaluateEngine.h index c0e261dc6..7ab54f8b3 100644 --- a/Source/Client/Core/UnitTests/Build/MockEvaluateEngine.h +++ b/Source/Client/Core/UnitTests/Build/MockEvaluateEngine.h @@ -38,13 +38,9 @@ namespace Soup::Core const OperationGraph& operationGraph, OperationResults& operationResults, const Path& temporaryDirectory, - const std::vector& globalAllowedReadAccess, - const std::vector& globalAllowedWriteAccess) + const std::vector& /*globalAllowedReadAccess*/, + const std::vector& /*globalAllowedWriteAccess*/) { - (operationGraph); - (globalAllowedReadAccess); - (globalAllowedWriteAccess); - std::stringstream message; message << "Evaluate: " << temporaryDirectory.ToString(); diff --git a/Source/Client/Core/UnitTests/Recipe/RecipeSMLTests.h b/Source/Client/Core/UnitTests/Recipe/RecipeSMLTests.h index 265dd514f..90267853d 100644 --- a/Source/Client/Core/UnitTests/Recipe/RecipeSMLTests.h +++ b/Source/Client/Core/UnitTests/Recipe/RecipeSMLTests.h @@ -164,8 +164,8 @@ IntegerValue: 55 FloatValue: 1.2 TrueValue: true FalseValue: false -Dependencies: {Build: [] -Runtime: [] +Dependencies: {Runtime: [] +Build: [] Test: [] } )";