From dd65fa7dd431264caa08d083cb3a94922a4084d5 Mon Sep 17 00:00:00 2001 From: hop311 Date: Fri, 6 Sep 2024 21:43:11 +0100 Subject: Add define caching to avoid post-load lookups --- src/openvic-simulation/misc/Define.cpp | 239 ++++++++++++++++++++++++++------- src/openvic-simulation/misc/Define.hpp | 55 ++++++-- 2 files changed, 231 insertions(+), 63 deletions(-) diff --git a/src/openvic-simulation/misc/Define.cpp b/src/openvic-simulation/misc/Define.cpp index 9ec5d49..6161842 100644 --- a/src/openvic-simulation/misc/Define.cpp +++ b/src/openvic-simulation/misc/Define.cpp @@ -1,109 +1,248 @@ #include "Define.hpp" -#include -#include -#include - #include #include "openvic-simulation/dataloader/NodeTools.hpp" #include "openvic-simulation/types/Date.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" +#include "openvic-simulation/utility/StringUtils.hpp" using namespace OpenVic; using namespace OpenVic::NodeTools; -Define::Define(std::string_view new_identifier, std::string&& new_value, Type new_type) - : HasIdentifier { new_identifier }, value { std::move(new_value) }, type { new_type } {} +std::string_view Define::type_to_string(Type type) { + using enum Type; + + switch (type) { + case Date: return "date"; + case Country: return "country"; + case Economy: return "economy"; + case Military: return "military"; + case Diplomacy: return "diplomacy"; + case Pops: return "pops"; + case Ai: return "ai"; + case Graphics: return "graphics"; + default: return "unknown"; + } +} + +Define::Type Define::string_to_type(std::string_view str) { + using enum Type; -fixed_point_t Define::get_value_as_fp() const { - return fixed_point_t::parse(value); + static const string_map_t type_map { + { "country", Country }, + { "economy", Economy }, + { "military", Military }, + { "diplomacy", Diplomacy }, + { "pops", Pops }, + { "ai", Ai }, + { "graphics", Graphics }, + }; + + const string_map_t::const_iterator type_it = type_map.find(str); + + if (type_it != type_map.end()) { + return type_it->second; + } else { + return Unknown; + } } -int64_t Define::get_value_as_int() const { - return std::strtoll(value.data(), nullptr, 10); +Define::Define(std::string_view new_identifier, std::string_view new_value, Type new_type) + : HasIdentifier { new_identifier }, value { new_value }, type { new_type } {} + +Date Define::get_value_as_date(bool* successful) const { + return Date::from_string(value, successful); } -uint64_t Define::get_value_as_uint() const { - return std::strtoull(value.data(), nullptr, 10); +fixed_point_t Define::get_value_as_fp(bool* successful) const { + return fixed_point_t::parse(value, successful); } -bool DefineManager::add_define(std::string_view name, std::string&& value, Define::Type type) { - if (name.empty()) { - Logger::error("Invalid define identifier - empty!"); - return false; - } - return defines.add_item({ name, std::move(value), type }, duplicate_warning_callback); +int64_t Define::get_value_as_int(bool* successful) const { + return StringUtils::string_to_int64(value, successful); } -Date DefineManager::get_start_date() const { - return start_date ? *start_date : Date {}; +uint64_t Define::get_value_as_uint(bool* successful) const { + return StringUtils::string_to_uint64(value, successful); } -Date DefineManager::get_end_date() const { - return end_date ? *end_date : Date {}; +std::ostream& OpenVic::operator<<(std::ostream& os, Define::Type type) { + return os << Define::type_to_string(type); } -bool DefineManager::in_game_period(Date date) const { - if (start_date && end_date) { - return date.in_range(*start_date, *end_date); +template +bool DefineManager::load_define(T& value, Define::Type type, std::string_view name) const { + static_assert( + std::same_as || std::same_as || std::integral + ); + + Define const* define = defines.get_item_by_identifier(name); + + if (define != nullptr) { + if (define->type != type) { + Logger::warning("Mismatched define type for \"", name, "\" - expected ", type, ", got ", define->type); + } + + const auto parse = + [define, &value, &name](std::string_view type_name) -> bool { + bool success = false; + const U result = (define->*Func)(&success); + if (success) { + value = static_cast(result); + return true; + } else { + Logger::error("Failed to parse ", type_name, " \"", define->get_value(), "\" for define \"", name, "\""); + return false; + } + }; + + if constexpr (std::same_as) { + return parse.template operator()("date"); + } else if constexpr (std::same_as) { + return parse.template operator()("fixed point"); + } else if constexpr (std::signed_integral) { + return parse.template operator()("signed int"); + } else if constexpr (std::unsigned_integral) { + return parse.template operator()("unsigned int"); + } } else { + Logger::error("Missing define \"", name, "\""); return false; } } -bool DefineManager::add_date_define(std::string_view name, Date date) { - if (name == "start_date") { - start_date = date; - } else if (name == "end_date") { - end_date = date; +template +bool DefineManager::_load_define_timespan(Timespan& value, Define::Type type, std::string_view name) const { + Define const* define = defines.get_item_by_identifier(name); + if (define != nullptr) { + if (define->type != type) { + Logger::warning("Mismatched define type for \"", name, "\" - expected ", type, ", got ", define->type); + } + bool success = false; + const int64_t result = define->get_value_as_int(&success); + if (success) { + value = Func(result); + return true; + } else { + Logger::error("Failed to parse days \"", define->get_value(), "\" for define \"", name, "\""); + return false; + } } else { - Logger::error("Invalid date define identifier - \"", name, "\" (must be start_date or end_date)"); + Logger::error("Missing define \"", name, "\""); + return false; + } +} + +bool DefineManager::load_define_days(Timespan& value, Define::Type type, std::string_view name) const { + return _load_define_timespan(value, type, name); +} + +bool DefineManager::load_define_months(Timespan& value, Define::Type type, std::string_view name) const { + return _load_define_timespan(value, type, name); +} + +bool DefineManager::load_define_years(Timespan& value, Define::Type type, std::string_view name) const { + return _load_define_timespan(value, type, name); +} + +DefineManager::DefineManager() + : // Date + start_date { 1836, 1, 1 }, + end_date { 1936, 1, 1 } + + // Country + + // Economy + + // Military + + // Diplomacy + + // Pops + + // Ai + + // Graphics + + {} + +bool DefineManager::add_define(std::string_view name, std::string_view value, Define::Type type) { + if (name.empty()) { + Logger::error("Invalid define identifier - empty!"); return false; } - return defines.add_item({ name, date.to_string(), Define::Type::Date }); + + if (value.empty()) { + Logger::error("Invalid define value for \"", name, "\" - empty!"); + return false; + } + + return defines.add_item({ name, value, type }, duplicate_warning_callback); +} + +bool DefineManager::in_game_period(Date date) const { + return date.in_range(start_date, end_date); } bool DefineManager::load_defines_file(ast::NodeCPtr root) { + using enum Define::Type; + bool ret = expect_dictionary_keys( "defines", ONE_EXACTLY, expect_dictionary([this](std::string_view key, ast::NodeCPtr value) -> bool { - using enum Define::Type; - static const string_map_t type_map { - { "country", Country }, - { "economy", Economy }, - { "military", Military }, - { "diplomacy", Diplomacy }, - { "pops", Pops }, - { "ai", Ai }, - { "graphics", Graphics }, - }; - const string_map_t::const_iterator type_it = type_map.find(key); + const Define::Type type = Define::string_to_type(key); - if (type_it != type_map.end()) { + if (type != Unknown) { return expect_dictionary_reserve_length( defines, - [this, &key, type = type_it->second](std::string_view inner_key, ast::NodeCPtr value) -> bool { - std::string str_val; - bool ret = expect_identifier_or_string(assign_variable_callback_string(str_val))(value); - ret &= add_define(inner_key, std::move(str_val), type); - return ret; + [this, type](std::string_view inner_key, ast::NodeCPtr value) -> bool { + return expect_identifier_or_string( + [this, &inner_key, type](std::string_view value) -> bool { + return add_define(inner_key, value, type); + } + )(value); } )(value); } else if (key == "start_date" || key == "end_date") { - return expect_date_identifier_or_string(std::bind_front(&DefineManager::add_date_define, this, key))(value); + return expect_identifier_or_string( + [this, &key](std::string_view value) -> bool { + return add_define(key, value, Date); + } + )(value); } else { + + Logger::error("Invalid define type - \"", key, "\""); return false; + } }) )(root); lock_defines(); + // Date + ret &= load_define(start_date, Date, "start_date"); + ret &= load_define(end_date, Date, "end_date"); + + // Country + + // Economy + + // Military + + // Diplomacy + + // Pops + + // Ai + + // Graphics + return ret; } diff --git a/src/openvic-simulation/misc/Define.hpp b/src/openvic-simulation/misc/Define.hpp index 3f7b3dc..7d8fbf7 100644 --- a/src/openvic-simulation/misc/Define.hpp +++ b/src/openvic-simulation/misc/Define.hpp @@ -1,7 +1,5 @@ #pragma once -#include - #include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" @@ -11,35 +9,66 @@ namespace OpenVic { struct Define : HasIdentifier { friend struct DefineManager; - enum class Type : unsigned char { Date, Country, Economy, Military, Diplomacy, Pops, Ai, Graphics }; + enum class Type : unsigned char { Unknown, Date, Country, Economy, Military, Diplomacy, Pops, Ai, Graphics }; + + static std::string_view type_to_string(Type type); + // This only accepts type names found in defines.lua, so it will never return Type::Date + static Type string_to_type(std::string_view str); private: std::string PROPERTY(value); const Type PROPERTY(type); - Define(std::string_view new_identifier, std::string&& new_value, Type new_type); + Define(std::string_view new_identifier, std::string_view new_value, Type new_type); public: Define(Define&&) = default; - fixed_point_t get_value_as_fp() const; - int64_t get_value_as_int() const; - uint64_t get_value_as_uint() const; + Date get_value_as_date(bool* successful = nullptr) const; + fixed_point_t get_value_as_fp(bool* successful = nullptr) const; + int64_t get_value_as_int(bool* successful = nullptr) const; + uint64_t get_value_as_uint(bool* successful = nullptr) const; }; + std::ostream& operator<<(std::ostream& os, Define::Type type); + struct DefineManager { private: IdentifierRegistry IDENTIFIER_REGISTRY(define); - std::optional start_date; - std::optional end_date; + // Date + Date PROPERTY(start_date); // start_date + Date PROPERTY(end_date); // end_date + + // Country + + // Economy + + // Military + + // Diplomacy + + // Pops + + // Ai + + // Graphics + + template + bool load_define(T& value, Define::Type type, std::string_view name) const; + + template + bool _load_define_timespan(Timespan& value, Define::Type type, std::string_view name) const; + + bool load_define_days(Timespan& value, Define::Type type, std::string_view name) const; + bool load_define_months(Timespan& value, Define::Type type, std::string_view name) const; + bool load_define_years(Timespan& value, Define::Type type, std::string_view name) const; public: - bool add_define(std::string_view name, std::string&& value, Define::Type type); - bool add_date_define(std::string_view name, Date date); + DefineManager(); + + bool add_define(std::string_view name, std::string_view value, Define::Type type); - Date get_start_date() const; - Date get_end_date() const; bool in_game_period(Date date) const; bool load_defines_file(ast::NodeCPtr root); -- cgit v1.2.3-56-ga3b1