aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author hop311 <hop3114@gmail.com>2024-01-03 15:30:23 +0100
committer hop311 <hop3114@gmail.com>2024-01-03 15:43:35 +0100
commitf0dd758b6c7f35ffb1f6b237805bcb8d39c20cc5 (patch)
tree21e54285c4f3927ecd3b1b621587d75b875ac3d3
parent461ec160448373f8d9492b9c586ff53a35edef18 (diff)
Added case insensitive ordered set and map and IdentifierRegistry
-rw-r--r--src/openvic-simulation/dataloader/Dataloader.cpp15
-rw-r--r--src/openvic-simulation/dataloader/NodeTools.hpp4
-rw-r--r--src/openvic-simulation/dataloader/Vic2PathSearch.cpp11
-rw-r--r--src/openvic-simulation/scripts/ConditionalWeight.cpp4
-rw-r--r--src/openvic-simulation/types/IdentifierRegistry.hpp35
-rw-r--r--src/openvic-simulation/types/OrderedContainers.hpp76
-rw-r--r--src/openvic-simulation/utility/StringUtils.hpp39
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;
}