Skip to content

Commit 0cd24a8

Browse files
Spartan322wvpm
andcommitted
Add type-safe pop_sum_t for large value sums of pops
Refactor pop_size_t to be type-safe Move pop_size_t to population/PopSize.hpp Add equalable to Concepts.hpp Add expect_strong_typedef to NodeTools.hpp Add `&& equalable<ValueType, OtherValueType>` requirement to IndexedFlatMap's divide_assign_handle_zero Fix ovdl::detail vs. OpenVic::detail namespace ambiguity in Dataloader.cpp Co-authored-by: wvpm <24685035+wvpm@users.noreply.github.com>
1 parent 20796b6 commit 0cd24a8

30 files changed

+522
-269
lines changed

src/openvic-simulation/core/template/Concepts.hpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,12 @@ namespace OpenVic {
108108
{ t.get_name() } -> std::same_as<std::string_view>;
109109
};
110110

111+
template<typename T>
112+
concept is_strongly_typed = derived_from_specialization_of<T, type_safe::strong_typedef>;
113+
111114
template<typename T>
112115
concept has_index = requires { typename T::index_t; } &&
113-
derived_from_specialization_of<typename T::index_t, type_safe::strong_typedef> && requires {
116+
is_strongly_typed<typename T::index_t> && requires {
114117
static_cast<std::size_t>(
115118
static_cast<type_safe::underlying_type<decltype(std::declval<T>().index)>>(std::declval<T>().index)
116119
);
@@ -222,8 +225,8 @@ namespace OpenVic {
222225
{ lhs /= rhs } -> std::same_as<Lhs&>;
223226
};
224227

225-
template<typename Lhs, typename A, typename B>
226-
concept mul_add_assignable = requires(Lhs& lhs, const A a, const B b) {
227-
{ lhs += a * b } -> std::same_as<Lhs&>;
228+
template<typename Lhs, typename Rhs = Lhs>
229+
concept equalable = requires(Lhs const& lhs, Rhs const& rhs) {
230+
{ lhs == rhs } -> std::convertible_to<bool>;
228231
};
229232
}

src/openvic-simulation/country/CountryInstance.cpp

Lines changed: 71 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@
4343
#include "openvic-simulation/types/Date.hpp"
4444
#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
4545
#include "openvic-simulation/types/IndexedFlatMap.hpp"
46-
#include "openvic-simulation/types/PopSize.hpp"
46+
#include "openvic-simulation/population/PopSize.hpp"
47+
#include "openvic-simulation/population/PopSum.hpp"
4748
#include "openvic-simulation/types/UnitBranchType.hpp"
4849
#include "openvic-simulation/utility/Containers.hpp"
4950
#include "openvic-simulation/utility/Logger.hpp"
@@ -1341,8 +1342,8 @@ void CountryInstance::_update_budget() {
13411342
OpenVic immediately updates both.
13421343
*/
13431344

1344-
pop_size_t total_non_colonial_population = 0;
1345-
pop_size_t administrators = 0;
1345+
pop_sum_t total_non_colonial_population = 0;
1346+
pop_sum_t administrators = 0;
13461347
for (State const* const state_ptr : states) {
13471348
if (state_ptr == nullptr) {
13481349
continue;
@@ -1353,7 +1354,7 @@ void CountryInstance::_update_budget() {
13531354
continue;
13541355
}
13551356

1356-
IndexedFlatMap<PopType, pop_size_t> const& state_population_by_type = state.get_population_by_type();
1357+
IndexedFlatMap<PopType, pop_sum_t> const& state_population_by_type = state.get_population_by_type();
13571358

13581359
for (auto const& [pop_type, size] : state_population_by_type) {
13591360
if (pop_type.is_administrator) {
@@ -1367,18 +1368,24 @@ void CountryInstance::_update_budget() {
13671368
administrative_efficiency_from_administrators.set(fixed_point_t::_1);
13681369
administrator_percentage.set(fixed_point_t::_0);
13691370
} else {
1370-
administrator_percentage.set(fixed_point_t(administrators) / total_non_colonial_population);
1371-
1372-
const fixed_point_t desired_administrators = desired_administrator_percentage.get_untracked() * total_non_colonial_population;
1373-
const fixed_point_t administrative_efficiency_from_administrators_unclamped = std::min(
1374-
fixed_point_t::mul_div(
1375-
administrators,
1376-
fixed_point_t::_1 + get_modifier_effect_value(*modifier_effect_cache.get_administrative_efficiency()),
1377-
desired_administrators
1378-
)
1379-
* (fixed_point_t::_1 + get_modifier_effect_value(*modifier_effect_cache.get_administrative_efficiency_modifier())),
1380-
fixed_point_t::_1
1371+
administrator_percentage.set(fixed_point_t::from_fraction(administrators, total_non_colonial_population));
1372+
1373+
const pop_sum_t desired_administrators = fixed_point_t::multiply_truncate(
1374+
total_non_colonial_population,
1375+
desired_administrator_percentage.get_untracked()
1376+
);
1377+
const pop_sum_t effective_administrators = fixed_point_t::multiply_truncate(
1378+
administrators,
1379+
fixed_point_t::_1 + get_modifier_effect_value(*modifier_effect_cache.get_administrative_efficiency())
13811380
);
1381+
const fixed_point_t administrative_efficiency_from_administrators_unclamped =
1382+
desired_administrators == 0
1383+
? fixed_point_t::_1
1384+
: std::min(
1385+
fixed_point_t::from_fraction(effective_administrators, desired_administrators)
1386+
* (fixed_point_t::_1 + get_modifier_effect_value(*modifier_effect_cache.get_administrative_efficiency_modifier())),
1387+
fixed_point_t::_1
1388+
);
13821389

13831390
administrative_efficiency_from_administrators.set(
13841391
game_rules_manager.get_prevent_negative_administration_efficiency()
@@ -1387,36 +1394,42 @@ void CountryInstance::_update_budget() {
13871394
);
13881395
}
13891396

1390-
fixed_point_t projected_administration_spending_unscaled_by_slider_running_total = 0;
1391-
fixed_point_t projected_education_spending_unscaled_by_slider_running_total = 0;
1392-
fixed_point_t projected_military_spending_unscaled_by_slider_running_total = 0;
1393-
fixed_point_t projected_pensions_spending_unscaled_by_slider_running_total = 0;
1394-
fixed_point_t projected_unemployment_subsidies_spending_unscaled_by_slider_running_total = 0;
1397+
int64_t projected_administration_spending_unscaled_by_slider_running_total = 0;
1398+
int64_t projected_education_spending_unscaled_by_slider_running_total = 0;
1399+
int64_t projected_military_spending_unscaled_by_slider_running_total = 0;
1400+
int64_t projected_pensions_spending_unscaled_by_slider_running_total = 0;
1401+
int64_t projected_unemployment_subsidies_spending_unscaled_by_slider_running_total = 0;
13951402

1396-
for (auto const& [pop_type, size] : get_population_by_type()) {
1397-
projected_administration_spending_unscaled_by_slider_running_total += size * administration_salary_base_by_pop_type.at(pop_type).get_untracked();
1398-
projected_education_spending_unscaled_by_slider_running_total += size * education_salary_base_by_pop_type.at(pop_type).get_untracked();
1399-
projected_military_spending_unscaled_by_slider_running_total += size * military_salary_base_by_pop_type.at(pop_type).get_untracked();
1400-
projected_pensions_spending_unscaled_by_slider_running_total += size * calculate_pensions_base(pop_type);
1401-
projected_unemployment_subsidies_spending_unscaled_by_slider_running_total += get_unemployed_pops_by_type(pop_type)
1402-
* calculate_unemployment_subsidies_base(pop_type);
1403-
}
1404-
1405-
projected_administration_spending_unscaled_by_slider.set(
1406-
projected_administration_spending_unscaled_by_slider_running_total / Pop::size_denominator
1407-
);
1408-
projected_education_spending_unscaled_by_slider.set(
1409-
projected_education_spending_unscaled_by_slider_running_total / Pop::size_denominator
1410-
);
1411-
projected_military_spending_unscaled_by_slider.set(
1412-
projected_military_spending_unscaled_by_slider_running_total / Pop::size_denominator
1413-
);
1414-
projected_pensions_spending_unscaled_by_slider.set(
1415-
projected_pensions_spending_unscaled_by_slider_running_total / Pop::size_denominator
1416-
);
1417-
projected_unemployment_subsidies_spending_unscaled_by_slider.set(
1418-
projected_unemployment_subsidies_spending_unscaled_by_slider_running_total / Pop::size_denominator
1419-
);
1403+
for (auto const& [pop_type, pop_size] : get_population_by_type()) {
1404+
const int64_t size = type_safe::get(pop_size);
1405+
projected_administration_spending_unscaled_by_slider_running_total += size * administration_salary_base_by_pop_type.at(pop_type).get_untracked().get_raw_value();
1406+
projected_education_spending_unscaled_by_slider_running_total += size * education_salary_base_by_pop_type.at(pop_type).get_untracked().get_raw_value();
1407+
projected_military_spending_unscaled_by_slider_running_total += size * military_salary_base_by_pop_type.at(pop_type).get_untracked().get_raw_value();
1408+
projected_pensions_spending_unscaled_by_slider_running_total += size * calculate_pensions_base(pop_type).get_raw_value();
1409+
projected_unemployment_subsidies_spending_unscaled_by_slider_running_total += type_safe::get(get_unemployed_pops_by_type(pop_type))
1410+
* calculate_unemployment_subsidies_base(pop_type).get_raw_value();
1411+
}
1412+
1413+
projected_administration_spending_unscaled_by_slider.set(fixed_point_t::from_fraction(
1414+
projected_administration_spending_unscaled_by_slider_running_total,
1415+
type_safe::get(Pop::size_denominator)
1416+
));
1417+
projected_education_spending_unscaled_by_slider.set(fixed_point_t::from_fraction(
1418+
projected_education_spending_unscaled_by_slider_running_total,
1419+
type_safe::get(Pop::size_denominator)
1420+
));
1421+
projected_military_spending_unscaled_by_slider.set(fixed_point_t::from_fraction(
1422+
projected_military_spending_unscaled_by_slider_running_total,
1423+
type_safe::get(Pop::size_denominator)
1424+
));
1425+
projected_pensions_spending_unscaled_by_slider.set(fixed_point_t::from_fraction(
1426+
projected_pensions_spending_unscaled_by_slider_running_total,
1427+
type_safe::get(Pop::size_denominator)
1428+
));
1429+
projected_unemployment_subsidies_spending_unscaled_by_slider.set(fixed_point_t::from_fraction(
1430+
projected_unemployment_subsidies_spending_unscaled_by_slider_running_total,
1431+
type_safe::get(Pop::size_denominator)
1432+
));
14201433
}
14211434

14221435
fixed_point_t CountryInstance::calculate_pensions_base(PopType const& pop_type) {
@@ -1498,9 +1511,18 @@ void CountryInstance::_update_population() {
14981511

14991512
for (auto const& [pop_type, pop_size] : get_population_by_type()) {
15001513
if (pop_type.research_leadership_optimum > 0 && pop_size > 0) {
1501-
const fixed_point_t factor = std::min(
1502-
pop_size / (get_total_population() * pop_type.research_leadership_optimum), fixed_point_t::_1
1514+
const pop_sum_t optimum_size = fixed_point_t::multiply_truncate(
1515+
get_total_population(),
1516+
pop_type.research_leadership_optimum
15031517
);
1518+
const fixed_point_t factor = optimum_size == 0
1519+
? fixed_point_t::_1
1520+
: std::min(
1521+
fixed_point_t::from_fraction(
1522+
pop_size,
1523+
optimum_size
1524+
), fixed_point_t::_1
1525+
);
15041526

15051527
if (pop_type.research_points != 0) {
15061528
const fixed_point_t research_points = pop_type.research_points * factor;
@@ -1634,11 +1656,9 @@ void CountryInstance::_update_military() {
16341656
naval_unit_start_experience += get_modifier_effect_value(*modifier_effect_cache.get_naval_unit_start_experience());
16351657

16361658
recruit_time = fixed_point_t::_1 + get_modifier_effect_value(*modifier_effect_cache.get_unit_recruitment_time());
1637-
combat_width = combat_width_t(
1638-
(
1639-
type_safe::get(military_defines.get_base_combat_width())
1640-
+ get_modifier_effect_value(*modifier_effect_cache.get_combat_width_additive())
1641-
).floor<type_safe::underlying_type<combat_width_t>>()
1659+
combat_width = fixed_point_t::multiply_truncate(
1660+
military_defines.get_base_combat_width(),
1661+
get_modifier_effect_value(*modifier_effect_cache.get_combat_width_additive())
16421662
);
16431663
dig_in_cap = get_modifier_effect_value(*modifier_effect_cache.get_dig_in_cap()).floor<int32_t>();
16441664
military_tactics = military_defines.get_base_military_tactics() +

src/openvic-simulation/dataloader/Dataloader.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,11 @@ string_set_t Dataloader::lookup_dirs_in_dir(std::string_view path) const {
240240
return ret;
241241
}
242242

243-
template<std::derived_from<detail::BasicParser> Parser, bool (*parse_func)(Parser&)>
243+
template<std::derived_from<ovdl::detail::BasicParser> Parser, bool (*parse_func)(Parser&)>
244244
static Parser _run_ovdl_parser(fs::path const& path) {
245245
Parser parser;
246246
memory::string buffer;
247-
auto error_log_stream = detail::make_callback_stream<char>(
247+
auto error_log_stream = ovdl::detail::make_callback_stream<char>(
248248
[](void const* s, std::streamsize n, void* user_data) -> std::streamsize {
249249
if (s != nullptr && n > 0 && user_data != nullptr) {
250250
static_cast<memory::string*>(user_data)->append(static_cast<char const*>(s), n);

src/openvic-simulation/dataloader/NodeTools.hpp

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -199,21 +199,49 @@ using namespace std::string_view_literals;
199199
return expect_uint(callback, base);
200200
}
201201

202+
template<derived_from_specialization_of<type_safe::strong_typedef> T, typename AsT = type_safe::underlying_type<T>>
203+
NodeCallback auto expect_strong_typedef(callback_t<T>& callback, int base = 10) {
204+
if constexpr (std::unsigned_integral<AsT>) {
205+
return expect_uint64(
206+
[callback](uint64_t val) mutable -> bool {
207+
if (val <= static_cast<uint64_t>(std::numeric_limits<AsT>::max())) {
208+
return callback(T(val));
209+
}
210+
spdlog::error_s(
211+
"Invalid uint: {} (valid range: [0, {}])", val,
212+
static_cast<uint64_t>(std::numeric_limits<AsT>::max())
213+
);
214+
return false;
215+
},
216+
base
217+
);
218+
} else {
219+
return expect_int64(
220+
[callback](int64_t val) mutable -> bool {
221+
if (val >= static_cast<int64_t>(std::numeric_limits<AsT>::min()) &&
222+
val <= static_cast<int64_t>(std::numeric_limits<AsT>::max())) {
223+
return callback(T(val));
224+
}
225+
spdlog::error_s(
226+
"Invalid int: {} (valid range: [{}, {}])", val,
227+
static_cast<int64_t>(std::numeric_limits<AsT>::min()),
228+
static_cast<int64_t>(std::numeric_limits<AsT>::max())
229+
);
230+
return false;
231+
},
232+
base
233+
);
234+
}
235+
}
236+
template<derived_from_specialization_of<type_safe::strong_typedef> T, typename AsT = type_safe::underlying_type<T>>
237+
NodeCallback auto expect_strong_typedef(callback_t<T>&& callback, int base = 10) {
238+
return expect_strong_typedef<T, AsT>(callback, base);
239+
}
240+
202241
template<derived_from_specialization_of<type_safe::strong_typedef> T>
203242
requires std::unsigned_integral<type_safe::underlying_type<T>>
204243
NodeCallback auto expect_index(callback_t<T>& callback, int base = 10) {
205-
using underlying_type = type_safe::underlying_type<T>;
206-
207-
return expect_uint64([callback](uint64_t val) mutable -> bool {
208-
if (val <= static_cast<uint64_t>(std::numeric_limits<underlying_type>::max())) {
209-
return callback(T(val));
210-
}
211-
spdlog::error_s(
212-
"Invalid uint: {} (valid range: [0, {}])",
213-
val, static_cast<uint64_t>(std::numeric_limits<underlying_type>::max())
214-
);
215-
return false;
216-
}, base);
244+
return expect_strong_typedef<T>(callback, base);
217245
}
218246
template<derived_from_specialization_of<type_safe::strong_typedef> T>
219247
requires std::unsigned_integral<type_safe::underlying_type<T>>

src/openvic-simulation/defines/MilitaryDefines.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#include "MilitaryDefines.hpp"
22

3-
#include <cstdint>
4-
53
#include "openvic-simulation/military/CombatWidth.hpp"
64

75
#include <type_safe/strong_typedef.hpp>
@@ -20,12 +18,9 @@ node_callback_t MilitaryDefines::expect_defines() {
2018
"DIG_IN_INCREASE_EACH_DAYS", ONE_EXACTLY, expect_days(assign_variable_callback(dig_in_increase_each_days)),
2119
"REINFORCE_SPEED", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(reinforce_speed)),
2220
"COMBAT_DIFFICULTY_IMPACT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(combat_difficulty_impact)),
23-
"BASE_COMBAT_WIDTH", ONE_EXACTLY, expect_int<int8_t>([this](int8_t val)->bool{
24-
base_combat_width = combat_width_t(static_cast<type_safe::underlying_type<combat_width_t>>(val));
25-
return true;
26-
}),
27-
"POP_MIN_SIZE_FOR_REGIMENT", ONE_EXACTLY, expect_uint(assign_variable_callback(min_pop_size_for_regiment)),
28-
"POP_SIZE_PER_REGIMENT", ONE_EXACTLY, expect_uint(assign_variable_callback(pop_size_per_regiment)),
21+
"BASE_COMBAT_WIDTH", ONE_EXACTLY, expect_strong_typedef<combat_width_t>(assign_variable_callback(base_combat_width)),
22+
"POP_MIN_SIZE_FOR_REGIMENT", ONE_EXACTLY, expect_strong_typedef<pop_size_t>(assign_variable_callback(min_pop_size_for_regiment)),
23+
"POP_SIZE_PER_REGIMENT", ONE_EXACTLY, expect_strong_typedef<pop_size_t>(assign_variable_callback(pop_size_per_regiment)),
2924
"SOLDIER_TO_POP_DAMAGE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(soldier_to_pop_damage)),
3025
"LAND_SPEED_MODIFIER", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(land_speed_modifier)),
3126
"NAVAL_SPEED_MODIFIER", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(naval_speed_modifier)),

src/openvic-simulation/defines/MilitaryDefines.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include "openvic-simulation/military/CombatWidth.hpp"
55
#include "openvic-simulation/types/Date.hpp"
66
#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
7-
#include "openvic-simulation/types/PopSize.hpp"
7+
#include "openvic-simulation/population/PopSize.hpp"
88
#include "openvic-simulation/utility/Getters.hpp"
99

1010
namespace OpenVic {

src/openvic-simulation/defines/PopsDefines.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ node_callback_t PopsDefines::expect_defines() {
7575
"MOVEMENT_SUPPORT_UH_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(movement_support_uh_factor)),
7676
"REBEL_OCCUPATION_STRENGTH_BONUS", ONE_EXACTLY,
7777
expect_fixed_point(assign_variable_callback(rebel_occupation_strength_bonus)),
78-
"LARGE_POPULATION_LIMIT", ONE_EXACTLY, expect_uint(assign_variable_callback(large_population_limit)),
78+
"LARGE_POPULATION_LIMIT", ONE_EXACTLY, expect_strong_typedef<pop_sum_t>(assign_variable_callback(large_population_limit)),
7979
"LARGE_POPULATION_INFLUENCE_PENALTY_CHUNK", ONE_EXACTLY,
80-
expect_uint(assign_variable_callback(large_population_influence_penalty_chunk))
80+
expect_strong_typedef<pop_sum_t>(assign_variable_callback(large_population_influence_penalty_chunk))
8181
);
8282
}

src/openvic-simulation/defines/PopsDefines.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#include "openvic-simulation/dataloader/NodeTools.hpp"
44
#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
5-
#include "openvic-simulation/types/PopSize.hpp"
5+
#include "openvic-simulation/population/PopSum.hpp"
66
#include "openvic-simulation/types/ProvinceLifeRating.hpp"
77
#include "openvic-simulation/utility/Getters.hpp"
88

@@ -71,8 +71,8 @@ namespace OpenVic {
7171
fixed_point_t PROPERTY(nationalist_movement_mil_cap);
7272
fixed_point_t PROPERTY(movement_support_uh_factor);
7373
fixed_point_t PROPERTY(rebel_occupation_strength_bonus);
74-
pop_size_t PROPERTY(large_population_limit, 0);
75-
pop_size_t PROPERTY(large_population_influence_penalty_chunk, 0);
74+
pop_sum_t PROPERTY(large_population_limit, 0);
75+
pop_sum_t PROPERTY(large_population_influence_penalty_chunk, 0);
7676

7777
PopsDefines();
7878

src/openvic-simulation/economy/production/ArtisanalProducer.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ void ArtisanalProducer::artisan_tick_handler::calculate_inputs(
7272
//throughput scalar, the minimum of stockpile / base_desired_quantity
7373
//inputs_bought_fraction uses base_desired_quantity as population size is cancelled in the production and input calculations.
7474
const pop_size_t pop_size = pop.get_size();
75-
fixed_point_t inputs_bought_numerator = pop_size,
76-
inputs_bought_denominator = production_type.base_workforce_size,
75+
fixed_point_t inputs_bought_numerator = type_safe::get(pop_size),
76+
inputs_bought_denominator = type_safe::get(production_type.base_workforce_size),
7777
inputs_bought_fraction_v = inputs_bought_numerator / inputs_bought_denominator;
7878

7979
distinct_goods_to_buy = 0;
@@ -494,7 +494,7 @@ fixed_point_t ArtisanalProducer::calculate_production_type_score(
494494
k * fixed_point_t::mul_div(costs, costs, revenue)
495495
-(1+k)*costs
496496
+ revenue
497-
) * Pop::size_denominator / workforce; //factor out pop size without making values too small
497+
).mul_div(Pop::size_denominator, workforce); //factor out pop size without making values too small
498498
}
499499

500500
ProductionType const* ArtisanalProducer::pick_production_type(

src/openvic-simulation/economy/production/ArtisanalProducer.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
88
#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp"
99
#include "openvic-simulation/types/fixed_point/Fraction.hpp"
10-
#include "openvic-simulation/types/PopSize.hpp"
1110
#include "openvic-simulation/utility/Getters.hpp"
1211

1312
namespace OpenVic {
@@ -23,6 +22,7 @@ namespace OpenVic {
2322
struct ProductionType;
2423
struct ProvinceInstance;
2524
struct RandomU32;
25+
struct pop_size_t;
2626

2727
struct ArtisanalProducer {
2828
private:

0 commit comments

Comments
 (0)