diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index 037abfb37..cdbdf3729 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -2458,7 +2458,7 @@ void CountryInstance::report_output(ProductionType const& production_type, const } void CountryInstance::request_salaries_and_welfare_and_import_subsidies(Pop& pop) { - PopType const& pop_type = *pop.get_type(); + PopType const& pop_type = pop.get_type(); const pop_size_t pop_size = pop.get_size(); SharedPopTypeValues const& pop_type_values = shared_country_values.get_shared_pop_type_values(pop_type); diff --git a/src/openvic-simulation/economy/production/ArtisanalProducer.cpp b/src/openvic-simulation/economy/production/ArtisanalProducer.cpp index 000881147..fef8535e2 100644 --- a/src/openvic-simulation/economy/production/ArtisanalProducer.cpp +++ b/src/openvic-simulation/economy/production/ArtisanalProducer.cpp @@ -294,7 +294,7 @@ void ArtisanalProducer::artisan_tick( memory::vector& reusable_map_1, fixed_point_map_t& goods_to_sell ) { - CountryInstance* const country_to_report_economy_nullable = pop.get_location()->get_country_to_report_economy(); + CountryInstance* const country_to_report_economy_nullable = pop.get_location().get_country_to_report_economy(); max_quantity_to_buy_per_good.clear(); IndexedFlatMap& wants_more_mask = reusable_goods_mask; memory::vector& max_price_per_input = reusable_map_0; diff --git a/src/openvic-simulation/economy/production/Employee.cpp b/src/openvic-simulation/economy/production/Employee.cpp index 79cc9c6da..5568563ad 100644 --- a/src/openvic-simulation/economy/production/Employee.cpp +++ b/src/openvic-simulation/economy/production/Employee.cpp @@ -11,6 +11,6 @@ Employee::Employee(Pop& new_pop, const pop_size_t new_size) {} fixed_point_t Employee::update_minimum_wage(CountryInstance& country_to_report_economy) { - const fixed_point_t minimum_wage_base = country_to_report_economy.calculate_minimum_wage_base(*pop.get_type()); + const fixed_point_t minimum_wage_base = country_to_report_economy.calculate_minimum_wage_base(pop.get_type()); return minimum_wage_cached = minimum_wage_base * size / Pop::size_denominator; } \ No newline at end of file diff --git a/src/openvic-simulation/economy/production/ResourceGatheringOperation.cpp b/src/openvic-simulation/economy/production/ResourceGatheringOperation.cpp index 19ece5d90..f2b7dd65d 100644 --- a/src/openvic-simulation/economy/production/ResourceGatheringOperation.cpp +++ b/src/openvic-simulation/economy/production/ResourceGatheringOperation.cpp @@ -203,7 +203,7 @@ void ResourceGatheringOperation::hire() { std::span jobs = production_type.get_jobs(); for (Pop& pop : location.get_mutable_pops()){ - PopType const& pop_type = *pop.get_type(); + PopType const& pop_type = pop.get_type(); for (Job const& job : jobs) { PopType const* const job_pop_type = job.pop_type; if (job_pop_type && *job_pop_type == pop_type) { @@ -424,13 +424,8 @@ void ResourceGatheringOperation::pay_employees(memory::vector& re Employee& employee = employees[i]; Pop& employee_pop = employee.get_pop(); - PopType const* employee_pop_type = employee_pop.get_type(); - if (employee_pop_type == nullptr) { - spdlog::error_s("employee has nullptr pop_type."); - return; - } - - if (employee_pop_type->is_slave) { + PopType const& employee_pop_type = employee_pop.get_type(); + if (employee_pop_type.is_slave) { continue; } diff --git a/src/openvic-simulation/map/ProvinceInstance.cpp b/src/openvic-simulation/map/ProvinceInstance.cpp index cdd58e89d..5f81baab1 100644 --- a/src/openvic-simulation/map/ProvinceInstance.cpp +++ b/src/openvic-simulation/map/ProvinceInstance.cpp @@ -181,11 +181,6 @@ bool ProvinceInstance::expand_building( return buildings[index].expand(modifier_effect_cache, actor, *this); } -void ProvinceInstance::_add_pop(Pop&& pop) { - pop.set_location(*this); - pops.insert(std::move(pop)); -} - bool ProvinceInstance::add_pop_vec( std::span pop_vec, PopDeps const& pop_deps @@ -193,12 +188,13 @@ bool ProvinceInstance::add_pop_vec( if (!province_definition.is_water()) { reserve_more(pops, pop_vec.size()); for (PopBase const& pop : pop_vec) { - _add_pop(Pop { + pops.emplace( + *this, pop, get_supporter_equivalents_by_ideology().get_keys(), pop_deps, ++last_pop_id - }); + ); } return true; } else { @@ -231,7 +227,7 @@ void ProvinceInstance::_update_pops(MilitaryDefines const& military_defines) { : is_owner_core() ? fixed_point_t::_1 : military_defines.get_pop_size_per_regiment_non_core_multiplier(); for (Pop& pop : pops) { - pops_cache_by_type.at(*pop.get_type()).push_back(&pop); + pops_cache_by_type.at(pop.get_type()).push_back(&pop); pop.update_gamestate(military_defines, owner, pop_size_per_regiment_multiplier); add_pops_aggregate(pop); if (pop.get_culture_status() == Pop::culture_status_t::UNACCEPTED) { @@ -319,11 +315,16 @@ bool ProvinceInstance::convert_rgo_worker_pops_to_equivalent(ProductionType cons std::span jobs = production_type.get_jobs(); for (Pop& pop : pops) { for (Job const& job : jobs) { - PopType const* const job_pop_type = job.pop_type; - PopType const* old_pop_type = pop.get_type(); + PopType const* const job_pop_type_ptr = job.pop_type; + if (job_pop_type_ptr == nullptr) { + continue; + } + + PopType const& job_pop_type = *job_pop_type_ptr; + PopType const& old_pop_type = pop.get_type(); if (job_pop_type != old_pop_type) { - PopType const* const equivalent = old_pop_type->get_equivalent(); - if (job_pop_type == equivalent) { + PopType const* const equivalent_ptr = old_pop_type.get_equivalent(); + if (equivalent_ptr != nullptr && job_pop_type == *equivalent_ptr) { is_valid_operation&=pop.convert_to_equivalent(); } } diff --git a/src/openvic-simulation/map/ProvinceInstance.hpp b/src/openvic-simulation/map/ProvinceInstance.hpp index 9fb949dca..8db9059e5 100644 --- a/src/openvic-simulation/map/ProvinceInstance.hpp +++ b/src/openvic-simulation/map/ProvinceInstance.hpp @@ -117,8 +117,7 @@ namespace OpenVic { private: pop_id_in_province_t last_pop_id{0}; - memory::colony PROPERTY(pops); // TODO - replace with a more easily vectorisable container? - void _add_pop(Pop&& pop); + memory::colony PROPERTY(pops); // TODO - replace with a more easily vectorisable container? void _update_pops(MilitaryDefines const& military_defines); bool convert_rgo_worker_pops_to_equivalent(ProductionType const& production_type); void initialise_rgo(); diff --git a/src/openvic-simulation/military/UnitInstanceGroup.cpp b/src/openvic-simulation/military/UnitInstanceGroup.cpp index 77497e14e..bc3b3429b 100644 --- a/src/openvic-simulation/military/UnitInstanceGroup.cpp +++ b/src/openvic-simulation/military/UnitInstanceGroup.cpp @@ -288,7 +288,7 @@ Pop* UnitInstanceManager::recruit_pop_in(ProvinceInstance& province, const bool } } else { for (auto& pop : province.get_mutable_pops()) { - if (pop.get_type()->can_be_recruited && pop.try_recruit()) { + if (pop.get_type().can_be_recruited && pop.try_recruit()) { /* Victoria 2 does not respect cultural restrictions when applying history. */ @@ -306,7 +306,7 @@ Pop* UnitInstanceManager::recruit_pop_in(ProvinceInstance& province, const bool } } else { for (auto& pop : province.get_mutable_pops()) { - if (pop.get_type()->can_be_recruited && pop.try_recruit_understrength()) { + if (pop.get_type().can_be_recruited && pop.try_recruit_understrength()) { /* Victoria 2 does not respect cultural restrictions when applying history. */ diff --git a/src/openvic-simulation/population/Pop.cpp b/src/openvic-simulation/population/Pop.cpp index 3ed9365f4..e4de5fbf4 100644 --- a/src/openvic-simulation/population/Pop.cpp +++ b/src/openvic-simulation/population/Pop.cpp @@ -7,10 +7,10 @@ #include #include +#include #include #include "openvic-simulation/core/error/ErrorMacros.hpp" -#include "openvic-simulation/core/FormatValidate.hpp" #include "openvic-simulation/core/Typedefs.hpp" #include "openvic-simulation/country/CountryParty.hpp" #include "openvic-simulation/country/CountryDefinition.hpp" @@ -49,20 +49,21 @@ using namespace OpenVic; PopBase::PopBase( PopType const& new_type, Culture const& new_culture, Religion const& new_religion, pop_size_t new_size, fixed_point_t new_militancy, fixed_point_t new_consciousness, RebelType const* new_rebel_type -) : type { &new_type }, culture { new_culture }, religion { new_religion }, size { new_size }, militancy { new_militancy }, +) : 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( + ProvinceInstance& new_location, PopBase const& pop_base, decltype(supporter_equivalents_by_ideology)::keys_span_type ideology_keys, PopDeps const& pop_deps, const pop_id_in_province_t new_id_in_province -) - : PopBase { pop_base }, +) : PopBase { pop_base }, + location { new_location }, id_in_province { new_id_in_province }, market_instance { pop_deps.market_instance }, artisanal_producer_optional { - type->is_artisan + pop_base.get_type().is_artisan ? std::optional { pop_deps.artisanal_producer_deps } @@ -73,7 +74,7 @@ Pop::Pop( } fixed_point_t Pop::get_unemployment_fraction() const { - if (!type->can_be_unemployed) { + if (!get_type().can_be_unemployed) { return 0; } return fixed_point_t::from_fraction(get_unemployed(), size); @@ -160,31 +161,21 @@ void Pop::setup_pop_test_values(IssueManager const& issue_manager) { } bool Pop::convert_to_equivalent() { - PopType const* const equivalent = get_type()->get_equivalent(); + PopType const& pop_type = type.get(); + PopType const* const equivalent = pop_type.get_equivalent(); if (equivalent == nullptr) { - spdlog::error_s("Tried to convert pop of type {} to equivalent, but there is no equivalent.", *get_type()); + spdlog::error_s("Tried to convert pop of type {} to equivalent, but there is no equivalent.", pop_type); return false; } - type = equivalent; + type = *equivalent; reserve_needs_fulfilled_goods(); return true; } -void Pop::set_location(ProvinceInstance& new_location) { - if (location != &new_location) { - location = &new_location; - - update_location_based_attributes(); - } -} - void Pop::update_location_based_attributes() { vote_equivalents_by_party.clear(); - if (location == nullptr) { - return; - } - CountryInstance const* owner = location->get_owner(); + CountryInstance const* owner = get_location().get_owner(); if (owner == nullptr) { return; } @@ -266,24 +257,24 @@ void Pop::update_gamestate( memory::string Pop::get_pop_context_text() const { return memory::fmt::format( "location: {} type: {} culture: {} religion: {} size: {}", - ovfmt::validate(location), *type, culture, religion, size + location, type, culture, religion, size ); } void Pop::reserve_needs_fulfilled_goods() { - PopType const& type_never_null = *type; + PopType const& pop_type = type.get(); #define RESERVE_NEEDS(need_category) \ - need_category##_needs_fulfilled_goods.reserve(type_never_null.get_##need_category##_needs().size()); + need_category##_needs_fulfilled_goods.reserve(pop_type.get_##need_category##_needs().size()); OV_DO_FOR_ALL_NEED_CATEGORIES(RESERVE_NEEDS) #undef RESERVE_NEEDS } void Pop::fill_needs_fulfilled_goods_with_false() { - PopType const& type_never_null = *type; + PopType const& pop_type = type.get(); #define FILL_WITH_FALSE(need_category) \ need_category##_needs_fulfilled_goods.clear(); \ - for (auto [good, base_demand] : type_never_null.get_##need_category##_needs()) { \ + for (auto [good, base_demand] : pop_type.get_##need_category##_needs()) { \ need_category##_needs_fulfilled_goods.emplace(good, false); \ } @@ -292,13 +283,13 @@ void Pop::fill_needs_fulfilled_goods_with_false() { } void Pop::pay_income_tax(fixed_point_t& income) { - CountryInstance* const tax_collector_nullable = location->get_country_to_report_economy(); + CountryInstance* const tax_collector_nullable = get_location().get_country_to_report_economy(); if (tax_collector_nullable == nullptr) { return; } - const fixed_point_t effective_tax_rate = tax_collector_nullable->get_effective_tax_rate_by_strata(type->strata).get_untracked(); + const fixed_point_t effective_tax_rate = tax_collector_nullable->get_effective_tax_rate_by_strata(get_type().strata).get_untracked(); const fixed_point_t tax = effective_tax_rate * income; - tax_collector_nullable->report_pop_income_tax(*type, income, tax); + tax_collector_nullable->report_pop_income_tax(type, income, tax); income -= tax; } @@ -532,8 +523,7 @@ void Pop::pop_tick_without_cleanup( #undef SET_TO_ZERO income = expenses = 0; - ProvinceInstance& location_never_null = *location; - CountryInstance* const country_to_report_economy_nullable = location_never_null.get_country_to_report_economy(); + CountryInstance* const country_to_report_economy_nullable = get_location().get_country_to_report_economy(); if (country_to_report_economy_nullable != nullptr) { country_to_report_economy_nullable->request_salaries_and_welfare_and_import_subsidies(*this); @@ -544,8 +534,8 @@ void Pop::pop_tick_without_cleanup( //import subsidies are based on yesterday yesterdays_import_value = 0; - PopType const& type_never_null = *type; - PopStrataValuesFromProvince const& shared_strata_values = shared_values.get_effects_by_strata(type_never_null.strata); + PopType const& pop_type = type; + PopStrataValuesFromProvince const& shared_strata_values = shared_values.get_effects_by_strata(pop_type.strata); PopsDefines const& defines = shared_values.defines; const fixed_point_t base_needs_scalar = ( fixed_point_t::_1 + 2 * consciousness / defines.get_pdef_base_con() @@ -557,7 +547,7 @@ void Pop::pop_tick_without_cleanup( fixed_point_t need_category##_needs_price_inverse_sum = 0; \ if (OV_likely(need_category##_needs_scalar > 0)) { \ need_category##_needs_acquired_quantity = need_category##_needs_desired_quantity = 0; \ - for (auto [good_definition_ptr, quantity] : type_never_null.get_##need_category##_needs()) { \ + for (auto [good_definition_ptr, quantity] : pop_type.get_##need_category##_needs()) { \ GoodDefinition const& good_definition = *good_definition_ptr; \ if (!market_instance.get_is_available(good_definition)) { \ continue; \ @@ -567,7 +557,7 @@ void Pop::pop_tick_without_cleanup( continue; \ } \ if (country_to_report_economy_nullable != nullptr) { \ - country_to_report_economy_nullable->report_pop_need_demand(*type, good_definition, max_quantity_to_buy); \ + country_to_report_economy_nullable->report_pop_need_demand(pop_type, good_definition, max_quantity_to_buy); \ } \ need_category##_needs_desired_quantity += max_quantity_to_buy; \ auto goods_to_sell_iterator = goods_to_sell.find(good_definition_ptr); \ @@ -577,7 +567,7 @@ void Pop::pop_tick_without_cleanup( max_quantity_to_buy -= own_produce_consumed; \ need_category##_needs_acquired_quantity += own_produce_consumed; \ if (country_to_report_economy_nullable != nullptr) { \ - country_to_report_economy_nullable->report_pop_need_consumption(type_never_null, good_definition, own_produce_consumed); \ + country_to_report_economy_nullable->report_pop_need_consumption(pop_type, good_definition, own_produce_consumed); \ } \ } \ if (OV_likely(max_quantity_to_buy > 0)) { \ @@ -664,8 +654,7 @@ void Pop::after_buy(void* actor, BuyResult const& buy_result) { } Pop& pop = *static_cast(actor); - ProvinceInstance& location_never_null = *pop.get_location(); - CountryInstance* const country_to_report_economy_nullable = location_never_null.get_country_to_report_economy(); + CountryInstance* const country_to_report_economy_nullable = pop.get_location().get_country_to_report_economy(); fixed_point_t money_spent = buy_result.money_spent_total; pop.yesterdays_import_value += buy_result.money_spent_on_imports; @@ -696,7 +685,7 @@ void Pop::after_buy(void* actor, BuyResult const& buy_result) { } } - CountryInstance* get_country_to_report_economy_nullable = pop.location->get_country_to_report_economy(); + CountryInstance* get_country_to_report_economy_nullable = pop.get_location().get_country_to_report_economy(); #define CONSUME_NEED(need_category) \ if (quantity_left_to_consume <= 0) { \ return; \ @@ -714,7 +703,7 @@ void Pop::after_buy(void* actor, BuyResult const& buy_result) { pop.need_category##_needs_acquired_quantity += consumed_quantity; \ quantity_left_to_consume -= consumed_quantity; \ if (get_country_to_report_economy_nullable != nullptr) { \ - get_country_to_report_economy_nullable->report_pop_need_consumption(*pop.type, good_definition, consumed_quantity); \ + get_country_to_report_economy_nullable->report_pop_need_consumption(pop.type, good_definition, consumed_quantity); \ } \ const fixed_point_t expense = fixed_point_t::mul_div( \ money_spent, \ diff --git a/src/openvic-simulation/population/Pop.hpp b/src/openvic-simulation/population/Pop.hpp index cc01ebf75..efb10130c 100644 --- a/src/openvic-simulation/population/Pop.hpp +++ b/src/openvic-simulation/population/Pop.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include "openvic-simulation/core/portable/ForwardableSpan.hpp" #include "openvic-simulation/economy/production/ArtisanalProducer.hpp" @@ -40,7 +41,7 @@ namespace OpenVic { friend PopManager; protected: - PopType const* PROPERTY_ACCESS(type, protected); + std::reference_wrapper PROPERTY_ACCESS(type, protected); pop_size_t PROPERTY_ACCESS(size, protected); fixed_point_t PROPERTY_RW_ACCESS(militancy, protected); fixed_point_t PROPERTY_RW_ACCESS(consciousness, protected); @@ -78,8 +79,6 @@ namespace OpenVic { * POP-18, POP-19, POP-20, POP-21, POP-34, POP-35, POP-36, POP-37 */ struct Pop : PopBase { - friend struct ProvinceInstance; - enum struct culture_status_t : uint8_t { UNACCEPTED, ACCEPTED, PRIMARY }; @@ -99,7 +98,14 @@ namespace OpenVic { fixed_point_t cash_allocated_for_artisanal_spending = 0; pop_size_t employed = 0; - ProvinceInstance* PROPERTY_PTR(location, nullptr); + const std::reference_wrapper PROPERTY(location); + + public: + [[nodiscard]] constexpr ProvinceInstance& get_location() { + return location; + } + + private: /* Last day's size change by source. */ pop_size_t PROPERTY(total_change, 0); @@ -164,13 +170,6 @@ namespace OpenVic { std::size_t PROPERTY(regiment_count, 0); std::size_t PROPERTY(max_supported_regiments, 0); - Pop( - PopBase const& pop_base, - decltype(supporter_equivalents_by_ideology)::keys_span_type ideology_keys, - PopDeps const& pop_deps, - const pop_id_in_province_t new_id_in_province - ); - memory::string get_pop_context_text() const; void reserve_needs_fulfilled_goods(); void fill_needs_fulfilled_goods_with_false(); @@ -200,6 +199,13 @@ namespace OpenVic { static void after_sell(void* actor, SellResult const& sell_result, memory::vector& reusable_vector); public: + Pop( + ProvinceInstance& new_location, + PopBase const& pop_base, + decltype(supporter_equivalents_by_ideology)::keys_span_type ideology_keys, + PopDeps const& pop_deps, + const pop_id_in_province_t new_id_in_province + ); Pop(Pop const&) = delete; Pop(Pop&&) = default; Pop& operator=(Pop const&) = delete; @@ -207,8 +213,6 @@ namespace OpenVic { void setup_pop_test_values(IssueManager const& issue_manager); bool convert_to_equivalent(); - - void set_location(ProvinceInstance& new_location); void update_location_based_attributes(); void update_gamestate( diff --git a/src/openvic-simulation/population/PopsAggregate.cpp b/src/openvic-simulation/population/PopsAggregate.cpp index a1beac08b..5d9afe735 100644 --- a/src/openvic-simulation/population/PopsAggregate.cpp +++ b/src/openvic-simulation/population/PopsAggregate.cpp @@ -169,7 +169,7 @@ void PopsAggregate::add_pops_aggregate(Pop const& pop) { militancy_running_total_raw += pop_size_v * static_cast(pop.get_militancy().get_raw_value()); - PopType const& pop_type = *pop.get_type(); + PopType const& pop_type = pop.get_type(); Strata const& strata = pop_type.strata; population_by_strata.at(strata) += pop_size; @@ -191,7 +191,7 @@ void PopsAggregate::add_pops_aggregate(Pop const& pop) { population_by_culture[&pop.culture] += pop_size; population_by_religion[&pop.religion] += pop_size; - if (pop.get_type()->can_be_recruited) { + if (pop_type.can_be_recruited) { max_supported_regiment_count += pop.get_max_supported_regiments(); } yesterdays_import_value.set(_yesterdays_import_value_running_total); diff --git a/src/openvic-simulation/utility/Getters.hpp b/src/openvic-simulation/utility/Getters.hpp index 70d6141cb..33a660caf 100644 --- a/src/openvic-simulation/utility/Getters.hpp +++ b/src/openvic-simulation/utility/Getters.hpp @@ -1,13 +1,11 @@ #pragma once -#include #include -#include +#include #include #include #include #include -#include #include "openvic-simulation/core/portable/ForwardableSpan.hpp" // IWYU pragma: keep for SPAN_PROPERTY #include "openvic-simulation/core/Typedefs.hpp" // IWYU pragma: keep @@ -154,6 +152,9 @@ namespace OpenVic { } else if constexpr (std::is_pointer_v) { /* Return const pointer */ return static_cast>>>(property); + } else if constexpr (is_specialization_of_v) { + /* Return T::type const& */ + return static_cast&>(property.get()); } else if constexpr (std::same_as> || std::same_as>) { /* Return optional std::string_view looking at string */ std::optional result;