diff options
author | Hop311 <Hop3114@gmail.com> | 2024-01-03 16:02:40 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-03 16:02:40 +0100 |
commit | b06b25bd2910818029ebbf1cd3014ef20a64e25b (patch) | |
tree | 21e54285c4f3927ecd3b1b621587d75b875ac3d3 /src/openvic-simulation/types | |
parent | 461ec160448373f8d9492b9c586ff53a35edef18 (diff) | |
parent | f0dd758b6c7f35ffb1f6b237805bcb8d39c20cc5 (diff) |
Merge pull request #118 from OpenVicProject/case-insensitive-registry
Added case insensitive ordered set and map and IdentifierRegistry
Diffstat (limited to 'src/openvic-simulation/types')
-rw-r--r-- | src/openvic-simulation/types/IdentifierRegistry.hpp | 35 | ||||
-rw-r--r-- | src/openvic-simulation/types/OrderedContainers.hpp | 76 |
2 files changed, 94 insertions, 17 deletions
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>; } |