aboutsummaryrefslogtreecommitdiff
path: root/src/openvic/dataloader
diff options
context:
space:
mode:
author Hop311 <hop3114@gmail.com>2023-09-08 18:12:22 +0200
committer Hop311 <hop3114@gmail.com>2023-09-08 18:12:22 +0200
commit7772f8871348b7b52cb0a478bb76df68d8799a07 (patch)
treefd8c4626b2cee69a9fe9250365af6b18eea63c70 /src/openvic/dataloader
parent7f9a9a8241ba81be9213e6606b8be4a48f1cbaab (diff)
More refactoring and duplicate code removal
Diffstat (limited to 'src/openvic/dataloader')
-rw-r--r--src/openvic/dataloader/Dataloader.cpp288
-rw-r--r--src/openvic/dataloader/Dataloader.hpp35
-rw-r--r--src/openvic/dataloader/NodeTools.cpp256
-rw-r--r--src/openvic/dataloader/NodeTools.hpp161
4 files changed, 0 insertions, 740 deletions
diff --git a/src/openvic/dataloader/Dataloader.cpp b/src/openvic/dataloader/Dataloader.cpp
deleted file mode 100644
index 55994d3..0000000
--- a/src/openvic/dataloader/Dataloader.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
-#include "Dataloader.hpp"
-
-#include "openvic/GameManager.hpp"
-#include "openvic/utility/Logger.hpp"
-
-#include <openvic-dataloader/csv/Parser.hpp>
-#include <openvic-dataloader/detail/CallbackOStream.hpp>
-#include <openvic-dataloader/v2script/Parser.hpp>
-
-using namespace OpenVic;
-using namespace OpenVic::NodeTools;
-using namespace ovdl;
-
-bool Dataloader::set_roots(std::vector<std::filesystem::path> new_roots) {
- if (!roots.empty()) {
- Logger::error("Overriding existing dataloader roots!");
- roots.clear();
- }
- bool ret = true;
- for (std::reverse_iterator<std::vector<std::filesystem::path>::const_iterator> it = new_roots.crbegin(); it != new_roots.crend(); ++it) {
- if (std::find(roots.begin(), roots.end(), *it) == roots.end()) {
- if (std::filesystem::is_directory(*it)) {
- Logger::info("Adding dataloader root: ", *it);
- roots.push_back(*it);
- } else {
- Logger::error("Invalid dataloader root (must be an existing directory): ", *it);
- ret = false;
- }
- } else {
- Logger::error("Duplicate dataloader root: ", *it);
- ret = false;
- }
- }
- if (roots.empty()) {
- Logger::error("Dataloader has no roots after attempting to add ", new_roots.size());
- ret = false;
- }
- return ret;
-}
-
-std::filesystem::path Dataloader::lookup_file(std::filesystem::path const& path) const {
- for (std::filesystem::path const& root : roots) {
- const std::filesystem::path composed = root / path;
- if (std::filesystem::is_regular_file(composed)) {
- return composed;
- }
- }
- Logger::error("Lookup for ", path, " failed!");
- return {};
-}
-
-const std::filesystem::path Dataloader::TXT = ".txt";
-
-static bool contains_file_with_name(std::vector<std::filesystem::path> const& paths,
- std::filesystem::path const& name) {
-
- for (std::filesystem::path const& path : paths) {
- if (path.filename() == name) return true;
- }
- return false;
-}
-
-std::vector<std::filesystem::path> Dataloader::lookup_files_in_dir(std::filesystem::path const& path,
- std::filesystem::path const* extension) const {
-
- std::vector<std::filesystem::path> ret;
- for (std::filesystem::path const& root : roots) {
- const std::filesystem::path composed = root / path;
- std::error_code ec;
- for (std::filesystem::directory_entry const& entry : std::filesystem::directory_iterator { composed, ec }) {
- if (entry.is_regular_file()) {
- const std::filesystem::path file = entry;
- if (extension == nullptr || file.extension() == *extension) {
- if (!contains_file_with_name(ret, file.filename())) {
- ret.push_back(file);
- }
- }
- }
- }
- }
- return ret;
-}
-
-bool Dataloader::apply_to_files_in_dir(std::filesystem::path const& path,
- std::function<bool(std::filesystem::path const&)> callback,
- std::filesystem::path const* extension) const {
-
- bool ret = true;
- for (std::filesystem::path const& file : lookup_files_in_dir(path, extension)) {
- ret &= callback(file);
- }
- return ret;
-}
-
-template<std::derived_from<detail::BasicParser> Parser, bool(Parser::*parse_func)()>
-static Parser _run_ovdl_parser(std::filesystem::path const& path) {
- Parser parser;
- std::string buffer;
- auto error_log_stream = ovdl::detail::CallbackStream {
- [](void const* s, std::streamsize n, void* user_data) -> std::streamsize {
- if (s != nullptr && n > 0 && user_data != nullptr) {
- static_cast<std::string*>(user_data)->append(static_cast<char const*>(s), n);
- return n;
- } else {
- Logger::error("Invalid input to parser error log callback: ", s, " / ", n, " / ", user_data);
- return 0;
- }
- }, &buffer
- };
- parser.set_error_log_to(error_log_stream);
- parser.load_from_file(path);
- if (!buffer.empty()) {
- Logger::error("Parser load errors:\n\n", buffer, "\n");
- buffer.clear();
- }
- if (parser.has_fatal_error() || parser.has_error()) {
- Logger::error("Parser errors while loading ", path);
- return parser;
- }
- if (!(parser.*parse_func)()) {
- Logger::error("Parse function returned false!");
- }
- if (!buffer.empty()) {
- Logger::error("Parser parse errors:\n\n", buffer, "\n");
- buffer.clear();
- }
- if (parser.has_fatal_error() || parser.has_error()) {
- Logger::error("Parser errors while parsing ", path);
- }
- return parser;
-}
-
-static v2script::Parser _parse_defines(std::filesystem::path const& path) {
- return _run_ovdl_parser<v2script::Parser, &v2script::Parser::simple_parse>(path);
-}
-
-static csv::Windows1252Parser _parse_csv(std::filesystem::path const& path) {
- return _run_ovdl_parser<csv::Windows1252Parser, &csv::Windows1252Parser::parse_csv>(path);
-}
-
-bool Dataloader::_load_pop_types(PopManager& pop_manager, std::filesystem::path const& pop_type_directory) const {
- const bool ret = apply_to_files_in_dir(pop_type_directory,
- [&pop_manager](std::filesystem::path const& file) -> bool {
- return pop_manager.load_pop_type_file(file, _parse_defines(file).get_file_node());
- }
- );
- if (!ret) {
- Logger::error("Failed to load pop types!");
- }
- pop_manager.lock_pop_types();
- return ret;
-}
-
-bool Dataloader::_load_map_dir(Map& map, std::filesystem::path const& map_directory) const {
- static const std::filesystem::path defaults_filename = "default.map";
- static const std::string default_definitions = "definition.csv";
- static const std::string default_provinces = "provinces.bmp";
- static const std::string default_positions = "positions.txt";
- static const std::string default_terrain = "terrain.bmp";
- static const std::string default_rivers = "rivers.bmp";
- static const std::string default_terrain_definition = "terrain.txt";
- static const std::string default_tree_definition = "trees.txt";
- static const std::string default_continent = "continent.txt";
- static const std::string default_adjacencies = "adjacencies.csv";
- static const std::string default_region = "region.txt";
- static const std::string default_region_sea = "region_sea.txt";
- static const std::string default_province_flag_sprite = "province_flag_sprites";
-
- const v2script::Parser parser = _parse_defines(lookup_file(map_directory / defaults_filename));
-
- std::vector<std::string_view> water_province_identifiers;
-
-#define APPLY_TO_MAP_PATHS(F) \
- F(definitions) F(provinces) F(positions) F(terrain) F(rivers) \
- F(terrain_definition) F(tree_definition) F(continent) F(adjacencies) \
- F(region) F(region_sea) F(province_flag_sprite)
-
-#define MAP_PATH_VAR(X) std::string_view X = default_##X;
- APPLY_TO_MAP_PATHS(MAP_PATH_VAR)
-#undef MAP_PATH_VAR
-
- bool ret = expect_dictionary_keys(
- "max_provinces", ONE_EXACTLY,
- expect_uint(
- [&map](uint64_t val) -> bool {
- if (Province::NULL_INDEX < val && val <= Province::MAX_INDEX) {
- return map.set_max_provinces(val);
- }
- Logger::error("Invalid max province count ", val, " (out of valid range ", Province::NULL_INDEX, " < max_provinces <= ", Province::MAX_INDEX, ")");
- return false;
- }
- ),
- "sea_starts", ONE_EXACTLY,
- expect_list_reserve_length(
- water_province_identifiers,
- expect_identifier(
- [&water_province_identifiers](std::string_view identifier) -> bool {
- water_province_identifiers.push_back(identifier);
- return true;
- }
- )
- ),
-
-#define MAP_PATH_DICT_ENTRY(X) \
- #X, ONE_EXACTLY, expect_string(assign_variable_callback(X)),
- APPLY_TO_MAP_PATHS(MAP_PATH_DICT_ENTRY)
-#undef MAP_PATH_DICT_ENTRY
-
-#undef APPLY_TO_MAP_PATHS
-
- "border_heights", ZERO_OR_ONE, success_callback,
- "terrain_sheet_heights", ZERO_OR_ONE, success_callback,
- "tree", ZERO_OR_ONE, success_callback,
- "border_cutoff", ZERO_OR_ONE, success_callback
- )(parser.get_file_node());
-
- if (!ret) {
- Logger::error("Failed to load map default file!");
- }
-
- if (!map.load_province_definitions(_parse_csv(lookup_file(map_directory / definitions)).get_lines())) {
- Logger::error("Failed to load province definitions file!");
- ret = false;
- }
-
- if (!map.set_water_province_list(water_province_identifiers)) {
- Logger::error("Failed to set water provinces!");
- ret = false;
- }
- map.lock_water_provinces();
-
- return ret;
-}
-
-bool Dataloader::load_defines(GameManager& game_manager) const {
- static const std::filesystem::path good_file = "common/goods.txt";
- static const std::filesystem::path pop_type_directory = "poptypes";
- static const std::filesystem::path graphical_culture_type_file = "common/graphicalculturetype.txt";
- static const std::filesystem::path culture_file = "common/cultures.txt";
- static const std::filesystem::path religion_file = "common/religion.txt";
- static const std::filesystem::path map_directory = "map";
-
- bool ret = true;
-
- if (!game_manager.good_manager.load_good_file(_parse_defines(lookup_file(good_file)).get_file_node())) {
- Logger::error("Failed to load goods!");
- ret = false;
- }
- if (!_load_pop_types(game_manager.pop_manager, pop_type_directory)) {
- Logger::error("Failed to load pop types!");
- ret = false;
- }
- if (!game_manager.pop_manager.culture_manager.load_graphical_culture_type_file(_parse_defines(lookup_file(graphical_culture_type_file)).get_file_node())) {
- Logger::error("Failed to load graphical culture types!");
- ret = false;
- }
- if (!game_manager.pop_manager.culture_manager.load_culture_file(_parse_defines(lookup_file(culture_file)).get_file_node())) {
- Logger::error("Failed to load cultures!");
- ret = false;
- }
- if (!game_manager.pop_manager.religion_manager.load_religion_file(_parse_defines(lookup_file(religion_file)).get_file_node())) {
- Logger::error("Failed to load religions!");
- ret = false;
- }
- if (!_load_map_dir(game_manager.map, map_directory)) {
- Logger::error("Failed to load map!");
- ret = false;
- }
-
- return ret;
-}
-
-bool Dataloader::load_pop_history(GameManager& game_manager, std::filesystem::path const& path) const {
- return apply_to_files_in_dir(path,
- [&game_manager](std::filesystem::path const& file) -> bool {
- return expect_dictionary(
- [&game_manager](std::string_view province_key, ast::NodeCPtr province_node) -> bool {
- Province* province = game_manager.map.get_province_by_identifier(province_key);
- if (province == nullptr) {
- Logger::error("Invalid province id: ", province_key);
- return false;
- }
- return province->load_pop_list(game_manager.pop_manager, province_node);
- }
- )(_parse_defines(file).get_file_node());
- }
- );
-}
diff --git a/src/openvic/dataloader/Dataloader.hpp b/src/openvic/dataloader/Dataloader.hpp
deleted file mode 100644
index f723803..0000000
--- a/src/openvic/dataloader/Dataloader.hpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#pragma once
-
-#include <filesystem>
-#include <functional>
-#include <vector>
-
-namespace OpenVic {
- struct GameManager;
- struct PopManager;
- struct Map;
-
- class Dataloader {
- std::vector<std::filesystem::path> roots;
-
- bool _load_pop_types(PopManager& pop_manager, std::filesystem::path const& pop_type_directory) const;
- bool _load_map_dir(Map& map, std::filesystem::path const& map_directory) const;
-
- public:
- Dataloader() = default;
-
- /* In reverse-load order, so base defines first and final loaded mod last */
- bool set_roots(std::vector<std::filesystem::path> new_roots);
-
- std::filesystem::path lookup_file(std::filesystem::path const& path) const;
- static const std::filesystem::path TXT;
- std::vector<std::filesystem::path> lookup_files_in_dir(std::filesystem::path const& path,
- std::filesystem::path const* extension = &TXT) const;
- bool apply_to_files_in_dir(std::filesystem::path const& path,
- std::function<bool(std::filesystem::path const&)> callback,
- std::filesystem::path const* extension = &TXT) const;
-
- bool load_defines(GameManager& game_manager) const;
- bool load_pop_history(GameManager& game_manager, std::filesystem::path const& path) const;
- };
-}
diff --git a/src/openvic/dataloader/NodeTools.cpp b/src/openvic/dataloader/NodeTools.cpp
deleted file mode 100644
index 499527f..0000000
--- a/src/openvic/dataloader/NodeTools.cpp
+++ /dev/null
@@ -1,256 +0,0 @@
-#include "NodeTools.hpp"
-
-#include <charconv>
-
-using namespace OpenVic;
-using namespace OpenVic::NodeTools;
-
-template<typename T>
-static node_callback_t _expect_type(std::function<bool(T const&)> callback) {
- return [callback](ast::NodeCPtr node) -> bool {
- if (node != nullptr) {
- T const* cast_node = node->cast_to<T>();
- if (cast_node != nullptr) {
- return callback(*cast_node);
- }
- Logger::error("Invalid node type ", node->get_type(), " when expecting ", T::get_type_static());
- } else {
- Logger::error("Null node when expecting ", T::get_type_static());
- }
- return false;
- };
-}
-
-template<typename T = ast::AbstractStringNode>
-requires(std::derived_from<T, ast::AbstractStringNode>)
-static std::function<bool(T const&)> abstract_string_node_callback(std::function<bool(std::string_view)> callback) {
- return [callback](T const& node) -> bool {
- return callback(node._name);
- };
-}
-
-node_callback_t NodeTools::expect_identifier(std::function<bool(std::string_view)> callback) {
- return _expect_type<ast::IdentifierNode>(abstract_string_node_callback<ast::IdentifierNode>(callback));
-}
-
-node_callback_t NodeTools::expect_string(std::function<bool(std::string_view)> callback) {
- return _expect_type<ast::StringNode>(abstract_string_node_callback<ast::StringNode>(callback));
-}
-
-node_callback_t NodeTools::expect_identifier_or_string(std::function<bool(std::string_view)> callback) {
- return [callback](ast::NodeCPtr node) -> bool {
- if (node != nullptr) {
- ast::AbstractStringNode const* cast_node = node->cast_to<ast::IdentifierNode>();
- if (cast_node == nullptr) {
- cast_node = node->cast_to<ast::StringNode>();
- }
- if (cast_node != nullptr) {
- return abstract_string_node_callback(callback)(*cast_node);
- }
- Logger::error("Invalid node type ", node->get_type(), " when expecting ", ast::IdentifierNode::get_type_static(), " or ", ast::StringNode::get_type_static());
- } else {
- Logger::error("Null node when expecting ", ast::IdentifierNode::get_type_static(), " or ", ast::StringNode::get_type_static());
- }
- return false;
- };
-}
-
-node_callback_t NodeTools::expect_bool(std::function<bool(bool)> callback) {
- return expect_identifier(
- [callback](std::string_view identifier) -> bool {
- if (identifier == "yes") {
- return callback(true);
- } else if (identifier == "no") {
- return callback(false);
- }
- Logger::error("Invalid bool identifier text: ", identifier);
- return false;
- }
- );
-}
-
-node_callback_t NodeTools::expect_int(std::function<bool(int64_t)> callback) {
- return expect_identifier(
- [callback](std::string_view identifier) -> bool {
- bool successful = false;
- const int64_t val = StringUtils::string_to_int64(identifier, &successful, 10);
- if (successful) {
- return callback(val);
- }
- Logger::error("Invalid int identifier text: ", identifier);
- return false;
- }
- );
-}
-
-node_callback_t NodeTools::expect_uint(std::function<bool(uint64_t)> callback) {
- return expect_identifier(
- [callback](std::string_view identifier) -> bool {
- bool successful = false;
- const uint64_t val = StringUtils::string_to_uint64(identifier, &successful, 10);
- if (successful) {
- return callback(val);
- }
- Logger::error("Invalid uint identifier text: ", identifier);
- return false;
- }
- );
-}
-
-node_callback_t NodeTools::expect_fixed_point(std::function<bool(FP)> callback) {
- return expect_identifier(
- [callback](std::string_view identifier) -> bool {
- bool successful = false;
- const FP val = FP::parse(identifier.data(), identifier.length(), &successful);
- if (successful) {
- return callback(val);
- }
- Logger::error("Invalid fixed point identifier text: ", identifier);
- return false;
- }
- );
-}
-
-node_callback_t NodeTools::expect_colour(std::function<bool(colour_t)> callback) {
- return [callback](ast::NodeCPtr node) -> bool {
- colour_t col = NULL_COLOUR;
- uint32_t components = 0;
- bool ret = expect_list_of_length(3,
- expect_fixed_point(
- [&col, &components](FP val) -> bool {
- components++;
- col <<= 8;
- if (val < 0 || val > 255) {
- Logger::error("Invalid colour component: ", val);
- return false;
- } else {
- if (val <= 1) val *= 255;
- col |= val.to_int32_t();
- return true;
- }
- }
- )
- )(node);
- ret &= callback(col << 8 * (3 - components));
- return ret;
- };
-}
-
-node_callback_t NodeTools::expect_date(std::function<bool(Date)> callback) {
- return expect_identifier(
- [callback](std::string_view identifier) -> bool {
- bool successful = false;
- const Date date = Date::from_string(identifier, &successful);
- if (successful) {
- return callback(date);
- }
- Logger::error("Invalid date identifier text: ", identifier);
- return false;
- }
- );
-}
-
-node_callback_t NodeTools::expect_assign(key_value_callback_t callback) {
- return _expect_type<ast::AssignNode>(
- [callback](ast::AssignNode const& assign_node) -> bool {
- return callback(assign_node._name, assign_node._initializer.get());
- }
- );
-}
-
-node_callback_t NodeTools::expect_list_and_length(length_callback_t length_callback, node_callback_t callback) {
- return _expect_type<ast::AbstractListNode>(
- [length_callback, callback](ast::AbstractListNode const& list_node) -> bool {
- std::vector<ast::NodeUPtr> const& list = list_node._statements;
- bool ret = true;
- size_t size = length_callback(list.size());
- if (size > list.size()) {
- Logger::error("Trying to read more values than the list contains: ", size, " > ", list.size());
- size = list.size();
- ret = false;
- }
- std::for_each(list.begin(), list.begin() + size,
- [callback, &ret](ast::NodeUPtr const& sub_node) -> void {
- ret &= callback(sub_node.get());
- }
- );
- return ret;
- }
- );
-}
-
-node_callback_t NodeTools::expect_list_of_length(size_t length, node_callback_t callback) {
- return [length, callback](ast::NodeCPtr node) -> bool {
- bool ret = true;
- ret &= expect_list_and_length(
- [length, &ret](size_t size) -> size_t {
- if (size != length) {
- Logger::error("List length ", size, " does not match expected length ", length);
- ret = false;
- if (length < size) return length;
- }
- return size;
- },
- callback
- )(node);
- return ret;
- };
-}
-
-node_callback_t NodeTools::expect_list(node_callback_t callback) {
- return expect_list_and_length(default_length_callback, callback);
-}
-
-node_callback_t NodeTools::expect_dictionary_and_length(length_callback_t length_callback, key_value_callback_t callback) {
- return expect_list_and_length(length_callback, expect_assign(callback));
-}
-
-node_callback_t NodeTools::expect_dictionary(key_value_callback_t callback) {
- return expect_dictionary_and_length(default_length_callback, callback);
-}
-
-node_callback_t NodeTools::_expect_dictionary_keys_and_length(length_callback_t length_callback, bool allow_other_keys, key_map_t&& key_map) {
- return [length_callback, allow_other_keys, key_map = std::move(key_map)](ast::NodeCPtr node) mutable -> bool {
- bool ret = expect_dictionary_and_length(
- length_callback,
- [&key_map, allow_other_keys](std::string_view key, ast::NodeCPtr value) -> bool {
- const key_map_t::iterator it = key_map.find(key);
- if (it == key_map.end()) {
- if (allow_other_keys) return true;
- Logger::error("Invalid dictionary key: ", key);
- return false;
- }
- dictionary_entry_t& entry = it->second;
- if (++entry.count > 1 && !entry.can_repeat()) {
- Logger::error("Invalid repeat of dictionary key: ", key);
- return false;
- }
- return entry.callback(value);
- }
- )(node);
- for (key_map_t::value_type const& key_entry : key_map) {
- dictionary_entry_t const& entry = key_entry.second;
- if (entry.must_appear() && entry.count < 1) {
- Logger::error("Mandatory dictionary key not present: ", key_entry.first);
- ret = false;
- }
- }
- return ret;
- };
-}
-
-node_callback_t NodeTools::name_list_callback(std::vector<std::string>& list) {
- return expect_list_reserve_length(
- list,
- expect_identifier_or_string(
- [&list](std::string_view str) -> bool {
- if (!str.empty()) {
- list.push_back(std::string { str });
- return true;
- }
- Logger::error("Empty identifier or string");
- return false;
- }
- )
- );
-}
diff --git a/src/openvic/dataloader/NodeTools.hpp b/src/openvic/dataloader/NodeTools.hpp
deleted file mode 100644
index daea8ce..0000000
--- a/src/openvic/dataloader/NodeTools.hpp
+++ /dev/null
@@ -1,161 +0,0 @@
-#pragma once
-
-#include <map>
-
-#include "openvic/types/Colour.hpp"
-#include "openvic/types/Date.hpp"
-#include "openvic/types/fixed_point/FP.hpp"
-
-#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
-
-namespace OpenVic {
- namespace ast = ovdl::v2script::ast;
-
- namespace NodeTools {
-
- using node_callback_t = std::function<bool(ast::NodeCPtr)>;
- constexpr bool success_callback(ast::NodeCPtr) { return true; }
-
- using key_value_callback_t = std::function<bool(std::string_view, ast::NodeCPtr)>;
-
- node_callback_t expect_identifier(std::function<bool(std::string_view)> callback);
- node_callback_t expect_string(std::function<bool(std::string_view)> callback);
- node_callback_t expect_identifier_or_string(std::function<bool(std::string_view)> callback);
- node_callback_t expect_bool(std::function<bool(bool)> callback);
- node_callback_t expect_int(std::function<bool(int64_t)> callback);
- node_callback_t expect_uint(std::function<bool(uint64_t)> callback);
- node_callback_t expect_fixed_point(std::function<bool(FP)> callback);
- node_callback_t expect_colour(std::function<bool(colour_t)> callback);
- node_callback_t expect_date(std::function<bool(Date)> callback);
- node_callback_t expect_assign(key_value_callback_t callback);
-
- using length_callback_t = std::function<size_t(size_t)>;
- constexpr size_t default_length_callback(size_t size) { return size; };
-
- node_callback_t expect_list_and_length(length_callback_t length_callback, node_callback_t callback);
- node_callback_t expect_list_of_length(size_t length, node_callback_t callback);
- node_callback_t expect_list(node_callback_t callback);
-
- node_callback_t expect_dictionary_and_length(length_callback_t length_callback, key_value_callback_t callback);
- node_callback_t expect_dictionary(key_value_callback_t callback);
-
- struct dictionary_entry_t {
- const enum class expected_count_t : uint8_t {
- _MUST_APPEAR = 0b01,
- _CAN_REPEAT = 0b10,
-
- ZERO_OR_ONE = 0,
- ONE_EXACTLY = _MUST_APPEAR,
- ZERO_OR_MORE = _CAN_REPEAT,
- ONE_OR_MORE = _MUST_APPEAR | _CAN_REPEAT
- } expected_count;
- const node_callback_t callback;
- size_t count;
-
- dictionary_entry_t(expected_count_t new_expected_count, node_callback_t new_callback)
- : expected_count { new_expected_count }, callback { new_callback }, count { 0 } {}
-
- constexpr bool must_appear() const {
- return static_cast<uint8_t>(expected_count) & static_cast<uint8_t>(expected_count_t::_MUST_APPEAR);
- }
- constexpr bool can_repeat() const {
- return static_cast<uint8_t>(expected_count) & static_cast<uint8_t>(expected_count_t::_CAN_REPEAT);
- }
- };
- using enum dictionary_entry_t::expected_count_t;
- using key_map_t = std::map<std::string, dictionary_entry_t, std::less<void>>;
-
- constexpr struct allow_other_keys_t {} ALLOW_OTHER_KEYS;
-
- node_callback_t _expect_dictionary_keys_and_length(length_callback_t length_callback, bool allow_other_keys, key_map_t&& key_map);
-
- template<typename... Args>
- node_callback_t _expect_dictionary_keys_and_length(length_callback_t length_callback,
- bool allow_other_keys, key_map_t&& key_map,
- const std::string_view key, dictionary_entry_t::expected_count_t expected_count, node_callback_t callback,
- Args... args) {
- if (key_map.find(key) == key_map.end()) {
- key_map.emplace(key, dictionary_entry_t { expected_count, callback });
- } else {
- Logger::error("Duplicate expected dictionary key: ", key);
- }
- return _expect_dictionary_keys_and_length(length_callback, allow_other_keys, std::move(key_map), args...);
- }
-
- template<typename... Args>
- node_callback_t expect_dictionary_keys_and_length(length_callback_t length_callback,
- const std::string_view key, dictionary_entry_t::expected_count_t expected_count, node_callback_t callback,
- Args... args) {
- return _expect_dictionary_keys_and_length(length_callback, false, {}, key, expected_count, callback, args...);
- }
-
- template<typename... Args>
- node_callback_t expect_dictionary_keys_and_length(length_callback_t length_callback,
- allow_other_keys_t, Args... args) {
- return _expect_dictionary_keys_and_length(length_callback, true, {}, args...);
- }
-
- template<typename... Args>
- node_callback_t expect_dictionary_keys(Args... args) {
- return expect_dictionary_keys_and_length(default_length_callback, args...);
- }
-
- template<typename T>
- concept Reservable = requires(T& t) {
- { t.size() } -> std::same_as<size_t>;
- t.reserve( size_t {} );
- };
- template<Reservable T>
- node_callback_t expect_list_reserve_length(T& t, node_callback_t callback) {
- return expect_list_and_length(
- [&t](size_t size) -> size_t {
- t.reserve(t.size() + size);
- return size;
- },
- callback
- );
- }
- template<Reservable T>
- node_callback_t expect_dictionary_reserve_length(T& t, key_value_callback_t callback) {
- return expect_list_reserve_length(t, expect_assign(callback));
- }
-
- node_callback_t name_list_callback(std::vector<std::string>& list);
-
- template<typename T>
- std::function<bool(T)> assign_variable_callback(T& var) {
- return [&var](T val) -> bool {
- var = val;
- return true;
- };
- }
-
- template<typename T>
- requires(std::integral<T>)
- std::function<bool(uint64_t)> assign_variable_callback_uint(const std::string_view name, T& var) {
- return [&var, name](uint64_t val) -> bool {
- if (val <= std::numeric_limits<T>::max()) {
- var = val;
- return true;
- }
- Logger::error("Invalid ", name, ": ", val, " (valid range: [0, ", static_cast<uint64_t>(std::numeric_limits<T>::max()), "])");
- return false;
- };
- }
-
- template<typename T>
- requires(std::integral<T>)
- std::function<bool(int64_t)> assign_variable_callback_int(const std::string_view name, T& var) {
- return [&var, name](int64_t val) -> bool {
- if (std::numeric_limits<T>::lowest() <= val && val <= std::numeric_limits<T>::max()) {
- var = val;
- return true;
- }
- Logger::error("Invalid ", name, ": ", val, " (valid range: [",
- static_cast<int64_t>(std::numeric_limits<T>::lowest()), ", ",
- static_cast<uint64_t>(std::numeric_limits<T>::max()), "])");
- return false;
- };
- }
- }
-}