diff options
Diffstat (limited to 'src/openvic-simulation/types/OrderedContainers.hpp')
-rw-r--r-- | src/openvic-simulation/types/OrderedContainers.hpp | 76 |
1 files changed, 70 insertions, 6 deletions
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>; } |