diff options
author | hop311 <hop3114@gmail.com> | 2024-01-03 15:30:23 +0100 |
---|---|---|
committer | hop311 <hop3114@gmail.com> | 2024-01-03 15:43:35 +0100 |
commit | f0dd758b6c7f35ffb1f6b237805bcb8d39c20cc5 (patch) | |
tree | 21e54285c4f3927ecd3b1b621587d75b875ac3d3 | |
parent | 461ec160448373f8d9492b9c586ff53a35edef18 (diff) |
Added case insensitive ordered set and map and IdentifierRegistry
-rw-r--r-- | src/openvic-simulation/dataloader/Dataloader.cpp | 15 | ||||
-rw-r--r-- | src/openvic-simulation/dataloader/NodeTools.hpp | 4 | ||||
-rw-r--r-- | src/openvic-simulation/dataloader/Vic2PathSearch.cpp | 11 | ||||
-rw-r--r-- | src/openvic-simulation/scripts/ConditionalWeight.cpp | 4 | ||||
-rw-r--r-- | src/openvic-simulation/types/IdentifierRegistry.hpp | 35 | ||||
-rw-r--r-- | src/openvic-simulation/types/OrderedContainers.hpp | 76 | ||||
-rw-r--r-- | src/openvic-simulation/utility/StringUtils.hpp | 39 |
7 files changed, 139 insertions, 45 deletions
diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index 64d89e8..223b795 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -8,8 +8,8 @@ #include <lexy-vdf/Parser.hpp> #include "openvic-simulation/GameManager.hpp" -#include "openvic-simulation/utility/ConstexprIntToStr.hpp" #include "openvic-simulation/utility/Logger.hpp" +#include "openvic-simulation/utility/StringUtils.hpp" using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -34,13 +34,6 @@ static fs::path ensure_forward_slash_path(std::string_view path) { #endif } -static constexpr bool path_equals_case_insensitive(std::string_view lhs, std::string_view rhs) { - constexpr auto ichar_equals = [](unsigned char l, unsigned char r) { - return std::tolower(l) == std::tolower(r); - }; - return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), ichar_equals); -} - bool Dataloader::set_roots(path_vector_t const& new_roots) { if (!roots.empty()) { Logger::error("Overriding existing dataloader roots!"); @@ -91,7 +84,7 @@ fs::path Dataloader::lookup_file(std::string_view path, bool print_error) const for (fs::directory_entry const& entry : fs::directory_iterator { composed.parent_path(), ec }) { if (entry.is_regular_file()) { const fs::path file = entry; - if (path_equals_case_insensitive(file.filename().string(), filename)) { + if (StringUtils::strings_equal_case_insensitive(file.filename().string(), filename)) { return file; } } @@ -599,9 +592,9 @@ bool Dataloader::_load_events(GameManager& game_manager) { static constexpr std::string_view events_directory = "events"; const bool ret = apply_to_files( lookup_files_in_dir(events_directory, ".txt"), - [&game_manager](fs::path const& file) -> bool { + [this, &game_manager](fs::path const& file) -> bool { return game_manager.get_event_manager().load_event_file( - game_manager.get_politics_manager().get_issue_manager(), parse_defines(file).get_file_node() + game_manager.get_politics_manager().get_issue_manager(), parse_defines_cached(file).get_file_node() ); } ); diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp index f5f960f..8ad731b 100644 --- a/src/openvic-simulation/dataloader/NodeTools.hpp +++ b/src/openvic-simulation/dataloader/NodeTools.hpp @@ -19,8 +19,8 @@ namespace OpenVic { /* Template for map from strings to Ts, in which string_views can be * searched for without needing to be copied into a string */ - template<typename T> - using string_map_t = ordered_map<std::string, T>; + template<typename T, class Hash = container_hash<std::string>, class KeyEqual = std::equal_to<>> + using string_map_t = ordered_map<std::string, T, Hash, KeyEqual>; /* String set type supporting heterogeneous key lookup */ using string_set_t = ordered_set<std::string>; diff --git a/src/openvic-simulation/dataloader/Vic2PathSearch.cpp b/src/openvic-simulation/dataloader/Vic2PathSearch.cpp index d3468e4..26facbe 100644 --- a/src/openvic-simulation/dataloader/Vic2PathSearch.cpp +++ b/src/openvic-simulation/dataloader/Vic2PathSearch.cpp @@ -6,6 +6,7 @@ #include "openvic-simulation/types/OrderedContainers.hpp" #include "openvic-simulation/utility/ConstexprIntToStr.hpp" #include "openvic-simulation/utility/Logger.hpp" +#include "openvic-simulation/utility/StringUtils.hpp" #include "Dataloader.hpp" @@ -20,7 +21,6 @@ #endif using namespace OpenVic; -using namespace OpenVic::NodeTools; using namespace ovdl; #if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__)) @@ -31,17 +31,10 @@ using namespace ovdl; #define FILESYSTEM_NEEDS_FORWARD_SLASHES #endif -static constexpr bool path_equals_case_insensitive(std::string_view lhs, std::string_view rhs) { - constexpr auto ichar_equals = [](unsigned char l, unsigned char r) { - return std::tolower(l) == std::tolower(r); - }; - return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), ichar_equals); -} - // Windows and Mac by default act like case insensitive filesystems static constexpr bool path_equals(std::string_view lhs, std::string_view rhs) { #if defined(FILESYSTEM_CASE_INSENSITIVE) - return path_equals_case_insensitive(lhs, rhs); + return StringUtils::strings_equal_case_insensitive(lhs, rhs); #else return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); #endif diff --git a/src/openvic-simulation/scripts/ConditionalWeight.cpp b/src/openvic-simulation/scripts/ConditionalWeight.cpp index 29dc93b..17bbbd6 100644 --- a/src/openvic-simulation/scripts/ConditionalWeight.cpp +++ b/src/openvic-simulation/scripts/ConditionalWeight.cpp @@ -23,7 +23,9 @@ static NodeCallback auto expect_modifier(std::vector<T>& items) { node_callback_t ConditionalWeight::expect_conditional_weight(base_key_t base_key) { return expect_dictionary_keys( // TODO - add days and years as options with a shared expected count of ONE_EXACTLY - base_key_to_string(base_key), ONE_EXACTLY, expect_fixed_point(assign_variable_callback(base)), + base_key_to_string(base_key), ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(base)), + "days", ZERO_OR_ONE, success_callback, + "years", ZERO_OR_ONE, success_callback, "modifier", ZERO_OR_MORE, expect_modifier(condition_weight_items), "group", ZERO_OR_MORE, [this](ast::NodeCPtr node) -> bool { condition_weight_group_t items; diff --git a/src/openvic-simulation/types/IdentifierRegistry.hpp b/src/openvic-simulation/types/IdentifierRegistry.hpp index a385fca..53a68a5 100644 --- a/src/openvic-simulation/types/IdentifierRegistry.hpp +++ b/src/openvic-simulation/types/IdentifierRegistry.hpp @@ -110,14 +110,18 @@ namespace OpenVic { /* _GetIdentifier - takes _Type const* and returns std::string_view * _GetPointer - takes _Storage [const]& and returns T [const]* */ - template<typename _Type, typename _Storage, typename _GetIdentifier, typename _GetPointer> + template< + typename _Type, typename _Storage, typename _GetIdentifier, typename _GetPointer, + class Hash = container_hash<std::string>, class KeyEqual = std::equal_to<>> class UniqueKeyRegistry { + using identifier_index_map_t = string_map_t<size_t, Hash, KeyEqual>; + const std::string name; const bool log_lock; std::vector<_Storage> PROPERTY_REF(items); bool locked = false; - string_map_t<size_t> identifier_index_map; + identifier_index_map_t identifier_index_map; _GetIdentifier GetIdentifier; _GetPointer GetPointer; @@ -155,7 +159,7 @@ namespace OpenVic { return duplicate_callback(name, new_identifier); } } - const std::pair<string_map_t<size_t>::iterator, bool> ret = + const std::pair<typename identifier_index_map_t::iterator, bool> ret = identifier_index_map.emplace(std::move(new_identifier), items.size()); items.emplace_back(std::move(item)); return ret.second && ret.first->second + 1 == items.size(); @@ -279,8 +283,9 @@ namespace OpenVic { } std::vector<std::string_view> get_item_identifiers() const { - std::vector<std::string_view> identifiers(items.size()); - for (typename decltype(identifier_index_map)::value_type const& entry : identifier_index_map) { + std::vector<std::string_view> identifiers; + identifiers.reserve(items.size()); + for (typename identifier_index_map_t::value_type const& entry : identifier_index_map) { identifiers.push_back(entry.first); } return identifiers; @@ -314,8 +319,8 @@ namespace OpenVic { } }; - template<typename _Type, typename _GetIdentifier> - using ValueRegistry = UniqueKeyRegistry<_Type, _Type, _GetIdentifier, _addressof<_Type>>; + template<typename _Type, typename _GetIdentifier, class Hash = container_hash<std::string>, class KeyEqual = std::equal_to<>> + using ValueRegistry = UniqueKeyRegistry<_Type, _Type, _GetIdentifier, _addressof<_Type>, Hash, KeyEqual>; /* std::unique_ptr dynamic storage */ template<typename T> @@ -328,8 +333,8 @@ namespace OpenVic { } }; - template<typename _Type, typename _GetIdentifier> - using InstanceRegistry = UniqueKeyRegistry<_Type, std::unique_ptr<_Type>, _GetIdentifier, _uptr_get<_Type>>; + template<typename _Type, typename _GetIdentifier, class Hash = container_hash<std::string>, class KeyEqual = std::equal_to<>> + using InstanceRegistry = UniqueKeyRegistry<_Type, std::unique_ptr<_Type>, _GetIdentifier, _uptr_get<_Type>, Hash, KeyEqual>; /* HasIdentifier versions */ template<std::derived_from<HasIdentifier> T> @@ -339,11 +344,19 @@ namespace OpenVic { } }; + template<std::derived_from<HasIdentifier> _Type, class Hash = container_hash<std::string>, class KeyEqual = std::equal_to<>> + using IdentifierRegistry = ValueRegistry<_Type, _get_identifier<_Type>, Hash, KeyEqual>; + template<std::derived_from<HasIdentifier> _Type> - using IdentifierRegistry = ValueRegistry<_Type, _get_identifier<_Type>>; + using CaseInsensitiveIdentifierRegistry = + IdentifierRegistry<_Type, case_insensitive_string_hash, case_insensitive_string_equal>; + + template<std::derived_from<HasIdentifier> _Type, class Hash = container_hash<std::string>, class KeyEqual = std::equal_to<>> + using IdentifierInstanceRegistry = InstanceRegistry<_Type, _get_identifier<_Type>, Hash, KeyEqual>; template<std::derived_from<HasIdentifier> _Type> - using IdentifierInstanceRegistry = InstanceRegistry<_Type, _get_identifier<_Type>>; + using CaseInsensitiveIdentifierInstanceRegistry = + IdentifierInstanceRegistry<_Type, case_insensitive_string_hash, case_insensitive_string_equal>; /* Macros to generate declaration and constant accessor methods for a UniqueKeyRegistry member variable. */ diff --git a/src/openvic-simulation/types/OrderedContainers.hpp b/src/openvic-simulation/types/OrderedContainers.hpp index e90000c..1df9b10 100644 --- a/src/openvic-simulation/types/OrderedContainers.hpp +++ b/src/openvic-simulation/types/OrderedContainers.hpp @@ -1,6 +1,6 @@ #pragma once -#include <concepts> +#include <cctype> #include <deque> #include <functional> #include <memory> @@ -8,18 +8,19 @@ #include <tsl/ordered_map.h> #include <tsl/ordered_set.h> +#include "openvic-simulation/utility/StringUtils.hpp" #include "openvic-simulation/utility/Utility.hpp" namespace OpenVic { struct ordered_container_string_hash { using is_transparent = void; - [[nodiscard]] size_t operator()(const char* txt) const { + [[nodiscard]] size_t operator()(char const* txt) const { return std::hash<std::string_view> {}(txt); } [[nodiscard]] size_t operator()(std::string_view txt) const { return std::hash<std::string_view> {}(txt); } - [[nodiscard]] size_t operator()(const std::string& txt) const { + [[nodiscard]] size_t operator()(std::string const& txt) const { return std::hash<std::string> {}(txt); } }; @@ -32,7 +33,7 @@ namespace OpenVic { template<> struct container_hash<std::string_view> : ordered_container_string_hash {}; template<> - struct container_hash<const char*> : ordered_container_string_hash {}; + struct container_hash<char const*> : ordered_container_string_hash {}; // Useful for contiguous memory template< @@ -56,13 +57,13 @@ namespace OpenVic { // Useful for contiguous memory template< class Key, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>, class Allocator = std::allocator<Key>, - class ValueTypeContainer = std::deque<Key, Allocator>, class IndexType = std::uint_least32_t> + class IndexType = std::uint_least32_t> using vector_ordered_set = tsl::ordered_set<Key, Hash, KeyEqual, Allocator, std::vector<Key, Allocator>, IndexType>; // Useful for stable memory addresses (so long as you don't remove or insert values) template< class Key, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>, class Allocator = std::allocator<Key>, - class ValueTypeContainer = std::deque<Key, Allocator>, class IndexType = std::uint_least32_t> + class IndexType = std::uint_least32_t> using deque_ordered_set = tsl::ordered_set<Key, Hash, KeyEqual, Allocator, std::deque<Key, Allocator>, IndexType>; template< @@ -98,4 +99,67 @@ namespace OpenVic { IsDequeOrderedMap<T> && std::same_as<Key, typename T::key_type> && std::same_as<Value, typename T::mapped_type>; template<typename T, typename Key> concept IsDequeOrderedSetOf = IsDequeOrderedSet<T> && std::same_as<Key, typename T::key_type>; + + /* Case-Insensitive Containers */ + struct case_insensitive_string_hash { + using is_transparent = void; + + private: + /* Based on the byte array hashing functions in MSVC's <type_traits>. */ + [[nodiscard]] static constexpr size_t _hash_bytes_case_insensitive(char const* first, size_t count) { + constexpr size_t _offset_basis = 14695981039346656037ULL; + constexpr size_t _prime = 1099511628211ULL; + size_t hash = _offset_basis; + for (size_t i = 0; i < count; ++i) { + hash ^= static_cast<size_t>(std::tolower(static_cast<unsigned char>(first[i]))); + hash *= _prime; + } + return hash; + } + + public: + [[nodiscard]] constexpr size_t operator()(char const* txt) const { + return operator()(std::string_view { txt }); + } + [[nodiscard]] constexpr size_t operator()(std::string_view txt) const { + return _hash_bytes_case_insensitive(txt.data(), txt.length()); + } + [[nodiscard]] constexpr size_t operator()(std::string const& txt) const { + return _hash_bytes_case_insensitive(txt.data(), txt.length()); + } + }; + + struct case_insensitive_string_equal { + using is_transparent = void; + + [[nodiscard]] constexpr bool operator()(std::string_view const& lhs, std::string_view const& rhs) const { + return StringUtils::strings_equal_case_insensitive(lhs, rhs); + } + }; + + // Useful for contiguous memory + template<class Key, class T, class Allocator = std::allocator<std::pair<Key, T>>, class IndexType = std::uint_least32_t> + using case_insensitive_vector_ordered_map = + vector_ordered_map<Key, T, case_insensitive_string_hash, case_insensitive_string_equal, Allocator, IndexType>; + + // Useful for stable memory addresses (so long as you don't remove or insert values) + template<class Key, class T, class Allocator = std::allocator<std::pair<Key, T>>, class IndexType = std::uint_least32_t> + using case_insensitive_deque_ordered_map = + deque_ordered_map<Key, T, case_insensitive_string_hash, case_insensitive_string_equal, Allocator, IndexType>; + + template<class Key, class T, class Allocator = std::allocator<std::pair<Key, T>>, class IndexType = std::uint_least32_t> + using case_insensitive_ordered_map = case_insensitive_vector_ordered_map<Key, T, Allocator, IndexType>; + + // Useful for contiguous memory + template<class Key, class Allocator = std::allocator<Key>, class IndexType = std::uint_least32_t> + using case_insensitive_vector_ordered_set = + vector_ordered_set<Key, case_insensitive_string_hash, case_insensitive_string_equal, Allocator, IndexType>; + + // Useful for stable memory addresses (so long as you don't remove or insert values) + template<class Key, class Allocator = std::allocator<Key>, class IndexType = std::uint_least32_t> + using case_insensitive_deque_ordered_set = + deque_ordered_set<Key, case_insensitive_string_hash, case_insensitive_string_equal, Allocator, IndexType>; + + template<class Key, class Allocator = std::allocator<Key>, class IndexType = std::uint_least32_t> + using case_insensitive_ordered_set = case_insensitive_vector_ordered_set<Key, Allocator, IndexType>; } diff --git a/src/openvic-simulation/utility/StringUtils.hpp b/src/openvic-simulation/utility/StringUtils.hpp index ede1d6b..c5a0b71 100644 --- a/src/openvic-simulation/utility/StringUtils.hpp +++ b/src/openvic-simulation/utility/StringUtils.hpp @@ -1,5 +1,6 @@ #pragma once +#include <cctype> #include <cstdint> #include <cstring> #include <limits> @@ -97,7 +98,7 @@ namespace OpenVic::StringUtils { return string_to_uint64(str, str + length, successful, base); } - inline uint64_t string_to_uint64(std::string_view str, bool* successful = nullptr, int base = 10) { + inline constexpr uint64_t string_to_uint64(std::string_view str, bool* successful = nullptr, int base = 10) { return string_to_uint64(str.data(), str.length(), successful, base); } @@ -142,10 +143,20 @@ namespace OpenVic::StringUtils { return string_to_int64(str, str + length, successful, base); } - inline int64_t string_to_int64(std::string_view str, bool* successful = nullptr, int base = 10) { + inline constexpr int64_t string_to_int64(std::string_view str, bool* successful = nullptr, int base = 10) { return string_to_int64(str.data(), str.length(), successful, base); } + inline constexpr bool strings_equal_case_insensitive(std::string_view const& lhs, std::string_view const& rhs) { + if (lhs.size() != rhs.size()) { + return false; + } + constexpr auto ichar_equals = [](unsigned char l, unsigned char r) { + return std::tolower(l) == std::tolower(r); + }; + return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), ichar_equals); + } + inline constexpr std::string_view get_filename(std::string_view path) { size_t pos = path.size(); while (pos > 0 && path[pos - 1] != '/' && path[pos - 1] != '\\') { @@ -198,11 +209,29 @@ namespace OpenVic::StringUtils { return _append_string_views(std::string_view { args }...); } - inline constexpr std::string_view remove_extension(std::string_view path) { + inline constexpr size_t get_extension_pos(std::string_view const& path) { size_t pos = path.size(); while (pos > 0 && path[--pos] != '.') {} - if (path[pos] == '.') { - path.remove_suffix(path.size() - pos); + return pos; + } + + inline constexpr std::string_view get_extension(std::string_view path) { + if (!path.empty()) { + const size_t pos = get_extension_pos(path); + if (path[pos] == '.') { + path.remove_prefix(pos); + return path; + } + } + return {}; + } + + inline constexpr std::string_view remove_extension(std::string_view path) { + if (!path.empty()) { + const size_t pos = get_extension_pos(path); + if (path[pos] == '.') { + path.remove_suffix(path.size() - pos); + } } return path; } |