From 14ba9531d118fab87b360db4aae765807fca3cec Mon Sep 17 00:00:00 2001 From: hop311 Date: Wed, 24 Jan 2024 23:28:09 +0000 Subject: Added StringMapCase and case insensitive expect_dictionary_keys --- src/openvic-simulation/dataloader/NodeTools.cpp | 79 +-------- src/openvic-simulation/dataloader/NodeTools.hpp | 183 +++++++++++++++------ src/openvic-simulation/economy/ProductionType.cpp | 2 +- src/openvic-simulation/interface/GFX.cpp | 13 +- src/openvic-simulation/interface/GFX.hpp | 12 +- src/openvic-simulation/interface/GUI.cpp | 27 ++- src/openvic-simulation/interface/GUI.hpp | 24 +-- src/openvic-simulation/interface/LoadBase.hpp | 6 +- src/openvic-simulation/map/TerrainType.cpp | 6 +- .../types/IdentifierRegistry.hpp | 55 +++---- src/openvic-simulation/types/OrderedContainers.hpp | 52 +++++- src/openvic-simulation/utility/Utility.hpp | 8 + 12 files changed, 253 insertions(+), 214 deletions(-) (limited to 'src') diff --git a/src/openvic-simulation/dataloader/NodeTools.cpp b/src/openvic-simulation/dataloader/NodeTools.cpp index 957aa01..7ab0dbe 100644 --- a/src/openvic-simulation/dataloader/NodeTools.cpp +++ b/src/openvic-simulation/dataloader/NodeTools.cpp @@ -1,7 +1,6 @@ #include "NodeTools.hpp" #include "openvic-simulation/types/Colour.hpp" -#include "openvic-simulation/utility/TslHelper.hpp" using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -70,7 +69,7 @@ node_callback_t NodeTools::expect_identifier_or_string(callback_t callback) { - static const case_insensitive_string_map_t bool_map = { { "yes", true }, { "no", false } }; + static const case_insensitive_string_map_t bool_map { { "yes", true }, { "no", false } }; return expect_identifier(expect_mapped_string(bool_map, callback)); } @@ -324,82 +323,6 @@ node_callback_t NodeTools::expect_dictionary(key_value_callback_t callback) { return expect_dictionary_and_length(default_length_callback, callback); } -bool NodeTools::add_key_map_entry( - key_map_t& key_map, std::string_view key, dictionary_entry_t::expected_count_t expected_count, node_callback_t callback -) { - if (!key_map.contains(key)) { - key_map.emplace(key, dictionary_entry_t { expected_count, callback }); - return true; - } - Logger::error("Duplicate expected dictionary key: ", key); - return false; -} - -bool NodeTools::remove_key_map_entry(key_map_t& key_map, std::string_view key) { - if (key_map.erase(key) == 0) { - Logger::error("Failed to find dictionary key to remove: ", key); - return false; - } - return true; -} - -key_value_callback_t NodeTools::dictionary_keys_callback(key_map_t& key_map, key_value_callback_t default_callback) { - return [&key_map, default_callback](std::string_view key, ast::NodeCPtr value) -> bool { - key_map_t::iterator it = key_map.find(key); - if (it == key_map.end()) { - return default_callback(key, value); - } - dictionary_entry_t& entry = it.value(); - if (++entry.count > 1 && !entry.can_repeat()) { - Logger::error("Invalid repeat of dictionary key: ", key); - return false; - } - if (entry.callback(value)) { - return true; - } else { - Logger::error("Callback failed for dictionary key: ", key); - return false; - } - }; -} - -bool NodeTools::check_key_map_counts(key_map_t& key_map) { - bool ret = true; - for (auto key_entry : mutable_iterator(key_map)) { - dictionary_entry_t& entry = key_entry.second; - if (entry.must_appear() && entry.count < 1) { - Logger::error("Mandatory dictionary key not present: ", key_entry.first); - ret = false; - } - entry.count = 0; - } - return ret; -} - -node_callback_t NodeTools::expect_dictionary_key_map_and_length_and_default( - key_map_t key_map, length_callback_t length_callback, key_value_callback_t default_callback -) { - return [length_callback, default_callback, key_map = std::move(key_map)](ast::NodeCPtr node) mutable -> bool { - bool ret = expect_dictionary_and_length(length_callback, dictionary_keys_callback(key_map, default_callback))(node); - ret &= check_key_map_counts(key_map); - return ret; - }; -} - -node_callback_t NodeTools::expect_dictionary_key_map_and_length(key_map_t key_map, length_callback_t length_callback) { - return expect_dictionary_key_map_and_length_and_default(std::move(key_map), length_callback, key_value_invalid_callback); -} - -node_callback_t NodeTools::expect_dictionary_key_map_and_default(key_map_t key_map, key_value_callback_t default_callback) { - return expect_dictionary_key_map_and_length_and_default(std::move(key_map), default_length_callback, default_callback); -} - -node_callback_t NodeTools::expect_dictionary_key_map(key_map_t key_map) { - return expect_dictionary_key_map_and_length_and_default( - std::move(key_map), default_length_callback, key_value_invalid_callback - ); -} - node_callback_t NodeTools::name_list_callback(callback_t callback) { return [callback](ast::NodeCPtr node) -> bool { name_list_t list; diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp index 9137d6a..54b61d0 100644 --- a/src/openvic-simulation/dataloader/NodeTools.hpp +++ b/src/openvic-simulation/dataloader/NodeTools.hpp @@ -14,21 +14,11 @@ #include "openvic-simulation/types/HasIdentifier.hpp" #include "openvic-simulation/types/OrderedContainers.hpp" #include "openvic-simulation/types/Vector.hpp" +#include "openvic-simulation/utility/TslHelper.hpp" namespace OpenVic { namespace ast = ovdl::v2script::ast; - /* Template for map from strings to Ts, in which string_views can be - * searched for without needing to be copied into a string */ - template, class KeyEqual = std::equal_to<>> - using string_map_t = ordered_map; - template - using case_insensitive_string_map_t = string_map_t; - - /* String set type supporting heterogeneous key lookup */ - using string_set_t = ordered_set; - using case_insensitive_string_set_t = case_insensitive_ordered_set; - using name_list_t = std::vector; std::ostream& operator<<(std::ostream& stream, name_list_t const& name_list); @@ -178,22 +168,80 @@ namespace OpenVic { } }; using enum dictionary_entry_t::expected_count_t; - using key_map_t = string_map_t; + template + using template_key_map_t = template_string_map_t; + + using key_map_t = template_key_map_t; + using case_insensitive_key_map_t = template_key_map_t; + + template bool add_key_map_entry( - key_map_t& key_map, std::string_view key, dictionary_entry_t::expected_count_t expected_count, - node_callback_t callback - ); - bool remove_key_map_entry(key_map_t& key_map, std::string_view key); - key_value_callback_t dictionary_keys_callback(key_map_t& key_map, key_value_callback_t default_callback); - bool check_key_map_counts(key_map_t& key_map); + template_key_map_t& key_map, std::string_view key, dictionary_entry_t::expected_count_t expected_count, + NodeCallback auto callback + ) { + if (!key_map.contains(key)) { + key_map.emplace(key, dictionary_entry_t { expected_count, callback }); + return true; + } + Logger::error("Duplicate expected dictionary key: ", key); + return false; + } - constexpr bool add_key_map_entries(key_map_t& key_map) { + template + bool remove_key_map_entry(template_key_map_t& key_map, std::string_view key) { + if (key_map.erase(key) == 0) { + Logger::error("Failed to find dictionary key to remove: ", key); + return false; + } return true; } - template + + template + KeyValueCallback auto dictionary_keys_callback( + template_key_map_t& key_map, KeyValueCallback auto default_callback + ) { + return [&key_map, default_callback](std::string_view key, ast::NodeCPtr value) -> bool { + typename template_key_map_t::iterator it = key_map.find(key); + if (it == key_map.end()) { + return default_callback(key, value); + } + dictionary_entry_t& entry = it.value(); + if (++entry.count > 1 && !entry.can_repeat()) { + Logger::error("Invalid repeat of dictionary key: ", key); + return false; + } + if (entry.callback(value)) { + return true; + } else { + Logger::error("Callback failed for dictionary key: ", key); + return false; + } + }; + } + + template + bool check_key_map_counts(template_key_map_t& key_map) { + bool ret = true; + for (auto key_entry : mutable_iterator(key_map)) { + dictionary_entry_t& entry = key_entry.second; + if (entry.must_appear() && entry.count < 1) { + Logger::error("Mandatory dictionary key not present: ", key_entry.first); + ret = false; + } + entry.count = 0; + } + return ret; + } + + template + constexpr bool add_key_map_entries(template_key_map_t& key_map) { + return true; + } + + template bool add_key_map_entries( - key_map_t& key_map, std::string_view key, dictionary_entry_t::expected_count_t expected_count, + template_key_map_t& key_map, std::string_view key, dictionary_entry_t::expected_count_t expected_count, NodeCallback auto callback, Args... args ) { bool ret = add_key_map_entry(key_map, key, expected_count, callback); @@ -201,43 +249,81 @@ namespace OpenVic { return ret; } - node_callback_t expect_dictionary_key_map_and_length_and_default( - key_map_t key_map, length_callback_t length_callback, key_value_callback_t default_callback - ); - node_callback_t expect_dictionary_key_map_and_length(key_map_t key_map, length_callback_t length_callback); - node_callback_t expect_dictionary_key_map_and_default(key_map_t key_map, key_value_callback_t default_callback); - node_callback_t expect_dictionary_key_map(key_map_t key_map); + template + NodeCallback auto expect_dictionary_key_map_and_length_and_default( + template_key_map_t key_map, LengthCallback auto length_callback, KeyValueCallback auto default_callback + ) { + return [length_callback, default_callback, key_map = std::move(key_map)](ast::NodeCPtr node) mutable -> bool { + bool ret = expect_dictionary_and_length( + length_callback, dictionary_keys_callback(key_map, default_callback) + )(node); + ret &= check_key_map_counts(key_map); + return ret; + }; + } - template + template + NodeCallback auto expect_dictionary_key_map_and_length( + template_key_map_t key_map, LengthCallback auto length_callback + ) { + return expect_dictionary_key_map_and_length_and_default( + std::move(key_map), length_callback, key_value_invalid_callback + ); + } + + template + NodeCallback auto expect_dictionary_key_map_and_default( + template_key_map_t key_map, KeyValueCallback auto default_callback + ) { + return expect_dictionary_key_map_and_length_and_default( + std::move(key_map), default_length_callback, default_callback + ); + } + + template + NodeCallback auto expect_dictionary_key_map(template_key_map_t key_map) { + return expect_dictionary_key_map_and_length_and_default( + std::move(key_map), default_length_callback, key_value_invalid_callback + ); + } + + template NodeCallback auto expect_dictionary_key_map_and_length_and_default( - key_map_t key_map, length_callback_t length_callback, key_value_callback_t default_callback, Args... args + template_key_map_t key_map, LengthCallback auto length_callback, KeyValueCallback auto default_callback, + Args... args ) { // TODO - pass return value back up (part of big key_map_t rewrite?) add_key_map_entries(key_map, args...); return expect_dictionary_key_map_and_length_and_default(std::move(key_map), length_callback, default_callback); } - template + template NodeCallback auto expect_dictionary_keys_and_length_and_default( LengthCallback auto length_callback, KeyValueCallback auto default_callback, Args... args ) { - return expect_dictionary_key_map_and_length_and_default({}, length_callback, default_callback, args...); + return expect_dictionary_key_map_and_length_and_default( + template_key_map_t {}, length_callback, default_callback, args... + ); } - template + template NodeCallback auto expect_dictionary_keys_and_length(LengthCallback auto length_callback, Args... args) { - return expect_dictionary_key_map_and_length_and_default({}, length_callback, key_value_invalid_callback, args...); + return expect_dictionary_key_map_and_length_and_default( + template_key_map_t {}, length_callback, key_value_invalid_callback, args... + ); } - template + template NodeCallback auto expect_dictionary_keys_and_default(KeyValueCallback auto default_callback, Args... args) { - return expect_dictionary_key_map_and_length_and_default({}, default_length_callback, default_callback, args...); + return expect_dictionary_key_map_and_length_and_default( + template_key_map_t {}, default_length_callback, default_callback, args... + ); } - template + template NodeCallback auto expect_dictionary_keys(Args... args) { return expect_dictionary_key_map_and_length_and_default( - {}, default_length_callback, key_value_invalid_callback, args... + template_key_map_t {}, default_length_callback, key_value_invalid_callback, args... ); } @@ -253,41 +339,42 @@ namespace OpenVic { NodeCallback auto expect_dictionary_reserve_length(Reservable auto& reservable, KeyValueCallback auto callback) { return expect_dictionary_and_length(reserve_length_callback(reservable), callback); } - template + template NodeCallback auto expect_dictionary_key_map_reserve_length_and_default( - Reservable auto& reservable, key_map_t key_map, KeyValueCallback auto default_callback, Args... args + Reservable auto& reservable, template_key_map_t key_map, KeyValueCallback auto default_callback, + Args... args ) { return expect_dictionary_key_map_and_length_and_default( std::move(key_map), reserve_length_callback(reservable), default_callback, args... ); } - template + template NodeCallback auto expect_dictionary_key_map_reserve_length( - Reservable auto& reservable, key_map_t key_map, Args... args + Reservable auto& reservable, template_key_map_t key_map, Args... args ) { return expect_dictionary_key_map_and_length(std::move(key_map), reserve_length_callback(reservable), args...); } - template + template NodeCallback auto expect_dictionary_keys_reserve_length_and_default( Reservable auto& reservable, KeyValueCallback auto default_callback, Args... args ) { - return expect_dictionary_keys_and_length_and_default( + return expect_dictionary_keys_and_length_and_default( reserve_length_callback(reservable), default_callback, args... ); } - template + template NodeCallback auto expect_dictionary_keys_reserve_length(Reservable auto& reservable, Args... args) { - return expect_dictionary_keys_and_length(reserve_length_callback(reservable), args...); + return expect_dictionary_keys_and_length(reserve_length_callback(reservable), args...); } node_callback_t name_list_callback(callback_t callback); - template + template Callback auto expect_mapped_string( - string_map_t const& map, Callback auto callback + template_string_map_t const& map, Callback auto callback ) { return [&map, callback](std::string_view string) -> bool { - const typename string_map_t::const_iterator it = map.find(string); + const typename template_string_map_t::const_iterator it = map.find(string); if (it != map.end()) { return callback(it->second); } diff --git a/src/openvic-simulation/economy/ProductionType.cpp b/src/openvic-simulation/economy/ProductionType.cpp index 9c806e5..7029fd1 100644 --- a/src/openvic-simulation/economy/ProductionType.cpp +++ b/src/openvic-simulation/economy/ProductionType.cpp @@ -230,7 +230,7 @@ bool ProductionTypeManager::load_production_types_file( { "factory", FACTORY }, { "rgo", RGO }, { "artisan", ARTISAN } }; - const auto parse_node = expect_dictionary_keys( + auto parse_node = expect_dictionary_keys( "template", ZERO_OR_ONE, success_callback, /* Already parsed using expect_key in Pass #1 above. */ "bonus", ZERO_OR_MORE, [&bonuses](ast::NodeCPtr bonus_node) -> bool { ConditionScript trigger { scope_t::STATE, scope_t::NO_SCOPE, scope_t::NO_SCOPE }; diff --git a/src/openvic-simulation/interface/GFX.cpp b/src/openvic-simulation/interface/GFX.cpp index 0ec2954..ca31419 100644 --- a/src/openvic-simulation/interface/GFX.cpp +++ b/src/openvic-simulation/interface/GFX.cpp @@ -26,11 +26,10 @@ node_callback_t Sprite::expect_sprites(length_callback_t length_callback, callba TextureSprite::TextureSprite() : texture_file {}, no_of_frames { NO_FRAMES } {} -bool TextureSprite::_fill_key_map(key_map_t& key_map) { +bool TextureSprite::_fill_key_map(case_insensitive_key_map_t& key_map) { bool ret = Sprite::_fill_key_map(key_map); ret &= add_key_map_entries(key_map, "texturefile", ZERO_OR_ONE, expect_string(assign_variable_callback_string(texture_file)), - "textureFile", ZERO_OR_ONE, expect_string(assign_variable_callback_string(texture_file)), "noOfFrames", ZERO_OR_ONE, expect_uint(assign_variable_callback(no_of_frames)), "norefcount", ZERO_OR_ONE, success_callback, @@ -45,7 +44,7 @@ bool TextureSprite::_fill_key_map(key_map_t& key_map) { TileTextureSprite::TileTextureSprite() : texture_file {}, size {} {} -bool TileTextureSprite::_fill_key_map(key_map_t& key_map) { +bool TileTextureSprite::_fill_key_map(case_insensitive_key_map_t& key_map) { bool ret = Sprite::_fill_key_map(key_map); ret &= add_key_map_entries(key_map, "texturefile", ZERO_OR_ONE, expect_string(assign_variable_callback_string(texture_file)), @@ -59,7 +58,7 @@ bool TileTextureSprite::_fill_key_map(key_map_t& key_map) { ProgressBar::ProgressBar() : back_colour {}, progress_colour {} {} -bool ProgressBar::_fill_key_map(key_map_t& key_map) { +bool ProgressBar::_fill_key_map(case_insensitive_key_map_t& key_map) { bool ret = Sprite::_fill_key_map(key_map); ret &= add_key_map_entries(key_map, "color", ONE_EXACTLY, expect_colour(assign_variable_callback(progress_colour)), @@ -78,7 +77,7 @@ bool ProgressBar::_fill_key_map(key_map_t& key_map) { PieChart::PieChart() : size {} {} -bool PieChart::_fill_key_map(key_map_t& key_map) { +bool PieChart::_fill_key_map(case_insensitive_key_map_t& key_map) { bool ret = Sprite::_fill_key_map(key_map); ret &= add_key_map_entries(key_map, "size", ONE_EXACTLY, expect_uint(assign_variable_callback(size))); return ret; @@ -86,7 +85,7 @@ bool PieChart::_fill_key_map(key_map_t& key_map) { LineChart::LineChart() : size {}, linewidth {} {} -bool LineChart::_fill_key_map(key_map_t& key_map) { +bool LineChart::_fill_key_map(case_insensitive_key_map_t& key_map) { bool ret = Sprite::_fill_key_map(key_map); ret &= add_key_map_entries(key_map, "size", ONE_EXACTLY, expect_ivec2(assign_variable_callback(size)), @@ -98,7 +97,7 @@ bool LineChart::_fill_key_map(key_map_t& key_map) { MaskedFlag::MaskedFlag() : overlay_file {}, mask_file {} {} -bool MaskedFlag::_fill_key_map(key_map_t& key_map) { +bool MaskedFlag::_fill_key_map(case_insensitive_key_map_t& key_map) { bool ret = Sprite::_fill_key_map(key_map); ret &= add_key_map_entries(key_map, "textureFile1", ONE_EXACTLY, expect_string(assign_variable_callback_string(overlay_file)), diff --git a/src/openvic-simulation/interface/GFX.hpp b/src/openvic-simulation/interface/GFX.hpp index efd2293..21baa85 100644 --- a/src/openvic-simulation/interface/GFX.hpp +++ b/src/openvic-simulation/interface/GFX.hpp @@ -52,7 +52,7 @@ namespace OpenVic::GFX { protected: TextureSprite(); - bool _fill_key_map(NodeTools::key_map_t& key_map) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override; public: TextureSprite(TextureSprite&&) = default; @@ -70,7 +70,7 @@ namespace OpenVic::GFX { protected: TileTextureSprite(); - bool _fill_key_map(NodeTools::key_map_t& key_map) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override; public: TileTextureSprite(TileTextureSprite&&) = default; @@ -93,7 +93,7 @@ namespace OpenVic::GFX { protected: ProgressBar(); - bool _fill_key_map(NodeTools::key_map_t& key_map) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override; public: ProgressBar(ProgressBar&&) = default; @@ -110,7 +110,7 @@ namespace OpenVic::GFX { protected: PieChart(); - bool _fill_key_map(NodeTools::key_map_t& key_map) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override; public: PieChart(PieChart&&) = default; @@ -128,7 +128,7 @@ namespace OpenVic::GFX { protected: LineChart(); - bool _fill_key_map(NodeTools::key_map_t& key_map) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override; public: LineChart(LineChart&&) = default; @@ -146,7 +146,7 @@ namespace OpenVic::GFX { protected: MaskedFlag(); - bool _fill_key_map(NodeTools::key_map_t& key_map) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override; public: MaskedFlag(MaskedFlag&&) = default; diff --git a/src/openvic-simulation/interface/GUI.cpp b/src/openvic-simulation/interface/GUI.cpp index 23a577c..7aebfe8 100644 --- a/src/openvic-simulation/interface/GUI.cpp +++ b/src/openvic-simulation/interface/GUI.cpp @@ -8,7 +8,7 @@ using namespace OpenVic::NodeTools; Element::Element() : position {}, orientation { orientation_t::UPPER_LEFT } {} -bool Element::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { +bool Element::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) { bool ret = Named::_fill_key_map(key_map, ui_manager); using enum orientation_t; static const string_map_t orientation_map = { @@ -18,14 +18,13 @@ bool Element::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_m }; ret &= add_key_map_entries(key_map, "position", ONE_EXACTLY, expect_fvec2(assign_variable_callback(position)), - "orientation", ZERO_OR_ONE, expect_string(expect_mapped_string(orientation_map, assign_variable_callback(orientation))), - "Orientation", ZERO_OR_ONE, expect_string(expect_mapped_string(orientation_map, assign_variable_callback(orientation))) + "orientation", ZERO_OR_ONE, expect_string(expect_mapped_string(orientation_map, assign_variable_callback(orientation))) ); return ret; } bool Element::_fill_elements_key_map( - NodeTools::key_map_t& key_map, callback_t&&> callback, UIManager const& ui_manager + NodeTools::case_insensitive_key_map_t& key_map, callback_t&&> callback, UIManager const& ui_manager ) { bool ret = true; ret &= add_key_map_entries(key_map, @@ -42,7 +41,7 @@ bool Element::_fill_elements_key_map( return ret; } -bool Scene::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { +bool Scene::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) { return Element::_fill_elements_key_map(key_map, [this](std::unique_ptr&& element) -> bool { return scene_elements.add_item(std::move(element)); }, ui_manager); @@ -59,7 +58,7 @@ node_callback_t Scene::expect_scene( Window::Window() : moveable { false }, fullscreen { false } {} -bool Window::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { +bool Window::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) { bool ret = Element::_fill_elements_key_map(key_map, [this](std::unique_ptr&& element) -> bool { return window_elements.add_item(std::move(element)); }, ui_manager); @@ -78,7 +77,7 @@ bool Window::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_ma Icon::Icon() : sprite { nullptr }, frame { GFX::NO_FRAMES } {} -bool Icon::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { +bool Icon::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) { bool ret = Element::_fill_key_map(key_map, ui_manager); ret &= add_key_map_entries(key_map, "spriteType", ONE_EXACTLY, expect_string(ui_manager.expect_sprite_str(assign_variable_callback_pointer(sprite))), @@ -89,7 +88,7 @@ bool Icon::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_mana BaseButton::BaseButton() : sprite { nullptr } {} -bool BaseButton::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { +bool BaseButton::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) { bool ret = Element::_fill_key_map(key_map, ui_manager); // look up sprite registry for texture sprite with name... ret &= add_key_map_entries(key_map, @@ -104,7 +103,7 @@ bool BaseButton::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& u Button::Button() : text {}, font { nullptr} {} -bool Button::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { +bool Button::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) { bool ret = BaseButton::_fill_key_map(key_map, ui_manager); ret &= add_key_map_entries(key_map, "buttonText", ZERO_OR_ONE, expect_string(assign_variable_callback_string(text), true), @@ -118,14 +117,14 @@ bool Button::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_ma return ret; } -bool Checkbox::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { +bool Checkbox::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) { bool ret = BaseButton::_fill_key_map(key_map, ui_manager); return ret; } AlignedElement::AlignedElement() : format { format_t::left } {} -bool AlignedElement::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { +bool AlignedElement::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) { bool ret = Element::_fill_key_map(key_map, ui_manager); using enum format_t; static const string_map_t format_map = { @@ -139,7 +138,7 @@ bool AlignedElement::_fill_key_map(NodeTools::key_map_t& key_map, UIManager cons Text::Text() : text {}, font { nullptr } {} -bool Text::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { +bool Text::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) { bool ret = AlignedElement::_fill_key_map(key_map, ui_manager); ret &= add_key_map_entries(key_map, "text", ZERO_OR_ONE, expect_string(assign_variable_callback_string(text), true), @@ -158,7 +157,7 @@ bool Text::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_mana OverlappingElementsBox::OverlappingElementsBox() : size {} {} -bool OverlappingElementsBox::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { +bool OverlappingElementsBox::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) { bool ret = AlignedElement::_fill_key_map(key_map, ui_manager); ret &= add_key_map_entries(key_map, "size", ONE_EXACTLY, expect_fvec2(assign_variable_callback(size)), @@ -169,7 +168,7 @@ bool OverlappingElementsBox::_fill_key_map(NodeTools::key_map_t& key_map, UIMana ListBox::ListBox() : size {} {} -bool ListBox::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { +bool ListBox::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) { bool ret = Element::_fill_key_map(key_map, ui_manager); ret &= add_key_map_entries(key_map, "backGround", ZERO_OR_ONE, success_callback, diff --git a/src/openvic-simulation/interface/GUI.hpp b/src/openvic-simulation/interface/GUI.hpp index d658adf..96bb2a2 100644 --- a/src/openvic-simulation/interface/GUI.hpp +++ b/src/openvic-simulation/interface/GUI.hpp @@ -23,9 +23,9 @@ namespace OpenVic::GUI { protected: Element(); - bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) override; static bool _fill_elements_key_map( - NodeTools::key_map_t& key_map, NodeTools::callback_t&&> callback, + NodeTools::case_insensitive_key_map_t& key_map, NodeTools::callback_t&&> callback, UIManager const& ui_manager ); @@ -45,7 +45,7 @@ namespace OpenVic::GUI { protected: Scene() = default; - bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) override; public: Scene(Scene&&) = default; @@ -72,7 +72,7 @@ namespace OpenVic::GUI { protected: Window(); - bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) override; public: Window(Window&&) = default; @@ -90,7 +90,7 @@ namespace OpenVic::GUI { protected: Icon(); - bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) override; public: Icon(Icon&&) = default; @@ -106,7 +106,7 @@ namespace OpenVic::GUI { protected: BaseButton(); - bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) override; public: BaseButton(BaseButton&&) = default; @@ -126,7 +126,7 @@ namespace OpenVic::GUI { protected: Button(); - bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) override; public: Button(Button&&) = default; @@ -141,7 +141,7 @@ namespace OpenVic::GUI { protected: Checkbox() = default; - bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) override; public: Checkbox(Checkbox&&) = default; @@ -162,7 +162,7 @@ namespace OpenVic::GUI { protected: AlignedElement(); - bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) override; public: AlignedElement(AlignedElement&&) = default; @@ -183,7 +183,7 @@ namespace OpenVic::GUI { protected: Text(); - bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) override; public: Text(Text&&) = default; @@ -201,7 +201,7 @@ namespace OpenVic::GUI { protected: OverlappingElementsBox(); - bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) override; public: OverlappingElementsBox(OverlappingElementsBox&&) = default; @@ -220,7 +220,7 @@ namespace OpenVic::GUI { protected: ListBox(); - bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) override; public: ListBox(ListBox&&) = default; diff --git a/src/openvic-simulation/interface/LoadBase.hpp b/src/openvic-simulation/interface/LoadBase.hpp index 3363651..10b0169 100644 --- a/src/openvic-simulation/interface/LoadBase.hpp +++ b/src/openvic-simulation/interface/LoadBase.hpp @@ -10,14 +10,14 @@ namespace OpenVic { protected: LoadBase() = default; - virtual bool _fill_key_map(NodeTools::key_map_t&, Context...) = 0; + virtual bool _fill_key_map(NodeTools::case_insensitive_key_map_t&, Context...) = 0; public: LoadBase(LoadBase&&) = default; virtual ~LoadBase() = default; bool load(ast::NodeCPtr node, Context... context) { - NodeTools::key_map_t key_map; + NodeTools::case_insensitive_key_map_t key_map; bool ret = _fill_key_map(key_map, context...); ret &= NodeTools::expect_dictionary_key_map(std::move(key_map))(node); return ret; @@ -45,7 +45,7 @@ namespace OpenVic { protected: Named() = default; - virtual bool _fill_key_map(NodeTools::key_map_t& key_map, Context...) override { + virtual bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, Context...) override { using namespace OpenVic::NodeTools; return add_key_map_entries(key_map, "name", ONE_EXACTLY, expect_string(assign_variable_callback_string(name))); } diff --git a/src/openvic-simulation/map/TerrainType.cpp b/src/openvic-simulation/map/TerrainType.cpp index e7dd068..93a5e83 100644 --- a/src/openvic-simulation/map/TerrainType.cpp +++ b/src/openvic-simulation/map/TerrainType.cpp @@ -1,7 +1,5 @@ #include "TerrainType.hpp" -#include - #include "openvic-simulation/types/Colour.hpp" using namespace OpenVic; @@ -132,7 +130,9 @@ TerrainTypeMapping::index_t TerrainTypeManager::get_terrain_texture_limit() cons bool TerrainTypeManager::load_terrain_types(ModifierManager const& modifier_manager, ast::NodeCPtr root) { const bool ret = expect_dictionary_keys_reserve_length_and_default( terrain_type_mappings, - std::bind_front(&TerrainTypeManager::_load_terrain_type_mapping, this), + [this](std::string_view key, ast::NodeCPtr value) -> bool { + return _load_terrain_type_mapping(key, value); + }, "terrain", ONE_EXACTLY, expect_uint(assign_variable_callback(terrain_texture_limit)), "categories", ONE_EXACTLY, _load_terrain_type_categories(modifier_manager) )(root); diff --git a/src/openvic-simulation/types/IdentifierRegistry.hpp b/src/openvic-simulation/types/IdentifierRegistry.hpp index 4d002e7..7e6fdb3 100644 --- a/src/openvic-simulation/types/IdentifierRegistry.hpp +++ b/src/openvic-simulation/types/IdentifierRegistry.hpp @@ -142,26 +142,11 @@ namespace OpenVic { } }; - /* Registry Identifier Map Info - how unique identifier strings are compared when looking up entries. */ - template - concept RegistryIdentifierMapInfo = requires(std::string_view identifier) { - { typename IdentifierMapInfo::hash {}(identifier) } -> std::same_as; - { typename IdentifierMapInfo::equal {}(identifier, identifier) } -> std::same_as; - }; - struct RegistryIdentifierMapInfoCaseSensitive { - using hash = container_hash; - using equal = std::equal_to<>; - }; - struct RegistryIdentifierMapInfoCaseInsensitive { - using hash = case_insensitive_string_hash; - using equal = case_insensitive_string_equal; - }; - template< RegistryValueInfo ValueInfo, /* The type that is being registered and that has unique string identifiers */ template typename _ItemInfo, /* How the type is being stored, usually either by value or std::unique_ptr */ template typename _StorageInfo = RegistryStorageInfoVector, /* How items are stored, including indexing type */ - RegistryIdentifierMapInfo IdentifierMapInfo = RegistryIdentifierMapInfoCaseSensitive /* Identifier map parameters */ + StringMapCase Case = StringMapCaseSensitive /* Identifier map parameters */ > requires( RegistryItemInfo<_ItemInfo, typename ValueInfo::internal_value_type> && @@ -177,8 +162,7 @@ namespace OpenVic { private: using StorageInfo = _StorageInfo; using index_type = typename StorageInfo::index_type; - using identifier_index_map_t = - string_map_t; + using identifier_index_map_t = template_string_map_t; public: using storage_type = typename StorageInfo::storage_type; @@ -440,50 +424,49 @@ namespace OpenVic { /* Item Specialisations */ template< RegistryValueInfo ValueInfo, template typename StorageInfo = RegistryStorageInfoVector, - RegistryIdentifierMapInfo IdentifierMapInfo = RegistryIdentifierMapInfoCaseSensitive + StringMapCase Case = StringMapCaseSensitive > - requires RegistryStorageInfo::item_type> - using ValueRegistry = UniqueKeyRegistry; + requires + RegistryStorageInfo::item_type> + using ValueRegistry = UniqueKeyRegistry; template< RegistryValueInfo ValueInfo, template typename StorageInfo = RegistryStorageInfoVector, - RegistryIdentifierMapInfo IdentifierMapInfo = RegistryIdentifierMapInfoCaseSensitive + StringMapCase Case = StringMapCaseSensitive > - requires RegistryStorageInfo::item_type> - using InstanceRegistry = UniqueKeyRegistry; + requires + RegistryStorageInfo::item_type> + using InstanceRegistry = UniqueKeyRegistry; /* HasIdentifier Specialisations */ template< std::derived_from Value, template typename StorageInfo = RegistryStorageInfoVector, - RegistryIdentifierMapInfo IdentifierMapInfo = RegistryIdentifierMapInfoCaseSensitive + StringMapCase Case = StringMapCaseSensitive > - using IdentifierRegistry = ValueRegistry, StorageInfo, IdentifierMapInfo>; + using IdentifierRegistry = ValueRegistry, StorageInfo, Case>; template< std::derived_from Value, template typename StorageInfo = RegistryStorageInfoVector, - RegistryIdentifierMapInfo IdentifierMapInfo = RegistryIdentifierMapInfoCaseSensitive + StringMapCase Case = StringMapCaseSensitive > using IdentifierPointerRegistry = - ValueRegistry>, StorageInfo, IdentifierMapInfo>; + ValueRegistry>, StorageInfo, Case>; template< std::derived_from Value, template typename StorageInfo = RegistryStorageInfoVector, - RegistryIdentifierMapInfo IdentifierMapInfo = RegistryIdentifierMapInfoCaseSensitive + StringMapCase Case = StringMapCaseSensitive > - using IdentifierInstanceRegistry = InstanceRegistry, StorageInfo, IdentifierMapInfo>; + using IdentifierInstanceRegistry = InstanceRegistry, StorageInfo, Case>; /* Case-Insensitive HasIdentifier Specialisations */ template Value, template typename StorageInfo = RegistryStorageInfoVector> - using CaseInsensitiveIdentifierRegistry = - IdentifierRegistry; + using CaseInsensitiveIdentifierRegistry = IdentifierRegistry; template Value, template typename StorageInfo = RegistryStorageInfoVector> - using CaseInsensitiveIdentifierPointerRegistry = - IdentifierPointerRegistry; + using CaseInsensitiveIdentifierPointerRegistry = IdentifierPointerRegistry; template Value, template typename StorageInfo = RegistryStorageInfoVector> - using CaseInsensitiveIdentifierInstanceRegistry = - IdentifierInstanceRegistry; + using CaseInsensitiveIdentifierInstanceRegistry = IdentifierInstanceRegistry; /* 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 e9f8717..31bf17a 100644 --- a/src/openvic-simulation/types/OrderedContainers.hpp +++ b/src/openvic-simulation/types/OrderedContainers.hpp @@ -72,17 +72,17 @@ namespace OpenVic { using ordered_set = vector_ordered_set; template - concept IsOrderedMap = utility::is_specialization_of_v; + concept IsOrderedMap = utility::is_derived_from_specialization_of; template - concept IsOrderedSet = utility::is_specialization_of_v; + concept IsOrderedSet = utility::is_derived_from_specialization_of; template - concept IsVectorOrderedMap = utility::is_specialization_of_v; + concept IsVectorOrderedMap = utility::is_derived_from_specialization_of; template - concept IsVectorOrderedSet = utility::is_specialization_of_v; + concept IsVectorOrderedSet = utility::is_derived_from_specialization_of; template - concept IsDequeOrderedMap = utility::is_specialization_of_v; + concept IsDequeOrderedMap = utility::is_derived_from_specialization_of; template - concept IsDequeOrderedSet = utility::is_specialization_of_v; + concept IsDequeOrderedSet = utility::is_derived_from_specialization_of; template concept IsOrderedMapOf = @@ -162,4 +162,44 @@ namespace OpenVic { template, class IndexType = std::uint_least32_t> using case_insensitive_ordered_set = case_insensitive_vector_ordered_set; + + template + concept StringMapCase = requires(std::string_view identifier) { + { typename Case::hash {}(identifier) } -> std::same_as; + { typename Case::equal {}(identifier, identifier) } -> std::same_as; + }; + struct StringMapCaseSensitive { + using hash = container_hash; + using equal = std::equal_to<>; + }; + struct StringMapCaseInsensitive { + using hash = case_insensitive_string_hash; + using equal = case_insensitive_string_equal; + }; + + /* Intermediate struct that "remembers" Case, instead of just decomposing it into its hash and equal components, + * needed so that templates can deduce the Case with which a type was defined. */ + template typename Container, StringMapCase Case, typename... Args> + struct template_case_container_t : Container { + using container_t = Container; + using container_t::container_t; + + using case_t = Case; + }; + + /* Template for map with string keys, supporting search by string_view without creating an intermediate string. */ + template + using template_string_map_t = template_case_container_t; + + template + using string_map_t = template_string_map_t; + template + using case_insensitive_string_map_t = template_string_map_t; + + /* Template for set with string elements, supporting search by string_view without creating an intermediate string. */ + template + using template_string_set_t = template_case_container_t; + + using string_set_t = template_string_set_t; + using case_insensitive_string_set_t = template_string_set_t; } diff --git a/src/openvic-simulation/utility/Utility.hpp b/src/openvic-simulation/utility/Utility.hpp index 9951532..8180e55 100644 --- a/src/openvic-simulation/utility/Utility.hpp +++ b/src/openvic-simulation/utility/Utility.hpp @@ -81,6 +81,14 @@ namespace OpenVic::utility { template class Z> inline constexpr bool is_specialization_of_v = is_specialization_of::value; + template class Template, typename... Args> + void _derived_from_specialization_impl(const Template&); + + template class Template> + concept is_derived_from_specialization_of = requires(const T& t) { + _derived_from_specialization_impl