From f83e869def6608f64606aead24ad1cfbb6f5c72a Mon Sep 17 00:00:00 2001 From: hop311 Date: Tue, 16 Jul 2024 23:57:50 +0100 Subject: Add IndexedMap and use in low key count, high value density cases --- src/openvic-simulation/InstanceManager.cpp | 21 +- .../country/CountryDefinition.cpp | 4 +- .../country/CountryDefinition.hpp | 5 +- src/openvic-simulation/country/CountryInstance.cpp | 57 ++++-- src/openvic-simulation/country/CountryInstance.hpp | 27 ++- src/openvic-simulation/dataloader/Dataloader.cpp | 5 +- src/openvic-simulation/dataloader/NodeTools.hpp | 21 ++ src/openvic-simulation/economy/GoodDefinition.cpp | 2 +- src/openvic-simulation/economy/GoodDefinition.hpp | 5 +- src/openvic-simulation/history/CountryHistory.cpp | 25 ++- src/openvic-simulation/history/CountryHistory.hpp | 21 +- src/openvic-simulation/map/MapInstance.cpp | 13 +- src/openvic-simulation/map/MapInstance.hpp | 11 +- src/openvic-simulation/map/Mapmode.cpp | 2 +- src/openvic-simulation/map/Mapmode.hpp | 4 +- src/openvic-simulation/map/ProvinceDefinition.cpp | 4 +- src/openvic-simulation/map/ProvinceDefinition.hpp | 4 +- src/openvic-simulation/map/ProvinceInstance.cpp | 20 +- src/openvic-simulation/map/ProvinceInstance.hpp | 14 +- src/openvic-simulation/politics/NationalFocus.cpp | 5 +- src/openvic-simulation/politics/NationalFocus.hpp | 12 +- src/openvic-simulation/pop/Pop.cpp | 37 ++-- src/openvic-simulation/pop/Pop.hpp | 11 +- src/openvic-simulation/types/HasIdentifier.hpp | 18 ++ src/openvic-simulation/types/IndexedMap.hpp | 220 +++++++++++++++++++++ 25 files changed, 444 insertions(+), 124 deletions(-) create mode 100644 src/openvic-simulation/types/IndexedMap.hpp diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp index c51dec7..d314acd 100644 --- a/src/openvic-simulation/InstanceManager.cpp +++ b/src/openvic-simulation/InstanceManager.cpp @@ -69,7 +69,18 @@ bool InstanceManager::setup() { } bool ret = good_instance_manager.setup(definition_manager.get_economy_manager().get_good_definition_manager()); - ret &= map_instance.setup(definition_manager.get_economy_manager().get_building_type_manager()); + ret &= map_instance.setup( + definition_manager.get_economy_manager().get_building_type_manager(), + definition_manager.get_pop_manager().get_pop_types(), + definition_manager.get_politics_manager().get_ideology_manager().get_ideologies() + ); + ret &= map_instance.get_state_manager().generate_states(map_instance); + ret &= country_instance_manager.generate_country_instances( + definition_manager.get_country_definition_manager(), + definition_manager.get_research_manager().get_technology_manager().get_technologies(), + definition_manager.get_research_manager().get_invention_manager().get_inventions(), + definition_manager.get_politics_manager().get_ideology_manager().get_ideologies() + ); game_instance_setup = true; @@ -104,14 +115,10 @@ bool InstanceManager::load_bookmark(Bookmark const* new_bookmark) { bool ret = map_instance.apply_history_to_provinces( definition_manager.get_history_manager().get_province_manager(), today, - // TODO - the following arguments are for generating test pop attributes - definition_manager.get_politics_manager().get_ideology_manager(), - definition_manager.get_politics_manager().get_issue_manager(), - *definition_manager.get_country_definition_manager().get_country_definition_by_identifier("ENG") + // TODO - the following argument is for generating test pop attributes + definition_manager.get_politics_manager().get_issue_manager() ); - ret &= map_instance.get_state_manager().generate_states(map_instance); - ret &= country_instance_manager.generate_country_instances(definition_manager.get_country_definition_manager()); ret &= country_instance_manager.apply_history_to_countries( definition_manager.get_history_manager().get_country_manager(), today, unit_instance_manager, map_instance ); diff --git a/src/openvic-simulation/country/CountryDefinition.cpp b/src/openvic-simulation/country/CountryDefinition.cpp index e414e9e..e73629e 100644 --- a/src/openvic-simulation/country/CountryDefinition.cpp +++ b/src/openvic-simulation/country/CountryDefinition.cpp @@ -25,7 +25,7 @@ CountryParty::CountryParty( CountryDefinition::CountryDefinition( std::string_view new_identifier, colour_t new_colour, - size_t new_index, + index_t new_index, GraphicalCultureType const& new_graphical_culture, IdentifierRegistry&& new_parties, unit_names_map_t&& new_unit_names, @@ -35,7 +35,7 @@ CountryDefinition::CountryDefinition( colour_t new_secondary_unit_colour, colour_t new_tertiary_unit_colour ) : HasIdentifierAndColour { new_identifier, new_colour, false }, - index { new_index }, + HasIndex { new_index }, graphical_culture { new_graphical_culture }, parties { std::move(new_parties) }, unit_names { std::move(new_unit_names) }, diff --git a/src/openvic-simulation/country/CountryDefinition.hpp b/src/openvic-simulation/country/CountryDefinition.hpp index 70e62b9..f04796a 100644 --- a/src/openvic-simulation/country/CountryDefinition.hpp +++ b/src/openvic-simulation/country/CountryDefinition.hpp @@ -41,14 +41,13 @@ namespace OpenVic { }; /* Generic information about a TAG */ - struct CountryDefinition : HasIdentifierAndColour { + struct CountryDefinition : HasIdentifierAndColour, HasIndex<> { friend struct CountryDefinitionManager; using unit_names_map_t = ordered_map; using government_colour_map_t = ordered_map; private: - const size_t PROPERTY(index); GraphicalCultureType const& PROPERTY(graphical_culture); /* Not const to allow elements to be moved, otherwise a copy is forced * which causes a compile error as the copy constructor has been deleted. */ @@ -62,7 +61,7 @@ namespace OpenVic { // Unit colours not const due to being added after construction CountryDefinition( - std::string_view new_identifier, colour_t new_colour, size_t new_index, + std::string_view new_identifier, colour_t new_colour, index_t new_index, GraphicalCultureType const& new_graphical_culture, IdentifierRegistry&& new_parties, unit_names_map_t&& new_unit_names, bool new_dynamic_tag, government_colour_map_t&& new_alternative_colours, colour_t new_primary_unit_colour, colour_t new_secondary_unit_colour, colour_t new_tertiary_unit_colour diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index a4086a7..3e21bab 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -2,15 +2,29 @@ #include "openvic-simulation/country/CountryDefinition.hpp" #include "openvic-simulation/history/CountryHistory.hpp" -#include "openvic-simulation/military/Deployment.hpp" #include "openvic-simulation/military/UnitInstanceGroup.hpp" using namespace OpenVic; -CountryInstance::CountryInstance(CountryDefinition const* new_country_definition) - : country_definition { new_country_definition }, primary_culture { nullptr }, religion { nullptr }, ruling_party { nullptr }, - last_election {}, capital { nullptr }, government_type { nullptr }, plurality { 0 }, national_value { nullptr }, - civilised { false }, prestige { 0 } {} +CountryInstance::CountryInstance( + CountryDefinition const* new_country_definition, + decltype(technologies)::keys_t const& technology_keys, + decltype(inventions)::keys_t const& invention_keys, + decltype(upper_house)::keys_t const& ideology_keys +) : country_definition { new_country_definition }, + primary_culture { nullptr }, + religion { nullptr }, + ruling_party { nullptr }, + last_election {}, + capital { nullptr }, + government_type { nullptr }, + plurality { 0 }, + national_value { nullptr }, + civilised { false }, + prestige { 0 }, + upper_house { &ideology_keys }, + technologies { &technology_keys }, + inventions { &invention_keys } {} std::string_view CountryInstance::get_identifier() const { return country_definition != nullptr ? country_definition->get_identifier() : "NULL"; @@ -41,19 +55,20 @@ bool CountryInstance::remove_accepted_culture(Culture const* culture_to_remove) return true; } -void CountryInstance::add_to_upper_house(Ideology const* party, fixed_point_t popularity) { - upper_house[party] = popularity; -} - -bool CountryInstance::remove_from_upper_house(Ideology const* party) { - return upper_house.erase(party) == 1; +bool CountryInstance::set_upper_house(Ideology const* ideology, fixed_point_t popularity) { + if (ideology != nullptr) { + upper_house[*ideology] = popularity; + return true; + } else { + Logger::error("Trying to set null ideology in upper house of ", get_identifier()); + return false; + } } bool CountryInstance::add_reform(Reform const* new_reform) { if (std::find(reforms.begin(), reforms.end(), new_reform) != reforms.end()) { Logger::warning( - "Attempted to add reform ", new_reform->get_identifier(), " to country ", country_definition->get_identifier(), - ": already present!" + "Attempted to add reform \"", new_reform, "\" to country ", get_identifier(), ": already present!" ); return false; } @@ -65,8 +80,7 @@ bool CountryInstance::remove_reform(Reform const* reform_to_remove) { auto existing_entry = std::find(reforms.begin(), reforms.end(), reform_to_remove); if (existing_entry == reforms.end()) { Logger::warning( - "Attempted to remove reform ", reform_to_remove->get_identifier(), " from country ", - country_definition->get_identifier(), ": not present!" + "Attempted to remove reform \"", reform_to_remove, "\" from country ", get_identifier(), ": not present!" ); return false; } @@ -178,9 +192,7 @@ bool CountryInstance::apply_history_to_country(CountryHistoryEntry const* entry) set_optional(religion, entry->get_religion()); set_optional(ruling_party, entry->get_ruling_party()); set_optional(last_election, entry->get_last_election()); - for (auto const& [ideology, popularity] : entry->get_upper_house()) { - add_to_upper_house(ideology, popularity); - } + ret &= upper_house.copy(entry->get_upper_house()); set_optional(capital, entry->get_capital()); set_optional(government_type, entry->get_government_type()); set_optional(plurality, entry->get_plurality()); @@ -194,11 +206,16 @@ bool CountryInstance::apply_history_to_country(CountryHistoryEntry const* entry) return ret; } -bool CountryInstanceManager::generate_country_instances(CountryDefinitionManager const& country_definition_manager) { +bool CountryInstanceManager::generate_country_instances( + CountryDefinitionManager const& country_definition_manager, + decltype(CountryInstance::technologies)::keys_t const& technology_keys, + decltype(CountryInstance::inventions)::keys_t const& invention_keys, + decltype(CountryInstance::upper_house)::keys_t const& ideology_keys +) { reserve_more(country_instances, country_definition_manager.get_country_definition_count()); for (CountryDefinition const& country_definition : country_definition_manager.get_country_definitions()) { - country_instances.add_item({ &country_definition }); + country_instances.add_item({ &country_definition, technology_keys, invention_keys, ideology_keys }); } return true; diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp index 3022b6a..885a5fd 100644 --- a/src/openvic-simulation/country/CountryInstance.hpp +++ b/src/openvic-simulation/country/CountryInstance.hpp @@ -6,9 +6,11 @@ #include "openvic-simulation/military/Leader.hpp" #include "openvic-simulation/military/UnitInstanceGroup.hpp" +#include "openvic-simulation/research/Invention.hpp" +#include "openvic-simulation/research/Technology.hpp" #include "openvic-simulation/types/Date.hpp" -#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" +#include "openvic-simulation/types/IndexedMap.hpp" #include "openvic-simulation/utility/Getters.hpp" namespace OpenVic { @@ -34,7 +36,7 @@ namespace OpenVic { Religion const* PROPERTY_RW(religion); CountryParty const* PROPERTY_RW(ruling_party); Date PROPERTY_RW(last_election); - fixed_point_map_t PROPERTY(upper_house); + IndexedMap PROPERTY(upper_house); // TODO - should this be ProvinceInstance and/or non-const pointer? // Currently ProvinceDefinition as that's what CountryHistoryEntry has (loaded prior to ProvinceInstance generation) ProvinceDefinition const* PROPERTY_RW(capital); @@ -44,21 +46,27 @@ namespace OpenVic { bool PROPERTY_RW(civilised); fixed_point_t PROPERTY_RW(prestige); std::vector PROPERTY(reforms); // TODO: should be map of reform groups to active reforms: must set defaults & validate applied history + + IndexedMap PROPERTY(technologies); + IndexedMap PROPERTY(inventions); + // TODO: Military units + OOBs; will probably need an extensible deployment class plf::colony PROPERTY(generals); plf::colony PROPERTY(admirals); - CountryInstance(CountryDefinition const* new_country_definition); + CountryInstance( + CountryDefinition const* new_country_definition, decltype(technologies)::keys_t const& technology_keys, + decltype(inventions)::keys_t const& invention_keys, decltype(upper_house)::keys_t const& ideology_keys + ); public: std::string_view get_identifier() const; bool add_accepted_culture(Culture const* new_accepted_culture); bool remove_accepted_culture(Culture const* culture_to_remove); - /* Add or modify a party in the upper house. */ - void add_to_upper_house(Ideology const* party, fixed_point_t popularity); - bool remove_from_upper_house(Ideology const* party); + /* Set a party's popularity in the upper house. */ + bool set_upper_house(Ideology const* ideology, fixed_point_t popularity); bool add_reform(Reform const* new_reform); bool remove_reform(Reform const* reform_to_remove); @@ -83,7 +91,12 @@ namespace OpenVic { IdentifierRegistry IDENTIFIER_REGISTRY(country_instance); public: - bool generate_country_instances(CountryDefinitionManager const& country_definition_manager); + bool generate_country_instances( + CountryDefinitionManager const& country_definition_manager, + decltype(CountryInstance::technologies)::keys_t const& technology_keys, + decltype(CountryInstance::inventions)::keys_t const& invention_keys, + decltype(CountryInstance::upper_house)::keys_t const& ideology_keys + ); bool apply_history_to_countries( CountryHistoryManager const& history_manager, Date date, UnitInstanceManager& unit_instance_manager, diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index f42a518..4fbd86b 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -538,7 +538,10 @@ bool Dataloader::_load_history(DefinitionManager& definition_manager, bool unuse } return country_history_manager.load_country_history_file( - definition_manager, *this, *country, parse_defines(file).get_file_node() + definition_manager, *this, *country, + definition_manager.get_politics_manager().get_ideology_manager().get_ideologies(), + definition_manager.get_politics_manager().get_government_type_manager().get_government_types(), + parse_defines(file).get_file_node() ); } ); diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp index b0bb723..e53e896 100644 --- a/src/openvic-simulation/dataloader/NodeTools.hpp +++ b/src/openvic-simulation/dataloader/NodeTools.hpp @@ -12,6 +12,7 @@ #include "openvic-simulation/types/Colour.hpp" #include "openvic-simulation/types/Date.hpp" #include "openvic-simulation/types/HasIdentifier.hpp" +#include "openvic-simulation/types/IndexedMap.hpp" #include "openvic-simulation/types/OrderedContainers.hpp" #include "openvic-simulation/types/Vector.hpp" #include "openvic-simulation/utility/Getters.hpp" @@ -537,6 +538,26 @@ namespace OpenVic { }; } + template + Callback auto map_callback( + IndexedMap& map, Key const* key, bool warn = false + ) { + return [&map, key, warn](Value value) -> bool { + if (key == nullptr) { + Logger::error("Null key in map_callback"); + return false; + } + Value& map_value = map[*key]; + bool ret = true; + if (map_value != Value {}) { + Logger::warn_or_error(warn, "Duplicate map entry with key: \"", key, "\""); + ret = warn; + } + map_value = std::move(value); + return ret; + }; + } + /* Often used for rotations which must be negated due to OpenVic's coordinate system being orientated * oppositely to Vic2's. */ template diff --git a/src/openvic-simulation/economy/GoodDefinition.cpp b/src/openvic-simulation/economy/GoodDefinition.cpp index 5a3d632..104764b 100644 --- a/src/openvic-simulation/economy/GoodDefinition.cpp +++ b/src/openvic-simulation/economy/GoodDefinition.cpp @@ -10,7 +10,7 @@ GoodCategory::GoodCategory(std::string_view new_identifier) : HasIdentifier { ne GoodDefinition::GoodDefinition( std::string_view new_identifier, colour_t new_colour, index_t new_index, GoodCategory const& new_category, price_t new_base_price, bool new_available_from_start, bool new_tradeable, bool new_money, bool new_overseas_penalty -) : HasIdentifierAndColour { new_identifier, new_colour, false }, index { new_index }, category { new_category }, +) : HasIdentifierAndColour { new_identifier, new_colour, false }, HasIndex { new_index }, category { new_category }, base_price { new_base_price }, available_from_start { new_available_from_start }, tradeable { new_tradeable }, money { new_money }, overseas_penalty { new_overseas_penalty } { assert(base_price > NULL_PRICE); diff --git a/src/openvic-simulation/economy/GoodDefinition.hpp b/src/openvic-simulation/economy/GoodDefinition.hpp index 0a3ad5c..3050243 100644 --- a/src/openvic-simulation/economy/GoodDefinition.hpp +++ b/src/openvic-simulation/economy/GoodDefinition.hpp @@ -28,18 +28,15 @@ namespace OpenVic { * ECON-238, ECON-239, ECON-240, ECON-241, ECON-242, ECON-243, ECON-244, ECON-245, ECON-246, ECON-247, ECON-248, ECON-249, * ECON-250, ECON-251, ECON-252, ECON-253, ECON-254, ECON-255, ECON-256, ECON-257, ECON-258, ECON-259, ECON-260, ECON-261 */ - struct GoodDefinition : HasIdentifierAndColour { + struct GoodDefinition : HasIdentifierAndColour, HasIndex<> { friend struct GoodDefinitionManager; - using index_t = size_t; - using price_t = fixed_point_t; static constexpr price_t NULL_PRICE = fixed_point_t::_0(); using good_definition_map_t = fixed_point_map_t; private: - const index_t PROPERTY(index); GoodCategory const& PROPERTY(category); const price_t PROPERTY(base_price); const bool PROPERTY_CUSTOM_PREFIX(available_from_start, is); diff --git a/src/openvic-simulation/history/CountryHistory.cpp b/src/openvic-simulation/history/CountryHistory.cpp index 5eba9ee..935a769 100644 --- a/src/openvic-simulation/history/CountryHistory.cpp +++ b/src/openvic-simulation/history/CountryHistory.cpp @@ -6,13 +6,21 @@ using namespace OpenVic; using namespace OpenVic::NodeTools; -CountryHistoryEntry::CountryHistoryEntry(CountryDefinition const& new_country, Date new_date) - : HistoryEntry { new_date }, country { new_country } {} +CountryHistoryEntry::CountryHistoryEntry( + CountryDefinition const& new_country, Date new_date, decltype(upper_house)::keys_t const& ideology_keys, + decltype(government_flag_overrides)::keys_t const& government_type_keys +) : HistoryEntry { new_date }, country { new_country }, upper_house { &ideology_keys }, + government_flag_overrides { &government_type_keys } {} -CountryHistoryMap::CountryHistoryMap(CountryDefinition const& new_country) : country { new_country } {} +CountryHistoryMap::CountryHistoryMap( + CountryDefinition const& new_country, decltype(ideology_keys) new_ideology_keys, + decltype(government_type_keys) new_government_type_keys +) : country { new_country }, ideology_keys { new_ideology_keys }, government_type_keys { new_government_type_keys } {} std::unique_ptr CountryHistoryMap::_make_entry(Date date) const { - return std::unique_ptr { new CountryHistoryEntry { country, date } }; + return std::unique_ptr { + new CountryHistoryEntry { country, date, ideology_keys, government_type_keys } + }; } bool CountryHistoryMap::_load_history_entry( @@ -90,8 +98,7 @@ bool CountryHistoryMap::_load_history_entry( "prestige", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(entry.prestige)), "ruling_party", ZERO_OR_ONE, country.expect_party_identifier(assign_variable_callback_pointer_opt(entry.ruling_party)), "last_election", ZERO_OR_ONE, expect_date(assign_variable_callback(entry.last_election)), - "upper_house", ZERO_OR_ONE, politics_manager.get_ideology_manager().expect_ideology_dictionary_reserve_length( - entry.upper_house, + "upper_house", ZERO_OR_ONE, politics_manager.get_ideology_manager().expect_ideology_dictionary( [&entry](Ideology const& ideology, ast::NodeCPtr value) -> bool { return expect_fixed_point(map_callback(entry.upper_house, &ideology))(value); } @@ -216,7 +223,9 @@ CountryHistoryMap const* CountryHistoryManager::get_country_history(CountryDefin } bool CountryHistoryManager::load_country_history_file( - DefinitionManager& definition_manager, Dataloader const& dataloader, CountryDefinition const& country, ast::NodeCPtr root + DefinitionManager& definition_manager, Dataloader const& dataloader, CountryDefinition const& country, + decltype(CountryHistoryMap::ideology_keys) ideology_keys, + decltype(CountryHistoryMap::government_type_keys) government_type_keys, ast::NodeCPtr root ) { if (locked) { Logger::error("Attempted to load country history file for ", country, " after country history registry was locked!"); @@ -230,7 +239,7 @@ bool CountryHistoryManager::load_country_history_file( decltype(country_histories)::iterator it = country_histories.find(&country); if (it == country_histories.end()) { const std::pair result = - country_histories.emplace(&country, CountryHistoryMap { country }); + country_histories.emplace(&country, CountryHistoryMap { country, ideology_keys, government_type_keys }); if (result.second) { it = result.first; } else { diff --git a/src/openvic-simulation/history/CountryHistory.hpp b/src/openvic-simulation/history/CountryHistory.hpp index 0de76c6..c74841d 100644 --- a/src/openvic-simulation/history/CountryHistory.hpp +++ b/src/openvic-simulation/history/CountryHistory.hpp @@ -1,11 +1,11 @@ #pragma once #include -#include #include "openvic-simulation/history/HistoryMap.hpp" #include "openvic-simulation/types/Date.hpp" #include "openvic-simulation/types/fixed_point/FixedPointMap.hpp" +#include "openvic-simulation/types/IndexedMap.hpp" #include "openvic-simulation/types/OrderedContainers.hpp" namespace OpenVic { @@ -36,7 +36,7 @@ namespace OpenVic { std::optional PROPERTY(religion); std::optional PROPERTY(ruling_party); std::optional PROPERTY(last_election); - fixed_point_map_t PROPERTY(upper_house); + IndexedMap PROPERTY(upper_house); std::optional PROPERTY(capital); std::optional PROPERTY(government_type); std::optional PROPERTY(plurality); @@ -57,10 +57,13 @@ namespace OpenVic { std::optional PROPERTY(colonial_points); string_set_t PROPERTY(country_flags); string_set_t PROPERTY(global_flags); - ordered_map PROPERTY(government_flag_overrides); + IndexedMap PROPERTY(government_flag_overrides); ordered_set PROPERTY(decisions); - CountryHistoryEntry(CountryDefinition const& new_country, Date new_date); + CountryHistoryEntry( + CountryDefinition const& new_country, Date new_date, decltype(upper_house)::keys_t const& ideology_keys, + decltype(government_flag_overrides)::keys_t const& government_type_keys + ); }; class Dataloader; @@ -72,9 +75,14 @@ namespace OpenVic { private: CountryDefinition const& PROPERTY(country); + decltype(CountryHistoryEntry::upper_house)::keys_t const& PROPERTY(ideology_keys); + decltype(CountryHistoryEntry::government_flag_overrides)::keys_t const& PROPERTY(government_type_keys); protected: - CountryHistoryMap(CountryDefinition const& new_country); + CountryHistoryMap( + CountryDefinition const& new_country, decltype(ideology_keys) new_ideology_keys, + decltype(government_type_keys) new_government_type_keys + ); std::unique_ptr _make_entry(Date date) const override; bool _load_history_entry( @@ -99,7 +107,8 @@ namespace OpenVic { bool load_country_history_file( DefinitionManager& definition_manager, Dataloader const& dataloader, CountryDefinition const& country, - ast::NodeCPtr root + decltype(CountryHistoryMap::ideology_keys) ideology_keys, + decltype(CountryHistoryMap::government_type_keys) government_type_keys, ast::NodeCPtr root ); }; diff --git a/src/openvic-simulation/map/MapInstance.cpp b/src/openvic-simulation/map/MapInstance.cpp index 1547ade..986b102 100644 --- a/src/openvic-simulation/map/MapInstance.cpp +++ b/src/openvic-simulation/map/MapInstance.cpp @@ -49,7 +49,11 @@ ProvinceDefinition::index_t MapInstance::get_selected_province_index() const { : ProvinceDefinition::NULL_INDEX; } -bool MapInstance::setup(BuildingTypeManager const& building_type_manager) { +bool MapInstance::setup( + BuildingTypeManager const& building_type_manager, + decltype(ProvinceInstance::pop_type_distribution)::keys_t const& pop_type_keys, + decltype(ProvinceInstance::ideology_distribution)::keys_t const& ideology_keys +) { if (province_instances_are_locked()) { Logger::error("Cannot setup map - province instances are locked!"); return false; @@ -64,7 +68,7 @@ bool MapInstance::setup(BuildingTypeManager const& building_type_manager) { province_instances.reserve(map_definition.get_province_definition_count()); for (ProvinceDefinition const& province : map_definition.get_province_definitions()) { - ret &= province_instances.add_item({ province }); + ret &= province_instances.add_item({ province, pop_type_keys, ideology_keys }); } province_instances.lock(); @@ -85,8 +89,7 @@ bool MapInstance::setup(BuildingTypeManager const& building_type_manager) { } bool MapInstance::apply_history_to_provinces( - ProvinceHistoryManager const& history_manager, Date date, IdeologyManager const& ideology_manager, - IssueManager const& issue_manager, CountryDefinition const& country + ProvinceHistoryManager const& history_manager, Date date, IssueManager const& issue_manager ) { bool ret = true; @@ -109,7 +112,7 @@ bool MapInstance::apply_history_to_provinces( if (pop_history_entry != nullptr) { province.add_pop_vec(pop_history_entry->get_pops()); - province.setup_pop_test_values(ideology_manager, issue_manager, country); + province.setup_pop_test_values(issue_manager); } } } diff --git a/src/openvic-simulation/map/MapInstance.hpp b/src/openvic-simulation/map/MapInstance.hpp index 2c0ff74..00bd638 100644 --- a/src/openvic-simulation/map/MapInstance.hpp +++ b/src/openvic-simulation/map/MapInstance.hpp @@ -10,9 +10,7 @@ namespace OpenVic { struct MapDefinition; struct BuildingTypeManager; struct ProvinceHistoryManager; - struct IdeologyManager; struct IssueManager; - struct CountryDefinition; /* REQUIREMENTS: * MAP-4 @@ -44,10 +42,13 @@ namespace OpenVic { ProvinceInstance* get_selected_province(); ProvinceDefinition::index_t get_selected_province_index() const; - bool setup(BuildingTypeManager const& building_type_manager); + bool setup( + BuildingTypeManager const& building_type_manager, + decltype(ProvinceInstance::pop_type_distribution)::keys_t const& pop_type_keys, + decltype(ProvinceInstance::ideology_distribution)::keys_t const& ideology_keys + ); bool apply_history_to_provinces( - ProvinceHistoryManager const& history_manager, Date date, IdeologyManager const& ideology_manager, - IssueManager const& issue_manager, CountryDefinition const& country + ProvinceHistoryManager const& history_manager, Date date, IssueManager const& issue_manager ); void update_gamestate(Date today); diff --git a/src/openvic-simulation/map/Mapmode.cpp b/src/openvic-simulation/map/Mapmode.cpp index f03b0e8..c47a07a 100644 --- a/src/openvic-simulation/map/Mapmode.cpp +++ b/src/openvic-simulation/map/Mapmode.cpp @@ -14,7 +14,7 @@ using namespace OpenVic::colour_literals; Mapmode::Mapmode( std::string_view new_identifier, index_t new_index, colour_func_t new_colour_func -) : HasIdentifier { new_identifier }, index { new_index }, colour_func { new_colour_func } { +) : HasIdentifier { new_identifier }, HasIndex { new_index }, colour_func { new_colour_func } { assert(colour_func != nullptr); } diff --git a/src/openvic-simulation/map/Mapmode.hpp b/src/openvic-simulation/map/Mapmode.hpp index d514f7a..ad0ed16 100644 --- a/src/openvic-simulation/map/Mapmode.hpp +++ b/src/openvic-simulation/map/Mapmode.hpp @@ -11,7 +11,7 @@ namespace OpenVic { struct MapInstance; struct ProvinceInstance; - struct Mapmode : HasIdentifier { + struct Mapmode : HasIdentifier, HasIndex<> { friend struct MapmodeManager; /* Bottom 32 bits are the base colour, top 32 are the stripe colour, both in ARGB format with the alpha channels @@ -24,10 +24,8 @@ namespace OpenVic { constexpr base_stripe_t(colour_argb_t both) : base_stripe_t { both, both } {} }; using colour_func_t = std::function; - using index_t = size_t; private: - const index_t PROPERTY(index); const colour_func_t colour_func; Mapmode(std::string_view new_identifier, index_t new_index, colour_func_t new_colour_func); diff --git a/src/openvic-simulation/map/ProvinceDefinition.cpp b/src/openvic-simulation/map/ProvinceDefinition.cpp index c40f8f0..4f34c1e 100644 --- a/src/openvic-simulation/map/ProvinceDefinition.cpp +++ b/src/openvic-simulation/map/ProvinceDefinition.cpp @@ -9,7 +9,7 @@ using namespace OpenVic::NodeTools; ProvinceDefinition::ProvinceDefinition( std::string_view new_identifier, colour_t new_colour, index_t new_index -) : HasIdentifierAndColour { new_identifier, new_colour, true }, index { new_index }, region { nullptr }, +) : HasIdentifierAndColour { new_identifier, new_colour, true }, HasIndex { new_index }, region { nullptr }, climate { nullptr }, continent { nullptr }, on_map { false }, water { false }, coastal { false }, port { false }, port_adjacent_province { nullptr }, default_terrain_type { nullptr }, adjacencies {}, centre {}, positions {} { @@ -22,7 +22,7 @@ bool ProvinceDefinition::operator==(ProvinceDefinition const& other) const { std::string ProvinceDefinition::to_string() const { std::stringstream stream; - stream << "(#" << std::to_string(index) << ", " << get_identifier() << ", 0x" << get_colour() << ")"; + stream << "(#" << std::to_string(get_index()) << ", " << get_identifier() << ", 0x" << get_colour() << ")"; return stream.str(); } diff --git a/src/openvic-simulation/map/ProvinceDefinition.hpp b/src/openvic-simulation/map/ProvinceDefinition.hpp index c66323c..c79af17 100644 --- a/src/openvic-simulation/map/ProvinceDefinition.hpp +++ b/src/openvic-simulation/map/ProvinceDefinition.hpp @@ -24,10 +24,9 @@ namespace OpenVic { * MAP-5, MAP-7, MAP-8, MAP-43, MAP-47 * POP-22 */ - struct ProvinceDefinition : HasIdentifierAndColour { + struct ProvinceDefinition : HasIdentifierAndColour, HasIndex { friend struct MapDefinition; - using index_t = uint16_t; using distance_t = fixed_point_t; // should this go inside adjacency_t? struct adjacency_t { @@ -84,7 +83,6 @@ namespace OpenVic { private: /* Immutable attributes (unchanged after initial game load) */ - const index_t PROPERTY(index); Region const* PROPERTY(region); Climate const* PROPERTY(climate); Continent const* PROPERTY(continent); diff --git a/src/openvic-simulation/map/ProvinceInstance.cpp b/src/openvic-simulation/map/ProvinceInstance.cpp index 8bb5345..1792fe0 100644 --- a/src/openvic-simulation/map/ProvinceInstance.cpp +++ b/src/openvic-simulation/map/ProvinceInstance.cpp @@ -7,8 +7,10 @@ using namespace OpenVic; -ProvinceInstance::ProvinceInstance(ProvinceDefinition const& new_province_definition) - : HasIdentifierAndColour { new_province_definition }, +ProvinceInstance::ProvinceInstance( + ProvinceDefinition const& new_province_definition, decltype(pop_type_distribution)::keys_t const& pop_type_keys, + decltype(ideology_distribution)::keys_t const& ideology_keys +) : HasIdentifierAndColour { new_province_definition }, province_definition { new_province_definition }, terrain_type { new_province_definition.get_default_terrain_type() }, life_rating { 0 }, @@ -25,8 +27,8 @@ ProvinceInstance::ProvinceInstance(ProvinceDefinition const& new_province_defini navies {}, pops {}, total_population { 0 }, - pop_type_distribution {}, - ideology_distribution {}, + pop_type_distribution { &pop_type_keys }, + ideology_distribution { &ideology_keys }, culture_distribution {}, religion_distribution {} {} @@ -58,7 +60,7 @@ bool ProvinceInstance::add_pop_vec(std::vector const& pop_vec) { if (!province_definition.is_water()) { reserve_more(pops, pop_vec.size()); for (PopBase const& pop : pop_vec) { - _add_pop(Pop { pop }); + _add_pop(Pop { pop, *ideology_distribution.get_keys() }); } return true; } else { @@ -82,7 +84,7 @@ void ProvinceInstance::_update_pops() { religion_distribution.clear(); for (Pop const& pop : pops) { total_population += pop.get_size(); - pop_type_distribution[&pop.get_type()] += pop.get_size(); + pop_type_distribution[pop.get_type()] += pop.get_size(); ideology_distribution += pop.get_ideologies(); culture_distribution[&pop.get_culture()] += pop.get_size(); religion_distribution[&pop.get_religion()] += pop.get_size(); @@ -214,10 +216,8 @@ bool ProvinceInstance::apply_history_to_province(ProvinceHistoryEntry const* ent return ret; } -void ProvinceInstance::setup_pop_test_values( - IdeologyManager const& ideology_manager, IssueManager const& issue_manager, CountryDefinition const& country -) { +void ProvinceInstance::setup_pop_test_values(IssueManager const& issue_manager) { for (Pop& pop : pops) { - pop.setup_pop_test_values(ideology_manager, issue_manager, country); + pop.setup_pop_test_values(issue_manager); } } diff --git a/src/openvic-simulation/map/ProvinceInstance.hpp b/src/openvic-simulation/map/ProvinceInstance.hpp index a4f9e98..4398cd4 100644 --- a/src/openvic-simulation/map/ProvinceInstance.hpp +++ b/src/openvic-simulation/map/ProvinceInstance.hpp @@ -21,7 +21,6 @@ namespace OpenVic { struct Religion; struct BuildingTypeManager; struct ProvinceHistoryEntry; - struct IdeologyManager; struct IssueManager; template @@ -61,12 +60,15 @@ namespace OpenVic { std::vector PROPERTY(pops); Pop::pop_size_t PROPERTY(total_population); - fixed_point_map_t PROPERTY(pop_type_distribution); - fixed_point_map_t PROPERTY(ideology_distribution); + IndexedMap PROPERTY(pop_type_distribution); + IndexedMap PROPERTY(ideology_distribution); fixed_point_map_t PROPERTY(culture_distribution); fixed_point_map_t PROPERTY(religion_distribution); - ProvinceInstance(ProvinceDefinition const& new_province_definition); + ProvinceInstance( + ProvinceDefinition const& new_province_definition, decltype(pop_type_distribution)::keys_t const& pop_type_keys, + decltype(ideology_distribution)::keys_t const& ideology_keys + ); void _add_pop(Pop&& pop); void _update_pops(); @@ -116,8 +118,6 @@ namespace OpenVic { bool setup(BuildingTypeManager const& building_type_manager); bool apply_history_to_province(ProvinceHistoryEntry const* entry); - void setup_pop_test_values( - IdeologyManager const& ideology_manager, IssueManager const& issue_manager, CountryDefinition const& country - ); + void setup_pop_test_values(IssueManager const& issue_manager); }; } diff --git a/src/openvic-simulation/politics/NationalFocus.cpp b/src/openvic-simulation/politics/NationalFocus.cpp index 85fcdc0..818021e 100644 --- a/src/openvic-simulation/politics/NationalFocus.cpp +++ b/src/openvic-simulation/politics/NationalFocus.cpp @@ -1,5 +1,7 @@ #include "NationalFocus.hpp" +#include "openvic-simulation/politics/Ideology.hpp" + using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -16,13 +18,12 @@ NationalFocus::NationalFocus( Ideology const* new_loyalty_ideology, fixed_point_t new_loyalty_value, ConditionScript&& new_limit -) : HasIdentifier { new_identifier }, +) : Modifier { new_identifier, std::move(new_modifiers), 0 }, group { new_group }, icon { new_icon }, has_flashpoint { new_has_flashpoint }, own_provinces { new_own_provinces }, outliner_show_as_percent { new_outliner_show_as_percent }, - modifiers { std::move(new_modifiers) }, loyalty_ideology { new_loyalty_ideology }, loyalty_value { new_loyalty_value }, limit { std::move(new_limit) } {} diff --git a/src/openvic-simulation/politics/NationalFocus.hpp b/src/openvic-simulation/politics/NationalFocus.hpp index f27af43..04a4100 100644 --- a/src/openvic-simulation/politics/NationalFocus.hpp +++ b/src/openvic-simulation/politics/NationalFocus.hpp @@ -1,9 +1,6 @@ #pragma once -#include "openvic-simulation/economy/GoodDefinition.hpp" #include "openvic-simulation/misc/Modifier.hpp" -#include "openvic-simulation/politics/Ideology.hpp" -#include "openvic-simulation/pop/Pop.hpp" #include "openvic-simulation/scripts/ConditionScript.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/utility/Getters.hpp" @@ -18,7 +15,9 @@ namespace OpenVic { NationalFocusGroup(std::string_view new_identifier); }; - struct NationalFocus : HasIdentifier { + struct Ideology; + + struct NationalFocus : Modifier { friend struct NationalFocusManager; private: @@ -27,7 +26,6 @@ namespace OpenVic { bool PROPERTY(has_flashpoint); bool PROPERTY(own_provinces); bool PROPERTY(outliner_show_as_percent); - ModifierValue PROPERTY(modifiers); Ideology const* PROPERTY(loyalty_ideology); fixed_point_t PROPERTY(loyalty_value); ConditionScript PROPERTY(limit); @@ -51,6 +49,10 @@ namespace OpenVic { NationalFocus(NationalFocus&&) = default; }; + struct PopManager; + struct IdeologyManager; + struct GoodDefinitionManager; + struct NationalFocusManager { private: IdentifierRegistry IDENTIFIER_REGISTRY(national_focus_group); diff --git a/src/openvic-simulation/pop/Pop.cpp b/src/openvic-simulation/pop/Pop.cpp index 8f4c445..0ecd937 100644 --- a/src/openvic-simulation/pop/Pop.cpp +++ b/src/openvic-simulation/pop/Pop.cpp @@ -19,7 +19,7 @@ PopBase::PopBase( ) : type { new_type }, culture { new_culture }, religion { new_religion }, size { new_size }, militancy { new_militancy }, consciousness { new_consciousness }, rebel_type { new_rebel_type } {} -Pop::Pop(PopBase const& pop_base) +Pop::Pop(PopBase const& pop_base, decltype(ideologies)::keys_t const& ideology_keys) : PopBase { pop_base }, location { nullptr }, total_change { 0 }, @@ -29,9 +29,9 @@ Pop::Pop(PopBase const& pop_base) num_migrated_internal { 0 }, num_migrated_external { 0 }, num_migrated_colonial { 0 }, - ideologies {}, + ideologies { &ideology_keys }, issues {}, - votes {}, + votes { nullptr }, unemployment { 0 }, cash { 0 }, income { 0 }, @@ -43,9 +43,7 @@ Pop::Pop(PopBase const& pop_base) assert(size > 0); } -void Pop::setup_pop_test_values( - IdeologyManager const& ideology_manager, IssueManager const& issue_manager, CountryDefinition const& country -) { +void Pop::setup_pop_test_values(IssueManager const& issue_manager) { /* Returns +/- range% of size. */ const auto test_size = [this](int32_t range) -> pop_size_t { return size * ((rand() % (2 * range + 1)) - range) / 100; @@ -63,21 +61,23 @@ void Pop::setup_pop_test_values( /* Generates a number between 0 and max (inclusive) and sets map[&key] to it if it's at least min. */ auto test_weight = - [] U>( - fixed_point_map_t& map, U const& key, int32_t min, int32_t max - ) -> void { + [](T& map, U const& key, int32_t min, int32_t max) -> void { const int32_t value = rand() % (max + 1); if (value >= min) { - map.emplace(&key, value); + if constexpr (utility::is_specialization_of_v) { + map[key] = value; + } else { + map.emplace(&key, value); + } } }; /* All entries equally weighted for testing. */ ideologies.clear(); - for (Ideology const& ideology : ideology_manager.get_ideologies()) { + for (Ideology const& ideology : *ideologies.get_keys()) { test_weight(ideologies, ideology, 1, 5); } - normalise_fixed_point_map(ideologies); + ideologies.normalise(); issues.clear(); for (Issue const& issue : issue_manager.get_issues()) { @@ -90,11 +90,13 @@ void Pop::setup_pop_test_values( } normalise_fixed_point_map(issues); - votes.clear(); - for (CountryParty const& party : country.get_parties()) { - test_weight(votes, party, 4, 10); + if (votes.has_keys()) { + votes.clear(); + for (CountryParty const& party : *votes.get_keys()) { + test_weight(votes, party, 4, 10); + } + votes.normalise(); } - normalise_fixed_point_map(votes); /* Returns a fixed point between 0 and max. */ const auto test_range = [](fixed_point_t max = 1) -> fixed_point_t { @@ -116,6 +118,9 @@ void Pop::set_location(ProvinceInstance const& new_location) { location = &new_location; // TODO - update location dependent attributes + + votes.set_keys(location->get_owner() != nullptr ? &location->get_owner()->get_parties() : nullptr); + // TODO - calculate vote distribution } } diff --git a/src/openvic-simulation/pop/Pop.hpp b/src/openvic-simulation/pop/Pop.hpp index 8ac6d4c..c74840f 100644 --- a/src/openvic-simulation/pop/Pop.hpp +++ b/src/openvic-simulation/pop/Pop.hpp @@ -10,6 +10,7 @@ #include "openvic-simulation/scripts/ConditionalWeight.hpp" #include "openvic-simulation/types/EnumBitfield.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" +#include "openvic-simulation/types/IndexedMap.hpp" namespace OpenVic { @@ -68,9 +69,9 @@ namespace OpenVic { fixed_point_t PROPERTY(literacy); - fixed_point_map_t PROPERTY(ideologies); + IndexedMap PROPERTY(ideologies); fixed_point_map_t PROPERTY(issues); - fixed_point_map_t PROPERTY(votes); + IndexedMap PROPERTY(votes); fixed_point_t PROPERTY(unemployment); fixed_point_t PROPERTY(cash); @@ -81,7 +82,7 @@ namespace OpenVic { fixed_point_t PROPERTY(everyday_needs_fulfilled); fixed_point_t PROPERTY(luxury_needs_fulfilled); - Pop(PopBase const& pop_base); + Pop(PopBase const& pop_base, decltype(ideologies)::keys_t const& ideology_keys); public: Pop(Pop const&) = delete; @@ -89,9 +90,7 @@ namespace OpenVic { Pop& operator=(Pop const&) = delete; Pop& operator=(Pop&&) = delete; - void setup_pop_test_values( - IdeologyManager const& ideology_manager, IssueManager const& issue_manager, CountryDefinition const& country - ); + void setup_pop_test_values(IssueManager const& issue_manager); void set_location(ProvinceInstance const& new_location); }; diff --git a/src/openvic-simulation/types/HasIdentifier.hpp b/src/openvic-simulation/types/HasIdentifier.hpp index 3f2d8a8..941eae9 100644 --- a/src/openvic-simulation/types/HasIdentifier.hpp +++ b/src/openvic-simulation/types/HasIdentifier.hpp @@ -85,4 +85,22 @@ namespace OpenVic { using HasIdentifierAndColour = _HasIdentifierAndColour; using HasIdentifierAndAlphaColour = _HasIdentifierAndColour; + + template + class HasIndex { + public: + using index_t = T; + + private: + const index_t PROPERTY(index); + + protected: + HasIndex(index_t new_index) : index { new_index } {} + HasIndex(HasIndex const&) = default; + + public: + HasIndex(HasIndex&&) = default; + HasIndex& operator=(HasIndex const&) = delete; + HasIndex& operator=(HasIndex&&) = delete; + }; } diff --git a/src/openvic-simulation/types/IndexedMap.hpp b/src/openvic-simulation/types/IndexedMap.hpp new file mode 100644 index 0000000..68effb9 --- /dev/null +++ b/src/openvic-simulation/types/IndexedMap.hpp @@ -0,0 +1,220 @@ +#pragma once + +#include +#include + +#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp" +#include "openvic-simulation/utility/Getters.hpp" +#include "openvic-simulation/utility/Logger.hpp" + +namespace OpenVic { + + template + struct IndexedMap : private std::vector { + using container_t = std::vector; + using key_t = Key; + using value_t = Value; + using keys_t = std::vector; + + using container_t::operator[]; + using container_t::size; + using container_t::begin; + using container_t::end; + + private: + keys_t const* PROPERTY(keys); + + public: + constexpr IndexedMap(keys_t const* new_keys) : keys { nullptr } { + set_keys(new_keys); + } + + IndexedMap(IndexedMap const&) = default; + IndexedMap(IndexedMap&&) = default; + IndexedMap& operator=(IndexedMap const&) = default; + IndexedMap& operator=(IndexedMap&&) = default; + + constexpr void fill(value_t const& value) { + std::fill(container_t::begin(), container_t::end(), value); + } + + constexpr void clear() { + fill({}); + } + + constexpr bool has_keys() const { + return keys != nullptr; + } + + constexpr void set_keys(keys_t const* new_keys) { + if (keys != new_keys) { + keys = new_keys; + + container_t::resize(keys != nullptr ? keys->size() : 0); + clear(); + } + } + + constexpr size_t get_index_from_item(key_t const& key) const { + if (has_keys() && keys->data() <= &key && &key <= &keys->back()) { + return std::distance(keys->data(), &key); + } else { + return 0; + } + } + + constexpr value_t* get_item_by_key(key_t const& key) { + const size_t index = get_index_from_item(key); + if (index < container_t::size()) { + return &container_t::operator[](index); + } + return nullptr; + } + + constexpr value_t const* get_item_by_key(key_t const& key) const { + const size_t index = get_index_from_item(key); + if (index < container_t::size()) { + return &container_t::operator[](index); + } + return nullptr; + } + + constexpr key_t const& operator()(size_t index) const { + return (*keys)[index]; + } + + constexpr key_t const* get_key_by_index(size_t index) const { + if (keys != nullptr && index < keys->size()) { + return &(*this)(index); + } else { + return nullptr; + } + } + + constexpr value_t& operator[](key_t const& key) { + return container_t::operator[](get_index_from_item(key)); + } + + constexpr value_t const& operator[](key_t const& key) const { + return container_t::operator[](get_index_from_item(key)); + } + + constexpr IndexedMap& operator+=(IndexedMap const& other) { + const size_t count = std::min(container_t::size(), other.size()); + for (size_t index = 0; index < count; ++index) { + container_t::operator[](index) += other[index]; + } + return *this; + } + + constexpr IndexedMap& operator*=(value_t factor) { + for (value_t& value : *this) { + value *= factor; + } + return *this; + } + + constexpr IndexedMap& operator/=(value_t divisor) { + for (value_t& value : *this) { + value /= divisor; + } + return *this; + } + + constexpr IndexedMap operator+(IndexedMap const& other) const { + IndexedMap ret = *this; + ret += other; + return ret; + } + + constexpr IndexedMap operator*(value_t factor) const { + IndexedMap ret = *this; + ret *= factor; + return ret; + } + + constexpr IndexedMap operator/(value_t divisor) const { + IndexedMap ret = *this; + ret /= divisor; + return ret; + } + + constexpr value_t get_total() const { + value_t total {}; + for (value_t const& value : *this) { + total += value; + } + return total; + } + + constexpr IndexedMap& normalise() { + const value_t total = get_total(); + if (total > 0) { + *this /= total; + } + return *this; + } + + constexpr bool copy(IndexedMap const& other) { + if (keys != other.keys) { + Logger::error( + "Trying to copy IndexedMaps with different keys with sizes: from ", other.size(), " to ", + container_t::size() + ); + return false; + } + static_cast(*this) = other; + return true; + } + + fixed_point_map_t to_fixed_point_map() const + requires(std::same_as) + { + fixed_point_map_t result; + + for (size_t index = 0; index < container_t::size(); index++) { + fixed_point_t const& value = container_t::operator[](index); + if (value != 0) { + result[&(*this)(index)] = value; + } + } + + return result; + } + }; + + template IMKey> + constexpr fixed_point_map_t& operator+=( + fixed_point_map_t& lhs, IndexedMap const& rhs + ) { + for (size_t index = 0; index < rhs.size(); index++) { + fixed_point_t const& value = rhs[index]; + if (value != 0) { + lhs[&rhs(index)] += value; + } + } + return lhs; + } + + /* Result is determined by comparing the first pair of unequal values, + * iterating from the highest index downward. */ + template + constexpr bool sorted_indexed_map_less_than( + IndexedMap const& lhs, IndexedMap const& rhs + ) { + if (lhs.get_keys() != rhs.get_keys() || lhs.size() != rhs.size()) { + Logger::error("Trying to compare IndexedMaps with different keys/sizes: ", lhs.size(), " vs ", rhs.size()); + return false; + } + + for (size_t index = lhs.size(); index > 0;) { + index--; + const std::strong_ordering value_cmp = lhs[index] <=> rhs[index]; + if (value_cmp != std::strong_ordering::equal) { + return value_cmp == std::strong_ordering::less; + } + } + + return false; + } +} -- cgit v1.2.3-56-ga3b1