diff options
author | Hop311 <Hop3114@gmail.com> | 2023-11-07 22:38:07 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-07 22:38:07 +0100 |
commit | ae2742113ec7283a2a5afa62f8bfd98a865c4208 (patch) | |
tree | 601591215af0c6724766019ebb577141ea5807c5 /src/openvic-simulation/history/HistoryMap.hpp | |
parent | 1603fbafb1c03830f38fefd87d8bd0d7d3f135a2 (diff) | |
parent | d30421fa7d7f6ad87d3f90cc0ab491742f0d2548 (diff) |
Merge pull request #64 from OpenVicProject/modifier-instance
ModifierEffects stored as instances
Diffstat (limited to 'src/openvic-simulation/history/HistoryMap.hpp')
-rw-r--r-- | src/openvic-simulation/history/HistoryMap.hpp | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/src/openvic-simulation/history/HistoryMap.hpp b/src/openvic-simulation/history/HistoryMap.hpp new file mode 100644 index 0000000..64d886d --- /dev/null +++ b/src/openvic-simulation/history/HistoryMap.hpp @@ -0,0 +1,110 @@ +#pragma once + +#include <map> +#include <memory> + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/types/Date.hpp" + +namespace OpenVic { + + struct HistoryEntry { + private: + Date PROPERTY(date); + + protected: + HistoryEntry(Date new_date); + }; + + struct GameManager; + + /* Helper functions to avoid cyclic dependency issues */ + Date _get_start_date(GameManager const& game_manager); + Date _get_end_date(GameManager const& game_manager); + + template<std::derived_from<HistoryEntry> _Entry, typename... Args> + struct HistoryMap { + using entry_type = _Entry; + + private: + std::map<Date, std::unique_ptr<entry_type>> PROPERTY(entries); + + bool _try_load_history_entry(GameManager const& game_manager, Args... args, Date date, ast::NodeCPtr root) { + typename decltype(entries)::iterator it = entries.find(date); + if (it == entries.end()) { + const std::pair<typename decltype(entries)::iterator, bool> result = entries.emplace(date, _make_entry(date)); + if (result.second) { + it = result.first; + } else { + Logger::error("Failed to create history entry at date ", date); + return false; + } + } + return _load_history_entry(game_manager, args..., *it->second, root); + } + + protected: + HistoryMap() = default; + + virtual std::unique_ptr<entry_type> _make_entry(Date date) const = 0; + + virtual bool _load_history_entry( + GameManager const& game_manager, Args... args, entry_type& entry, ast::NodeCPtr root + ) = 0; + + bool _load_history_file(GameManager const& game_manager, Args... args, ast::NodeCPtr root) { + return _try_load_history_entry(game_manager, args..., _get_start_date(game_manager), root); + } + + bool _load_history_sub_entry_callback( + GameManager const& game_manager, Args... args, Date date, ast::NodeCPtr root, std::string_view key, + ast::NodeCPtr value, NodeTools::key_value_callback_t default_callback = NodeTools::key_value_invalid_callback + ) { + /* Date blocks (loaded into the corresponding HistoryEntry) */ + bool is_date = false; + const Date sub_date { Date::from_string(key, &is_date, true) }; + if (is_date) { + if (sub_date <= date) { + Logger::error("History entry ", sub_date, " defined before parent entry date ", date); + return false; + } + const Date end_date = _get_end_date(game_manager); + if (sub_date > end_date) { + Logger::error("History entry ", sub_date, " defined after end date ", end_date); + return false; + } + if (_try_load_history_entry(game_manager, args..., sub_date, value)) { + return true; + } else { + Logger::error("Failed to load history entry at date ", sub_date); + return false; + } + } + + return default_callback(key, value); + } + + public: + /* Returns history entry at specific date, if date doesn't have an entry returns nullptr. */ + entry_type const* get_entry(Date date) const { + typename decltype(entries)::const_iterator it = entries.find(date); + if (it != entries.end()) { + return it->second.get(); + } + return nullptr; + } + /* Returns history entries up to date as an ordered list of entries. */ + std::vector<entry_type const*> get_entries(Date end) const { + std::vector<entry_type const*> ret; + for (typename decltype(entries)::value_type const& entry : entries) { + if (entry.first <= end) { + ret.push_back(entry.second.get()); + } + } + std::sort(ret.begin(), ret.end(), [](entry_type const* lhs, entry_type const* rhs) -> bool { + return lhs->get_date() < rhs->get_date(); + }); + return ret; + } + }; +} |