aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/headless/main.cpp53
-rw-r--r--src/openvic/GameManager.cpp19
-rw-r--r--src/openvic/dataloader/Dataloader.cpp136
-rw-r--r--src/openvic/dataloader/Dataloader.hpp16
-rw-r--r--src/openvic/dataloader/NodeTools.cpp62
-rw-r--r--src/openvic/dataloader/NodeTools.hpp25
-rw-r--r--src/openvic/economy/Good.cpp56
-rw-r--r--src/openvic/economy/Good.hpp30
-rw-r--r--src/openvic/map/Building.cpp2
-rw-r--r--src/openvic/map/Map.cpp18
-rw-r--r--src/openvic/map/Province.cpp6
-rw-r--r--src/openvic/map/Province.hpp5
-rw-r--r--src/openvic/pop/Culture.cpp40
-rw-r--r--src/openvic/pop/Culture.hpp6
-rw-r--r--src/openvic/pop/Pop.cpp38
-rw-r--r--src/openvic/pop/Pop.hpp3
-rw-r--r--src/openvic/pop/Religion.cpp12
-rw-r--r--src/openvic/pop/Religion.hpp3
-rw-r--r--src/openvic/types/Date.cpp122
-rw-r--r--src/openvic/types/Date.hpp8
-rw-r--r--src/openvic/types/IdentifierRegistry.cpp8
-rw-r--r--src/openvic/types/IdentifierRegistry.hpp18
-rw-r--r--src/openvic/types/fixed_point/FP.hpp192
-rw-r--r--src/openvic/utility/FloatUtils.hpp11
-rw-r--r--src/openvic/utility/NumberUtils.hpp27
-rw-r--r--src/openvic/utility/StringUtils.hpp88
26 files changed, 652 insertions, 352 deletions
diff --git a/src/headless/main.cpp b/src/headless/main.cpp
index 69e1e67..9366f12 100644
--- a/src/headless/main.cpp
+++ b/src/headless/main.cpp
@@ -1,13 +1,13 @@
#ifdef OPENVIC_SIM_HEADLESS
-#include <openvic/utility/Logger.hpp>
#include <openvic/GameManager.hpp>
#include <openvic/dataloader/Dataloader.hpp>
+#include <openvic/utility/Logger.hpp>
using namespace OpenVic;
static char const* get_program_name(char const* name) {
- static char const* const missing_name = "<program>";
+ static constexpr char const* missing_name = "<program>";
if (name == nullptr) return missing_name;
char const* last_separator = name;
while (*name != '\0') {
@@ -20,14 +20,8 @@ static char const* get_program_name(char const* name) {
return last_separator;
}
-int main(int argc, char const* argv[]) {
- if (argc < 2) {
- std::cout << "Usage: " << get_program_name(argc > 0 ? argv[0] : nullptr) << " <base defines dir> [[mod defines dir]+]" << std::endl;
- std::cout << "Requires defines path(s) as arguments, starting with the base defines and continuing with mods (paths with spaces need to be enclosed in \"quotes\")." << std::endl;
- return -1;
- }
-
- std::cout << "!!! HEADLESS SIMULATION START !!!" << std::endl;
+static return_t headless_load(std::vector<std::filesystem::path> const& roots) {
+ return_t ret = SUCCESS;
Logger::set_info_func([](std::string&& str) { std::cout << str; });
Logger::set_error_func([](std::string&& str) { std::cerr << str; });
@@ -37,20 +31,47 @@ int main(int argc, char const* argv[]) {
} };
Dataloader dataloader;
- std::vector<std::filesystem::path> roots;
- for (int i = 1; i < argc; ++i) {
- roots.push_back(argv[i]);
+ if (dataloader.set_roots(roots) != SUCCESS) {
+ Logger::error("Failed to set dataloader roots!");
+ ret = FAILURE;
}
- dataloader.set_roots(roots);
-
if (dataloader.load_defines(game_manager) != SUCCESS) {
Logger::error("Failed to load defines!");
+ ret = FAILURE;
}
if (game_manager.load_hardcoded_defines() != SUCCESS) {
Logger::error("Failed to load hardcoded defines!");
+ ret = FAILURE;
}
+ return ret;
+}
+
+int main(int argc, char const* argv[]) {
+ std::vector<std::filesystem::path> roots;
+ if (argc < 2) {
+ // TODO - non-Windows default paths
+ static const std::filesystem::path default_path = "C:/Program Files (x86)/Steam/steamapps/common/Victoria 2";
+
+ std::cout << "Usage: " << get_program_name(argc > 0 ? argv[0] : nullptr) << " <base defines dir> [[mod defines dir]+]\n"
+ << "Requires defines path(s) as arguments, starting with the base defines and continuing with mods.\n"
+ << "(Paths with spaces need to be enclosed in \"quotes\").\n"
+ << "Defaulting to " << default_path << std::endl;
+ roots.push_back(default_path);
+ } else {
+ for (int i = 1; i < argc; ++i) {
+ roots.push_back(argv[i]);
+ }
+ }
+
+ std::cout << "!!! HEADLESS SIMULATION START !!!" << std::endl;
+
+ const return_t ret = headless_load(roots);
+
std::cout << "!!! HEADLESS SIMULATION END !!!" << std::endl;
- return 0;
+
+ std::cout << "\nLoad returned: " << (ret == SUCCESS ? "SUCCESS" : "FAILURE") << std::endl;
+
+ return ret == SUCCESS ? 0 : -1;
}
#endif
diff --git a/src/openvic/GameManager.cpp b/src/openvic/GameManager.cpp
index b4fa8b5..f9c9664 100644
--- a/src/openvic/GameManager.cpp
+++ b/src/openvic/GameManager.cpp
@@ -103,19 +103,14 @@ return_t GameManager::load_hardcoded_defines() {
return HIGH_ALPHA_VALUE | (fraction_to_colour_byte(province.get_total_population(), map.get_highest_province_population() + 1, 0.1f, 1.0f) << 8);
} },
{ "mapmode_culture",
- // TODO - use std::max_element and maybe change distribution_t to be an ordered std::map
[](Map const& map, Province const& province) -> colour_t {
- distribution_t const& cultures = province.get_culture_distribution();
- if (!cultures.empty()) {
- // This breaks if replaced with distribution_t::value_type, something
- // about operator=(volatile const&) being deleted.
- std::pair<HasIdentifierAndColour const*, float> culture = *cultures.begin();
- for (distribution_t::value_type const p : cultures) {
- if (p.second > culture.second) culture = p;
- }
- return HIGH_ALPHA_VALUE | culture.first->get_colour();
- }
- return NULL_COLOUR;
+ HasIdentifierAndColour const* largest = get_largest_item(province.get_culture_distribution()).first;
+ return largest != nullptr ? HIGH_ALPHA_VALUE | largest->get_colour() : NULL_COLOUR;
+ } },
+ { "mapmode_religion",
+ [](Map const& map, Province const& province) -> colour_t {
+ HasIdentifierAndColour const* largest = get_largest_item(province.get_religion_distribution()).first;
+ return largest != nullptr ? HIGH_ALPHA_VALUE | largest->get_colour() : NULL_COLOUR;
} }
};
for (mapmode_t const& mapmode : mapmodes)
diff --git a/src/openvic/dataloader/Dataloader.cpp b/src/openvic/dataloader/Dataloader.cpp
index 90537c9..f2b725e 100644
--- a/src/openvic/dataloader/Dataloader.cpp
+++ b/src/openvic/dataloader/Dataloader.cpp
@@ -1,10 +1,10 @@
#include "Dataloader.hpp"
+#include "openvic/GameManager.hpp"
#include "openvic/utility/Logger.hpp"
-#include "openvic//GameManager.hpp"
-#include "openvic/dataloader/NodeTools.hpp"
#include <openvic-dataloader/detail/CallbackOStream.hpp>
+#include <openvic-dataloader/v2script/Parser.hpp>
using namespace OpenVic;
using namespace ovdl::v2script;
@@ -14,19 +14,26 @@ return_t Dataloader::set_roots(std::vector<std::filesystem::path> new_roots) {
Logger::error("Overriding existing dataloader roots!");
roots.clear();
}
+ return_t ret = SUCCESS;
for (std::reverse_iterator<std::vector<std::filesystem::path>::const_iterator> it = new_roots.crbegin(); it != new_roots.crend(); ++it) {
- if (std::filesystem::is_directory(*it)) {
- Logger::info("Adding dataloader root: ", *it);
- roots.push_back(*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 = FAILURE;
+ }
} else {
- Logger::error("Invalid dataloader root (must be an existing directory): ", *it);
+ Logger::error("Duplicate dataloader root: ", *it);
+ ret = FAILURE;
}
}
if (roots.empty()) {
Logger::error("Dataloader has no roots after attempting to add ", new_roots.size());
- return FAILURE;
+ ret = FAILURE;
}
- return SUCCESS;
+ return ret;
}
std::filesystem::path Dataloader::lookup_file(std::filesystem::path const& path) const {
@@ -40,28 +47,52 @@ std::filesystem::path Dataloader::lookup_file(std::filesystem::path const& path)
return {};
}
-static bool contains_file_with_name(std::vector<std::filesystem::path> const& paths, std::filesystem::path const& name) {
+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) const {
+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() && !contains_file_with_name(ret, entry.path().filename())) {
- ret.push_back(entry);
+ 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;
}
-static Parser parse_defines(std::filesystem::path const& path) {
+return_t Dataloader::apply_to_files_in_dir(std::filesystem::path const& path,
+ std::function<return_t(std::filesystem::path const&)> callback,
+ std::filesystem::path const* extension) const {
+
+ return_t ret = SUCCESS;
+ for (std::filesystem::path const& file : lookup_files_in_dir(path, extension)) {
+ if (callback(file) != SUCCESS) {
+ ret = FAILURE;
+ }
+ }
+ return ret;
+}
+
+Parser Dataloader::parse_defines(std::filesystem::path const& path) {
Parser parser;
std::string buffer;
auto error_log_stream = ovdl::detail::CallbackStream {
@@ -81,8 +112,8 @@ static Parser parse_defines(std::filesystem::path const& path) {
Logger::error("Parser load errors:\n\n", buffer, "\n");
buffer.clear();
}
- if (parser.has_fatal_error() || parser.has_error() || parser.has_warning()) {
- Logger::error("Parser warnings/errors while loading ", path);
+ if (parser.has_fatal_error() || parser.has_error()) {
+ Logger::error("Parser errors while loading ", path);
return parser;
}
parser.simple_parse();
@@ -90,51 +121,74 @@ static Parser parse_defines(std::filesystem::path const& path) {
Logger::error("Parser parse errors:\n\n", buffer, "\n");
buffer.clear();
}
- if (parser.has_fatal_error() || parser.has_error() || parser.has_warning()) {
- Logger::error("Parser warnings/errors while parsing ", path);
+ if (parser.has_fatal_error() || parser.has_error()) {
+ Logger::error("Parser errors while parsing ", path);
}
return parser;
}
+Parser Dataloader::parse_defines_lookup(std::filesystem::path const& path) const {
+ return parse_defines(lookup_file(path));
+}
+
+return_t Dataloader::_load_pop_types(PopManager& pop_manager, std::filesystem::path const& pop_type_directory) const {
+ return_t ret = SUCCESS;
+ if (apply_to_files_in_dir(pop_type_directory, [&pop_manager](std::filesystem::path const& file) -> return_t {
+ return pop_manager.load_pop_type_file(file, parse_defines(file).get_file_node());
+ }) != SUCCESS) {
+ Logger::error("Failed to load pop types!");
+ ret = FAILURE;
+ }
+ pop_manager.lock_pop_types();
+ return ret;
+}
+
return_t 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";
return_t ret = SUCCESS;
- if (game_manager.pop_manager.culture_manager.load_graphical_culture_type_file(parse_defines(
- lookup_file(graphical_culture_type_file)).get_file_node()) != SUCCESS) {
+ if (game_manager.good_manager.load_good_file(parse_defines_lookup(good_file).get_file_node()) != SUCCESS) {
+ Logger::error("Failed to load goods!");
+ ret = FAILURE;
+ }
+ if (_load_pop_types(game_manager.pop_manager, pop_type_directory) != SUCCESS) {
+ Logger::error("Failed to load pop types!");
+ ret = FAILURE;
+ }
+ if (game_manager.pop_manager.culture_manager.load_graphical_culture_type_file(parse_defines_lookup(graphical_culture_type_file).get_file_node()) != SUCCESS) {
Logger::error("Failed to load graphical culture types!");
ret = FAILURE;
}
- if (game_manager.pop_manager.culture_manager.load_culture_file(parse_defines(
- lookup_file(culture_file)).get_file_node()) != SUCCESS) {
+ if (game_manager.pop_manager.culture_manager.load_culture_file(parse_defines_lookup(culture_file).get_file_node()) != SUCCESS) {
Logger::error("Failed to load cultures!");
ret = FAILURE;
}
+ if (game_manager.pop_manager.religion_manager.load_religion_file(parse_defines_lookup(religion_file).get_file_node()) != SUCCESS) {
+ Logger::error("Failed to load religions!");
+ ret = FAILURE;
+ }
return ret;
}
-static return_t load_pop_history_file(GameManager& game_manager, std::filesystem::path const& path) {
- return NodeTools::expect_dictionary(parse_defines(path).get_file_node(), [&game_manager](std::string_view province_key, ast::NodeCPtr province_node) -> return_t {
- Province* province = game_manager.map.get_province_by_identifier(province_key);
- if (province == nullptr) {
- Logger::error("Invalid province id: ", province_key);
- return FAILURE;
- }
- return NodeTools::expect_list(province_node, [&game_manager, &province](ast::NodeCPtr pop_node) -> return_t {
- return game_manager.pop_manager.load_pop_into_province(*province, pop_node);
- });
- }, true);
-}
-
return_t Dataloader::load_pop_history(GameManager& game_manager, std::filesystem::path const& path) const {
- return_t ret = SUCCESS;
- for (std::filesystem::path const& file : lookup_files_in_dir(path)) {
- if (load_pop_history_file(game_manager, file) != SUCCESS) {
- ret = FAILURE;
- }
- }
- return ret;
+ return apply_to_files_in_dir(path, [&game_manager](std::filesystem::path const& file) -> return_t {
+ return NodeTools::expect_dictionary(parse_defines(file).get_file_node(),
+ [&game_manager](std::string_view province_key, ast::NodeCPtr province_node) -> return_t {
+ Province* province = game_manager.map.get_province_by_identifier(province_key);
+ if (province == nullptr) {
+ Logger::error("Invalid province id: ", province_key);
+ return FAILURE;
+ }
+ return NodeTools::expect_list(province_node, [&game_manager, &province](ast::NodeCPtr pop_node) -> return_t {
+ return game_manager.pop_manager.load_pop_into_province(*province, pop_node);
+ }
+ );
+ }, true);
+ });
}
diff --git a/src/openvic/dataloader/Dataloader.hpp b/src/openvic/dataloader/Dataloader.hpp
index b080300..3c868a3 100644
--- a/src/openvic/dataloader/Dataloader.hpp
+++ b/src/openvic/dataloader/Dataloader.hpp
@@ -1,14 +1,23 @@
#pragma once
+#include <filesystem>
+
#include "openvic/types/Return.hpp"
+
#include "openvic-dataloader/v2script/Parser.hpp"
namespace OpenVic {
struct GameManager;
+ struct PopManager;
class Dataloader {
std::vector<std::filesystem::path> roots;
+ static ovdl::v2script::Parser parse_defines(std::filesystem::path const& path);
+ ovdl::v2script::Parser parse_defines_lookup(std::filesystem::path const& path) const;
+
+ return_t _load_pop_types(PopManager& pop_manager, std::filesystem::path const& pop_type_directory) const;
+
public:
Dataloader() = default;
@@ -16,7 +25,12 @@ namespace OpenVic {
return_t set_roots(std::vector<std::filesystem::path> new_roots);
std::filesystem::path lookup_file(std::filesystem::path const& path) const;
- std::vector<std::filesystem::path> lookup_files_in_dir(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;
+ return_t apply_to_files_in_dir(std::filesystem::path const& path,
+ std::function<return_t(std::filesystem::path const&)> callback,
+ std::filesystem::path const* extension = &TXT) const;
return_t load_defines(GameManager& game_manager) const;
return_t 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
index a37892f..6ab2ba6 100644
--- a/src/openvic/dataloader/NodeTools.cpp
+++ b/src/openvic/dataloader/NodeTools.cpp
@@ -66,11 +66,9 @@ return_t NodeTools::expect_bool(ast::NodeCPtr node, std::function<return_t(bool)
return_t NodeTools::expect_int(ast::NodeCPtr node, std::function<return_t(int64_t)> callback) {
return expect_identifier(node, [callback](std::string_view identifier) -> return_t {
- int64_t val;
- char const* const start = identifier.data();
- char const* const end = start + identifier.size();
- const std::from_chars_result result = std::from_chars(start, end, val);
- if (result.ec == std::errc{} && result.ptr == end) {
+ 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);
@@ -80,10 +78,9 @@ return_t NodeTools::expect_int(ast::NodeCPtr node, std::function<return_t(int64_
return_t NodeTools::expect_uint(ast::NodeCPtr node, std::function<return_t(uint64_t)> callback) {
return expect_identifier(node, [callback](std::string_view identifier) -> return_t {
- uint64_t val;
- char const* identifier_end = identifier.data() + identifier.size();
- const std::from_chars_result result = std::from_chars(identifier.data(), identifier_end, val);
- if (result.ec == std::errc{} && result.ptr == identifier_end) {
+ 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);
@@ -94,7 +91,7 @@ return_t NodeTools::expect_uint(ast::NodeCPtr node, std::function<return_t(uint6
return_t NodeTools::expect_fixed_point(ast::NodeCPtr node, std::function<return_t(FP)> callback) {
return expect_identifier(node, [callback](std::string_view identifier) -> return_t {
bool successful = false;
- FP val = FP::parse(identifier.data(), identifier.length(), &successful);
+ const FP val = FP::parse(identifier.data(), identifier.length(), &successful);
if (successful) {
return callback(val);
}
@@ -106,7 +103,7 @@ return_t NodeTools::expect_fixed_point(ast::NodeCPtr node, std::function<return_
return_t NodeTools::expect_colour(ast::NodeCPtr node, std::function<return_t(colour_t)> callback) {
colour_t col = NULL_COLOUR;
uint32_t components = 0;
- return_t ret = expect_list(node, std::bind(expect_fixed_point, std::placeholders::_1,
+ return_t ret = expect_list_of_length(node, std::bind(expect_fixed_point, std::placeholders::_1,
[&col, &components](FP val) -> return_t {
return_t ret = SUCCESS;
if (val < 0 || val > 255) {
@@ -127,7 +124,7 @@ return_t NodeTools::expect_colour(ast::NodeCPtr node, std::function<return_t(col
return_t NodeTools::expect_date(ast::NodeCPtr node, std::function<return_t(Date)> callback) {
return expect_identifier(node, [callback](std::string_view identifier) -> return_t {
bool successful = false;
- Date date = Date::from_string(identifier, &successful);
+ const Date date = Date::from_string(identifier, &successful);
if (successful) {
return callback(date);
}
@@ -142,16 +139,16 @@ return_t NodeTools::expect_assign(ast::NodeCPtr node, std::function<return_t(std
});
}
-return_t NodeTools::expect_list(ast::NodeCPtr node, std::function<return_t(ast::NodeCPtr)> callback, size_t length, bool file_node) {
- const std::function<return_t(std::vector<ast::NodeUPtr> const&)> list_func = [length, callback](std::vector<ast::NodeUPtr> const& list) -> return_t {
+return_t NodeTools::expect_list_and_length(ast::NodeCPtr node, std::function<size_t(size_t)> length_callback, std::function<return_t(ast::NodeCPtr)> callback, bool file_node) {
+ const std::function<return_t(std::vector<ast::NodeUPtr> const&)> list_func = [length_callback, callback](std::vector<ast::NodeUPtr> const& list) -> return_t {
return_t ret = SUCCESS;
- size_t size = list.size();
- if (length > 0 && size != length) {
- Logger::error("List length ", size, " does not match expected length ", length);
+ 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 = FAILURE;
- if (length < size) size = length;
}
- std::for_each(list.begin(), list.begin() + size, [callback, &ret](ast::NodeUPtr const& sub_node) {
+ std::for_each(list.begin(), list.begin() + size, [callback, &ret](ast::NodeUPtr const& sub_node) -> void {
if (callback(sub_node.get()) != SUCCESS) ret = FAILURE;
});
return ret;
@@ -167,13 +164,34 @@ return_t NodeTools::expect_list(ast::NodeCPtr node, std::function<return_t(ast::
}
}
-return_t NodeTools::expect_dictionary(ast::NodeCPtr node, std::function<return_t(const std::string_view, ast::NodeCPtr)> callback, bool file_node) {
- return expect_list(node, std::bind(expect_assign, std::placeholders::_1, callback), 0, file_node);
+return_t NodeTools::expect_list_of_length(ast::NodeCPtr node, std::function<return_t(ast::NodeCPtr)> callback, size_t length, bool file_node) {
+ return_t ret = SUCCESS;
+ if (expect_list_and_length(node, [length, &ret](size_t size) -> size_t {
+ if (size != length) {
+ Logger::error("List length ", size, " does not match expected length ", length);
+ ret = FAILURE;
+ if (length < size) return length;
+ }
+ return size;
+ }, callback, file_node) != SUCCESS) ret = FAILURE;
+ return ret;
+}
+
+return_t NodeTools::expect_list(ast::NodeCPtr node, std::function<return_t(ast::NodeCPtr)> callback, bool file_node) {
+ return expect_list_and_length(node, default_length_callback, callback, file_node);
+}
+
+return_t NodeTools::expect_dictionary_and_length(ast::NodeCPtr node, std::function<size_t(size_t)> length_callback, std::function<return_t(std::string_view, ast::NodeCPtr)> callback, bool file_node) {
+ return expect_list_and_length(node, length_callback, std::bind(expect_assign, std::placeholders::_1, callback), file_node);
+}
+
+return_t NodeTools::expect_dictionary(ast::NodeCPtr node, std::function<return_t(std::string_view, ast::NodeCPtr)> callback, bool file_node) {
+ return expect_dictionary_and_length(node, default_length_callback, callback, file_node);
}
return_t NodeTools::expect_dictionary_keys(ast::NodeCPtr node, dictionary_key_map_t const& keys, bool allow_other_keys, bool file_node) {
std::map<std::string, size_t, std::less<void>> key_count;
- return_t ret = expect_dictionary(node, [keys, allow_other_keys, &key_count](const std::string_view key, ast::NodeCPtr value) -> return_t {
+ return_t ret = expect_dictionary(node, [keys, allow_other_keys, &key_count](std::string_view key, ast::NodeCPtr value) -> return_t {
const dictionary_key_map_t::const_iterator it = keys.find(key);
if (it == keys.end()) {
if (allow_other_keys) return SUCCESS;
diff --git a/src/openvic/dataloader/NodeTools.hpp b/src/openvic/dataloader/NodeTools.hpp
index ca7130c..48c3710 100644
--- a/src/openvic/dataloader/NodeTools.hpp
+++ b/src/openvic/dataloader/NodeTools.hpp
@@ -2,13 +2,13 @@
#include <map>
-#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
-
#include "openvic/types/Colour.hpp"
-#include "openvic/types/Return.hpp"
#include "openvic/types/Date.hpp"
+#include "openvic/types/Return.hpp"
#include "openvic/types/fixed_point/FP.hpp"
+#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
+
namespace OpenVic {
namespace ast = ovdl::v2script::ast;
@@ -27,7 +27,24 @@ namespace OpenVic {
return_t expect_colour(ast::NodeCPtr node, std::function<return_t(colour_t)> callback);
return_t expect_date(ast::NodeCPtr node, std::function<return_t(Date)> callback);
return_t expect_assign(ast::NodeCPtr node, std::function<return_t(std::string_view, ast::NodeCPtr)> callback);
- return_t expect_list(ast::NodeCPtr node, std::function<return_t(ast::NodeCPtr)> callback, size_t length = 0, bool file_node = false);
+
+ static const std::function<size_t(size_t)> default_length_callback = [](size_t size) -> size_t { return size; };
+
+ template<typename T> requires requires(T& t) {
+ { t.size() } -> std::same_as<size_t>;
+ t.reserve( size_t {} );
+ }
+ std::function<size_t(size_t)> reserve_length_callback(T& t) {
+ return [&t](size_t size) -> size_t {
+ t.reserve(t.size() + size);
+ return size;
+ };
+ }
+
+ return_t expect_list_and_length(ast::NodeCPtr node, std::function<size_t(size_t)> length_callback, std::function<return_t(ast::NodeCPtr)> callback, bool file_node = false);
+ return_t expect_list_of_length(ast::NodeCPtr node, std::function<return_t(ast::NodeCPtr)> callback, size_t length, bool file_node = false);
+ return_t expect_list(ast::NodeCPtr node, std::function<return_t(ast::NodeCPtr)> callback, bool file_node = false);
+ return_t expect_dictionary_and_length(ast::NodeCPtr node, std::function<size_t(size_t)> length_callback, std::function<return_t(std::string_view, ast::NodeCPtr)> callback, bool file_node = false);
return_t expect_dictionary(ast::NodeCPtr node, std::function<return_t(std::string_view, ast::NodeCPtr)> callback, bool file_node = false);
static const std::function<return_t(ast::NodeCPtr)> success_callback = [](ast::NodeCPtr) -> return_t { return SUCCESS; };
diff --git a/src/openvic/economy/Good.cpp b/src/openvic/economy/Good.cpp
index f14c170..fe92e4f 100644
--- a/src/openvic/economy/Good.cpp
+++ b/src/openvic/economy/Good.cpp
@@ -4,7 +4,9 @@
using namespace OpenVic;
-Good::Good(const std::string_view new_identifier, colour_t new_colour, const std::string_view new_category, price_t new_base_price,
+GoodCategory::GoodCategory(const std::string_view new_identifier) : HasIdentifier { new_identifier } {}
+
+Good::Good(const std::string_view new_identifier, colour_t new_colour, GoodCategory const& new_category, price_t new_base_price,
bool new_default_available, bool new_tradeable, bool new_currency, bool new_overseas_maintenance)
: HasIdentifierAndColour { new_identifier, new_colour, true },
category { new_category },
@@ -16,7 +18,7 @@ Good::Good(const std::string_view new_identifier, colour_t new_colour, const std
assert(base_price > NULL_PRICE);
}
-std::string const& Good::get_category() const {
+GoodCategory const& Good::get_category() const {
return category;
}
@@ -41,9 +43,25 @@ void Good::reset_to_defaults() {
price = base_price;
}
-GoodManager::GoodManager() : goods { "goods" } {}
+GoodManager::GoodManager() : good_categories { "good categories" }, goods { "goods" } {}
+
+return_t GoodManager::add_good_category(const std::string_view identifier) {
+ if (identifier.empty()) {
+ Logger::error("Invalid good category identifier - empty!");
+ return FAILURE;
+ }
+ return good_categories.add_item({ identifier });
+}
+
+void GoodManager::lock_good_categories() {
+ good_categories.lock();
+}
+
+GoodCategory const* GoodManager::get_good_category_by_identifier(const std::string_view identifier) const {
+ return good_categories.get_item_by_identifier(identifier);
+}
-return_t GoodManager::add_good(const std::string_view identifier, colour_t colour, const std::string_view category,
+return_t GoodManager::add_good(const std::string_view identifier, colour_t colour, GoodCategory const* category,
Good::price_t base_price, bool default_available, bool tradeable, bool currency, bool overseas_maintenance) {
if (identifier.empty()) {
Logger::error("Invalid good identifier - empty!");
@@ -53,26 +71,21 @@ return_t GoodManager::add_good(const std::string_view identifier, colour_t colou
Logger::error("Invalid good colour for ", identifier, ": ", Good::colour_to_hex_string(colour));
return FAILURE;
}
- if (category.empty()) {
- Logger::error("Invalid good category for ", identifier, ": empty!");
+ if (category == nullptr) {
+ Logger::error("Invalid good category for ", identifier, ": null");
return FAILURE;
}
if (base_price <= Good::NULL_PRICE) {
Logger::error("Invalid base price for ", identifier, ": ", base_price);
return FAILURE;
}
- return goods.add_item({ identifier, colour, category, base_price, default_available, tradeable, currency, overseas_maintenance });
+ return goods.add_item({ identifier, colour, *category, base_price, default_available, tradeable, currency, overseas_maintenance });
}
void GoodManager::lock_goods() {
goods.lock();
}
-void GoodManager::reset_to_defaults() {
- for (Good& good : goods.get_items())
- good.reset_to_defaults();
-}
-
Good const* GoodManager::get_good_by_index(size_t index) const {
return goods.get_item_by_index(index);
}
@@ -82,9 +95,26 @@ Good const* GoodManager::get_good_by_identifier(const std::string_view identifie
}
size_t GoodManager::get_good_count() const {
- return goods.get_item_count();
+ return goods.size();
}
std::vector<Good> const& GoodManager::get_goods() const {
return goods.get_items();
}
+
+void GoodManager::reset_to_defaults() {
+ for (Good& good : goods.get_items())
+ good.reset_to_defaults();
+}
+
+return_t GoodManager::load_good_file(ast::NodeCPtr root) {
+
+ // TODO - good loading
+
+ return_t ret = add_good_category("test_good_category");
+ lock_good_categories();
+ if (add_good("test_good", 0x00FF00, get_good_category_by_identifier("test_good_category"), FP::_0_99(), true, true, false, false) != SUCCESS)
+ ret = FAILURE;
+ lock_goods();
+ return ret;
+}
diff --git a/src/openvic/economy/Good.hpp b/src/openvic/economy/Good.hpp
index 5c8e68c..a3cd10b 100644
--- a/src/openvic/economy/Good.hpp
+++ b/src/openvic/economy/Good.hpp
@@ -1,11 +1,21 @@
#pragma once
#include "openvic/types/IdentifierRegistry.hpp"
-#include "openvic/types/fixed_point/FP.hpp"
+#include "openvic/dataloader/NodeTools.hpp"
namespace OpenVic {
struct GoodManager;
+ struct GoodCategory : HasIdentifier {
+ friend struct GoodManager;
+
+ private:
+ GoodCategory(const std::string_view new_identifier);
+
+ public:
+ GoodCategory(GoodCategory&&) = default;
+ };
+
/* REQUIREMENTS:
*
* ECON-3 , ECON-4 , ECON-5 , ECON-6 , ECON-7 , ECON-8 , ECON-9 , ECON-10, ECON-11, ECON-12, ECON-13, ECON-14,
@@ -25,19 +35,19 @@ namespace OpenVic {
static constexpr price_t NULL_PRICE = FP::_0();
private:
- const std::string category;
+ GoodCategory const& category;
const price_t base_price;
price_t price;
const bool default_available, tradeable, currency, overseas_maintenance;
bool available;
- Good(const std::string_view new_identifier, colour_t new_colour, const std::string_view new_category, price_t new_base_price,
+ Good(const std::string_view new_identifier, colour_t new_colour, GoodCategory const& new_category, price_t new_base_price,
bool new_default_available, bool new_tradeable, bool new_currency, bool new_overseas_maintenance);
public:
Good(Good&&) = default;
- std::string const& get_category() const;
+ GoodCategory const& get_category() const;
price_t get_base_price() const;
price_t get_price() const;
bool is_default_available() const;
@@ -47,19 +57,25 @@ namespace OpenVic {
struct GoodManager {
private:
+ IdentifierRegistry<GoodCategory> good_categories;
IdentifierRegistry<Good> goods;
public:
GoodManager();
- return_t add_good(const std::string_view identifier, colour_t colour, const std::string_view category, Good::price_t base_price,
+ return_t add_good_category(const std::string_view identifier);
+ void lock_good_categories();
+ GoodCategory const* get_good_category_by_identifier(const std::string_view identifier) const;
+
+ return_t add_good(const std::string_view identifier, colour_t colour, GoodCategory const* category, Good::price_t base_price,
bool default_available, bool tradeable, bool currency, bool overseas_maintenance);
void lock_goods();
- void reset_to_defaults();
-
Good const* get_good_by_index(size_t index) const;
Good const* get_good_by_identifier(const std::string_view identifier) const;
size_t get_good_count() const;
std::vector<Good> const& get_goods() const;
+
+ void reset_to_defaults();
+ return_t load_good_file(ast::NodeCPtr root);
};
}
diff --git a/src/openvic/map/Building.cpp b/src/openvic/map/Building.cpp
index d2662c4..00e0135 100644
--- a/src/openvic/map/Building.cpp
+++ b/src/openvic/map/Building.cpp
@@ -2,8 +2,8 @@
#include <cassert>
-#include "openvic/utility/Logger.hpp"
#include "openvic/map/Province.hpp"
+#include "openvic/utility/Logger.hpp"
using namespace OpenVic;
diff --git a/src/openvic/map/Map.cpp b/src/openvic/map/Map.cpp
index 95d94fd..c9dd9d2 100644
--- a/src/openvic/map/Map.cpp
+++ b/src/openvic/map/Map.cpp
@@ -31,7 +31,7 @@ Map::Map() : provinces { "provinces" },
mapmodes { "mapmodes" } {}
return_t Map::add_province(const std::string_view identifier, colour_t colour) {
- if (provinces.get_item_count() >= Province::MAX_INDEX) {
+ if (provinces.size() >= Province::MAX_INDEX) {
Logger::error("The map's province list is full - there can be at most ", Province::MAX_INDEX, " provinces");
return FAILURE;
}
@@ -43,7 +43,7 @@ return_t Map::add_province(const std::string_view identifier, colour_t colour) {
Logger::error("Invalid province colour for ", identifier, ": ", Province::colour_to_hex_string(colour));
return FAILURE;
}
- Province new_province { identifier, colour, static_cast<Province::index_t>(provinces.get_item_count() + 1) };
+ Province new_province { identifier, colour, static_cast<Province::index_t>(provinces.size() + 1) };
const Province::index_t index = get_index_from_colour(colour);
if (index != Province::NULL_INDEX) {
Logger::error("Duplicate province colours: ", get_province_by_index(index)->to_string(), " and ", new_province.to_string());
@@ -101,7 +101,7 @@ return_t Map::add_region(const std::string_view identifier, std::vector<std::str
size_t other_region_index = reinterpret_cast<size_t>(province->get_region());
if (other_region_index != 0) {
other_region_index--;
- if (other_region_index < regions.get_item_count())
+ if (other_region_index < regions.size())
Logger::error("Cannot add province ", province_identifier, " to region ", identifier, " - it is already part of ", regions.get_item_by_index(other_region_index)->get_identifier());
else
Logger::error("Cannot add province ", province_identifier, " to region ", identifier, " - it is already part of an unknown region with index ", other_region_index);
@@ -124,7 +124,7 @@ return_t Map::add_region(const std::string_view identifier, std::vector<std::str
// Used to detect provinces listed in multiple regions, will
// be corrected once regions is stable (i.e. lock_regions).
- Region* tmp_region_index = reinterpret_cast<Region*>(regions.get_item_count());
+ Region* tmp_region_index = reinterpret_cast<Region*>(regions.size());
for (Province* province : new_region.get_provinces())
province->region = tmp_region_index;
if (regions.add_item(std::move(new_region)) != SUCCESS) ret = FAILURE;
@@ -139,7 +139,7 @@ void Map::lock_regions() {
}
size_t Map::get_province_count() const {
- return provinces.get_item_count();
+ return provinces.size();
}
Province* Map::get_province_by_index(Province::index_t index) {
@@ -225,7 +225,7 @@ return_t Map::generate_province_shape_image(size_t new_width, size_t new_height,
height = new_height;
province_shape_image.resize(width * height);
- std::vector<bool> province_checklist(provinces.get_item_count());
+ std::vector<bool> province_checklist(provinces.size());
return_t ret = SUCCESS;
std::unordered_set<colour_t> unrecognised_province_colours, unrecognised_terrain_colours;
@@ -324,7 +324,7 @@ return_t Map::add_mapmode(const std::string_view identifier, Mapmode::colour_fun
Logger::error("Mapmode colour function is null for identifier: ", identifier);
return FAILURE;
}
- return mapmodes.add_item({ identifier, mapmodes.get_item_count(), colour_func });
+ return mapmodes.add_item({ identifier, mapmodes.size(), colour_func });
}
void Map::lock_mapmodes() {
@@ -332,7 +332,7 @@ void Map::lock_mapmodes() {
}
size_t Map::get_mapmode_count() const {
- return mapmodes.get_item_count();
+ return mapmodes.size();
}
Mapmode const* Map::get_mapmode_by_index(size_t index) const {
@@ -354,7 +354,7 @@ return_t Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target)
// Not an error if mapmodes haven't yet been loaded,
// e.g. if we want to allocate the province colour
// texture before mapmodes are loaded.
- if (!(mapmodes.get_item_count() == 0 && index == 0)) {
+ if (!(mapmodes.size() == 0 && index == 0)) {
Logger::error("Invalid mapmode index: ", index);
ret = FAILURE;
}
diff --git a/src/openvic/map/Province.cpp b/src/openvic/map/Province.cpp
index 76e478f..f4588d4 100644
--- a/src/openvic/map/Province.cpp
+++ b/src/openvic/map/Province.cpp
@@ -91,6 +91,10 @@ distribution_t const& Province::get_culture_distribution() const {
return cultures;
}
+distribution_t const& Province::get_religion_distribution() const {
+ return religions;
+}
+
/* REQUIREMENTS:
* MAP-65
*/
@@ -98,10 +102,12 @@ void Province::update_pops() {
total_population = 0;
pop_types.clear();
cultures.clear();
+ religions.clear();
for (Pop const& pop : pops) {
total_population += pop.get_size();
pop_types[&pop.get_type()] += pop.get_size();
cultures[&pop.get_culture()] += pop.get_size();
+ religions[&pop.get_religion()] += pop.get_size();
}
}
diff --git a/src/openvic/map/Province.hpp b/src/openvic/map/Province.hpp
index 3556bcb..527a6fe 100644
--- a/src/openvic/map/Province.hpp
+++ b/src/openvic/map/Province.hpp
@@ -1,7 +1,7 @@
#pragma once
-#include "openvic/pop/Pop.hpp"
#include "openvic/map/Building.hpp"
+#include "openvic/pop/Pop.hpp"
namespace OpenVic {
struct Map;
@@ -30,7 +30,7 @@ namespace OpenVic {
std::vector<Pop> pops;
Pop::pop_size_t total_population;
- distribution_t pop_types, cultures;
+ distribution_t pop_types, cultures, religions;
Province(const std::string_view new_identifier, colour_t new_colour, index_t new_index);
@@ -55,6 +55,7 @@ namespace OpenVic {
Pop::pop_size_t get_total_population() const;
distribution_t const& get_pop_type_distribution() const;
distribution_t const& get_culture_distribution() const;
+ distribution_t const& get_religion_distribution() const;
void update_pops();
void update_state(Date const& today);
diff --git a/src/openvic/pop/Culture.cpp b/src/openvic/pop/Culture.cpp
index 3bfb9b9..b0c04c2 100644
--- a/src/openvic/pop/Culture.cpp
+++ b/src/openvic/pop/Culture.cpp
@@ -101,11 +101,13 @@ Culture const* CultureManager::get_culture_by_identifier(const std::string_view
}
return_t CultureManager::load_graphical_culture_type_file(ast::NodeCPtr root) {
- const return_t ret = NodeTools::expect_list(root, [this](ast::NodeCPtr node) -> return_t {
- return NodeTools::expect_identifier(node, [this](std::string_view identifier) -> return_t {
- return add_graphical_culture_type(identifier);
- });
- }, 0, true);
+ const return_t ret = NodeTools::expect_list_and_length(root,
+ NodeTools::reserve_length_callback(graphical_culture_types),
+ [this](ast::NodeCPtr node) -> return_t {
+ return NodeTools::expect_identifier(node, [this](std::string_view identifier) -> return_t {
+ return add_graphical_culture_type(identifier);
+ });
+ }, true);
lock_graphical_culture_types();
return ret;
}
@@ -156,21 +158,25 @@ return_t CultureManager::load_culture_file(ast::NodeCPtr root) {
return NodeTools::expect_dictionary(culture_group_value, [this, culture_group](std::string_view key, ast::NodeCPtr value) -> return_t {
if (key == "leader" || key == "unit" || key == "union" || key == "is_overseas") return SUCCESS;
- colour_t colour = NULL_COLOUR;
+ colour_t colour = NULL_COLOUR;
Culture::name_list_t first_names, last_names;
- static const std::function<return_t(Culture::name_list_t&, ast::NodeCPtr)> read_name_list = [](Culture::name_list_t& names, ast::NodeCPtr node) -> return_t {
- return NodeTools::expect_list(node, [&names](ast::NodeCPtr val) -> return_t {
- return NodeTools::expect_identifier_or_string(val, [&names](std::string_view str) -> return_t {
- if (!str.empty()) {
- names.push_back(std::string { str });
- return SUCCESS;
+ static const std::function<return_t(Culture::name_list_t&, ast::NodeCPtr)> read_name_list =
+ [](Culture::name_list_t& names, ast::NodeCPtr node) -> return_t {
+ return NodeTools::expect_list_and_length(node,
+ NodeTools::reserve_length_callback(names),
+ [&names](ast::NodeCPtr val) -> return_t {
+ return NodeTools::expect_identifier_or_string(val, [&names](std::string_view str) -> return_t {
+ if (!str.empty()) {
+ names.push_back(std::string { str });
+ return SUCCESS;
+ }
+ Logger::error("Empty identifier or string");
+ return FAILURE;
+ });
}
- Logger::error("Empty identifier or string");
- return FAILURE;
- });
- });
- };
+ );
+ };
return_t ret = NodeTools::expect_dictionary_keys(value, {
{ "color", { true, false, [&colour](ast::NodeCPtr node) -> return_t {
diff --git a/src/openvic/pop/Culture.hpp b/src/openvic/pop/Culture.hpp
index 7012512..495ba1d 100644
--- a/src/openvic/pop/Culture.hpp
+++ b/src/openvic/pop/Culture.hpp
@@ -1,7 +1,7 @@
#pragma once
-#include "openvic/types/IdentifierRegistry.hpp"
#include "openvic/dataloader/NodeTools.hpp"
+#include "openvic/types/IdentifierRegistry.hpp"
namespace OpenVic {
@@ -72,7 +72,7 @@ namespace OpenVic {
void lock_cultures();
Culture const* get_culture_by_identifier(const std::string_view identifier) const;
- return_t load_graphical_culture_type_file(ast::NodeCPtr node);
- return_t load_culture_file(ast::NodeCPtr node);
+ return_t load_graphical_culture_type_file(ast::NodeCPtr root);
+ return_t load_culture_file(ast::NodeCPtr root);
};
}
diff --git a/src/openvic/pop/Pop.cpp b/src/openvic/pop/Pop.cpp
index 710d3e0..445aec3 100644
--- a/src/openvic/pop/Pop.cpp
+++ b/src/openvic/pop/Pop.cpp
@@ -98,27 +98,7 @@ bool PopType::get_is_slave() const {
return is_slave;
}
-static const std::string test_graphical_culture_type = "test_graphical_culture_type";
-static const std::string test_culture_group = "test_culture_group";
-static const std::string test_culture = "test_culture";
-static const std::string test_religion_group = "test_religion_group";
-static const std::string test_religion = "test_religion";
-static const std::string test_pop_type_poor = "test_pop_type_poor";
-static const std::string test_pop_type_middle = "test_pop_type_middle";
-static const std::string test_pop_type_rich = "test_pop_type_rich";
-
-PopManager::PopManager() : pop_types { "pop types" } {
- religion_manager.add_religion_group(test_religion_group);
- religion_manager.lock_religion_groups();
-
- religion_manager.add_religion(test_religion, 0xFF0000, religion_manager.get_religion_group_by_identifier(test_religion_group), 1, false);
- religion_manager.lock_religions();
-
- add_pop_type(test_pop_type_poor, 0xFF0000, PopType::strata_t::POOR, 1, 1, 1, false, false, false, false);
- add_pop_type(test_pop_type_middle, 0x00FF00, PopType::strata_t::MIDDLE, 1, 1, 1, false, false, false, false);
- add_pop_type(test_pop_type_rich, 0x0000FF, PopType::strata_t::RICH, 1, 1, 1, false, false, false, false);
- lock_pop_types();
-}
+PopManager::PopManager() : pop_types { "pop types" } {}
return_t PopManager::add_pop_type(const std::string_view identifier, colour_t colour, PopType::strata_t strata, PopType::sprite_t sprite,
Pop::pop_size_t max_size, Pop::pop_size_t merge_max_size, bool state_capital_only, bool demote_migrant, bool is_artisan, bool is_slave) {
@@ -153,8 +133,17 @@ PopType const* PopManager::get_pop_type_by_identifier(const std::string_view ide
return pop_types.get_item_by_identifier(identifier);
}
+return_t PopManager::load_pop_type_file(std::filesystem::path const& path, ast::NodeCPtr root) {
+
+ // TODO - pop type loading
+
+ if (pop_types.empty())
+ return add_pop_type("test_pop_type", 0xFF0000, PopType::strata_t::POOR, 1, 1, 1, false, false, false, false);
+ return SUCCESS;
+}
+
return_t PopManager::load_pop_into_province(Province& province, ast::NodeCPtr root) const {
- static PopType const* type = get_pop_type_by_identifier("test_pop_type_poor");
+ static PopType const* type = get_pop_type_by_identifier("test_pop_type");
Culture const* culture = nullptr;
static Religion const* religion = religion_manager.get_religion_by_identifier("test_religion");
Pop::pop_size_t size = 0;
@@ -176,8 +165,7 @@ return_t PopManager::load_pop_into_province(Province& province, ast::NodeCPtr ro
size = val;
return SUCCESS;
} else {
- Logger::error("Invalid pop size: ", val, " (setting to 1 instead)");
- size = 1;
+ Logger::error("Invalid pop size: ", val);
return FAILURE;
}
});
@@ -190,7 +178,7 @@ return_t PopManager::load_pop_into_province(Province& province, ast::NodeCPtr ro
if (type != nullptr && culture != nullptr && religion != nullptr && size > 0) {
if (province.add_pop({ *type, *culture, *religion, size }) != SUCCESS) ret = FAILURE;
} else {
- Logger::error("Some pop arguments are missing: type = ", type, ", culture = ", culture, ", religion = ", religion, ", size = ", size);
+ Logger::error("Some pop arguments are invalid: type = ", type, ", culture = ", culture, ", religion = ", religion, ", size = ", size);
ret = FAILURE;
}
return ret;
diff --git a/src/openvic/pop/Pop.hpp b/src/openvic/pop/Pop.hpp
index f5a7c4e..144d53c 100644
--- a/src/openvic/pop/Pop.hpp
+++ b/src/openvic/pop/Pop.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include <filesystem>
+
#include "openvic/pop/Culture.hpp"
#include "openvic/pop/Religion.hpp"
@@ -94,6 +96,7 @@ namespace OpenVic {
void lock_pop_types();
PopType const* get_pop_type_by_identifier(const std::string_view identifier) const;
+ return_t load_pop_type_file(std::filesystem::path const& path, ast::NodeCPtr root);
return_t load_pop_into_province(Province& province, ast::NodeCPtr root) const;
};
}
diff --git a/src/openvic/pop/Religion.cpp b/src/openvic/pop/Religion.cpp
index 0cfc7a6..8ff143f 100644
--- a/src/openvic/pop/Religion.cpp
+++ b/src/openvic/pop/Religion.cpp
@@ -78,3 +78,15 @@ void ReligionManager::lock_religions() {
Religion const* ReligionManager::get_religion_by_identifier(const std::string_view identifier) const {
return religions.get_item_by_identifier(identifier);
}
+
+return_t ReligionManager::load_religion_file(ast::NodeCPtr root) {
+
+ // TODO - religion loading
+
+ return_t ret = add_religion_group("test_religion_group");
+ lock_religion_groups();
+ if (add_religion("test_religion", 0xFF0000, get_religion_group_by_identifier("test_religion_group"), 1, false) != SUCCESS)
+ ret = FAILURE;
+ lock_religions();
+ return ret;
+}
diff --git a/src/openvic/pop/Religion.hpp b/src/openvic/pop/Religion.hpp
index e629977..730454e 100644
--- a/src/openvic/pop/Religion.hpp
+++ b/src/openvic/pop/Religion.hpp
@@ -1,6 +1,7 @@
#pragma once
#include "openvic/types/IdentifierRegistry.hpp"
+#include "openvic/dataloader/NodeTools.hpp"
namespace OpenVic {
@@ -50,5 +51,7 @@ namespace OpenVic {
return_t add_religion(const std::string_view identifier, colour_t colour, ReligionGroup const* group, Religion::icon_t icon, bool pagan);
void lock_religions();
Religion const* get_religion_by_identifier(const std::string_view identifier) const;
+
+ return_t load_religion_file(ast::NodeCPtr root);
};
}
diff --git a/src/openvic/types/Date.cpp b/src/openvic/types/Date.cpp
index b6e1367..1f13808 100644
--- a/src/openvic/types/Date.cpp
+++ b/src/openvic/types/Date.cpp
@@ -6,6 +6,7 @@
#include <charconv>
#include "openvic/utility/Logger.hpp"
+#include "openvic/utility/StringUtils.hpp"
using namespace OpenVic;
@@ -55,12 +56,16 @@ Timespan::operator double() const {
return days;
}
-Timespan::operator std::string() const {
+std::string Timespan::to_string() const {
return std::to_string(days);
}
+Timespan::operator std::string() const {
+ return to_string();
+}
+
std::ostream& OpenVic::operator<<(std::ostream& out, Timespan const& timespan) {
- return out << static_cast<std::string>(timespan);
+ return out << timespan.to_string();
}
Timespan Date::_dateToTimespan(year_t year, month_t month, day_t day) {
@@ -146,95 +151,112 @@ Date Date::operator++(int) {
return old;
}
-Date::operator std::string() const {
+std::string Date::to_string() const {
std::stringstream ss;
ss << *this;
return ss.str();
}
+Date::operator std::string() const {
+ return to_string();
+}
+
std::ostream& OpenVic::operator<<(std::ostream& out, Date const& date) {
- return out << static_cast<int>(date.getYear()) << '.' << static_cast<int>(date.getMonth()) << '.' << static_cast<int>(date.getDay());
+ return out << static_cast<int>(date.getYear()) << Date::SEPARATOR_CHARACTER << static_cast<int>(date.getMonth()) << Date::SEPARATOR_CHARACTER << static_cast<int>(date.getDay());
}
// Parsed from string of the form YYYY.MM.DD
-Date Date::from_string(const std::string_view date, bool* successful) {
+Date Date::from_string(char const* const str, char const* const end, bool* successful) {
if (successful != nullptr) *successful = true;
- size_t first_pos = 0;
- while (first_pos < date.length() && std::isdigit(date[first_pos])) {
- first_pos++;
+
+ year_t year = 0;
+ month_t month = 1;
+ day_t day = 1;
+
+ if (str == nullptr || end <= str) {
+ Logger::error("Invalid string start/end pointers: ", static_cast<void const*>(str), " - ", static_cast<void const*>(end));
+ if (successful != nullptr) *successful = false;
+ return { year, month, day };
}
- if (first_pos == 0) {
- Logger::error("Failed to find year digits in date: ", date);
+ char const* year_end = str;
+ while (std::isdigit(*year_end) && ++year_end < end);
+
+ if (year_end <= str) {
+ Logger::error("Failed to find year digits in date: ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
- return {};
+ return { year, month, day };
}
- int val = 0;
- char const* start = date.data();
- char const* end = start + first_pos;
- std::from_chars_result result = std::from_chars(start, end, val);
- if (result.ec != std::errc{} || result.ptr != end || val < 0 || val >= 1 << (8 * sizeof(year_t))) {
- Logger::error("Failed to read year: ", date);
+ bool sub_successful = false;
+ uint64_t val = StringUtils::string_to_uint64(str, year_end, &sub_successful, 10);
+ if (!sub_successful || val >= 1 << (8 * sizeof(year_t))) {
+ Logger::error("Failed to read year: ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
- return {};
+ return { year, month, day };
}
- year_t year = val;
- month_t month = 1;
- day_t day = 1;
- if (first_pos < date.length()) {
- if (date[first_pos] == '.') {
- size_t second_pos = ++first_pos;
- while (second_pos < date.length() && std::isdigit(date[second_pos])) {
- second_pos++;
+ year = val;
+ if (year_end < end) {
+ if (*year_end == SEPARATOR_CHARACTER) {
+ char const* const month_start = year_end + 1;
+ char const* month_end = month_start;
+ if (month_start < end) {
+ while (std::isdigit(*month_end) && ++month_end < end);
}
- if (first_pos == second_pos) {
- Logger::error("Failed to find month digits in date: ", date);
+ if (month_start >= month_end) {
+ Logger::error("Failed to find month digits in date: ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
} else {
- start = date.data() + first_pos;
- end = date.data() + second_pos;
- result = std::from_chars(start, end, val);
- if (result.ec != std::errc{} || result.ptr != end || val < 1 || val > MONTHS_IN_YEAR) {
- Logger::error("Failed to read month: ", date);
+ sub_successful = false;
+ val = StringUtils::string_to_uint64(month_start, month_end, &sub_successful, 10);
+ if (!sub_successful || val < 1 || val > MONTHS_IN_YEAR) {
+ Logger::error("Failed to read month: ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
} else {
month = val;
- if (second_pos < date.length()) {
- if (date[second_pos] == '.') {
- size_t third_pos = ++second_pos;
- while (third_pos < date.length() && std::isdigit(date[third_pos])) {
- third_pos++;
+ if (month_end < end) {
+ if (*month_end == SEPARATOR_CHARACTER) {
+ char const* const day_start = month_end + 1;
+ char const* day_end = day_start;
+ if (day_start < end) {
+ while (std::isdigit(*day_end) && ++day_end < end);
}
- if (second_pos == third_pos) {
- Logger::error("Failed to find day digits in date: ", date);
+ if (day_start >= day_end) {
+ Logger::error("Failed to find day digits in date: ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
} else {
- start = date.data() + second_pos;
- end = date.data() + third_pos;
- result = std::from_chars(start, end, val);
- if (result.ec != std::errc{} || result.ptr != end || val < 1 || val > DAYS_IN_MONTH[month - 1]) {
- Logger::error("Failed to read day: ", date);
+ sub_successful = false;
+ val = StringUtils::string_to_uint64(day_start, day_end, &sub_successful);
+ if (!sub_successful || val < 1 || val > DAYS_IN_MONTH[month - 1]) {
+ Logger::error("Failed to read day: ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
} else {
day = val;
- if (third_pos < date.length()) {
- Logger::error("Unexpected string \"", date.substr(third_pos), "\" at the end of date ", date);
+ if (day_end < end) {
+ Logger::error("Unexpected string \"", std::string_view { day_end, static_cast<size_t>(end - day_end) }, "\" at the end of date ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
}
}
}
} else {
- Logger::error("Unexpected character \"", date[second_pos], "\" in month of date ", date);
+ Logger::error("Unexpected character \"", *month_end, "\" in month of date ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
}
}
}
}
} else {
- Logger::error("Unexpected character \"", date[first_pos], "\" in year of date ", date);
+ Logger::error("Unexpected character \"", *year_end, "\" in year of date ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
}
}
- return _dateToTimespan(year, month, day);
+ return { year, month, day };
};
+
+Date Date::from_string(char const* str, size_t length, bool* successful) {
+ return from_string(str, str + length, successful);
+}
+
+Date Date::from_string(const std::string_view str, bool* successful) {
+ return from_string(str.data(), str.length(), successful);
+}
diff --git a/src/openvic/types/Date.hpp b/src/openvic/types/Date.hpp
index ca5645c..601f9dc 100644
--- a/src/openvic/types/Date.hpp
+++ b/src/openvic/types/Date.hpp
@@ -33,6 +33,7 @@ namespace OpenVic {
explicit operator day_t() const;
explicit operator double() const;
+ std::string to_string() const;
explicit operator std::string() const;
};
std::ostream& operator<<(std::ostream& out, Timespan const& timespan);
@@ -50,6 +51,8 @@ namespace OpenVic {
static Timespan::day_t const* DAYS_UP_TO_MONTH;
static month_t const* MONTH_FROM_DAY_IN_YEAR;
+ static constexpr char SEPARATOR_CHARACTER = '.';
+
private:
// Number of days since Jan 1st, Year 0
Timespan timespan;
@@ -82,9 +85,12 @@ namespace OpenVic {
Date& operator++();
Date operator++(int);
+ std::string to_string() const;
explicit operator std::string() const;
// Parsed from string of the form YYYY.MM.DD
- static Date from_string(const std::string_view date, bool* successful = nullptr);
+ static Date from_string(char const* str, char const* end, bool* successful = nullptr);
+ static Date from_string(char const* str, size_t length, bool* successful = nullptr);
+ static Date from_string(const std::string_view str, bool* successful = nullptr);
};
std::ostream& operator<<(std::ostream& out, Date const& date);
}
diff --git a/src/openvic/types/IdentifierRegistry.cpp b/src/openvic/types/IdentifierRegistry.cpp
index 97a1ff5..3710387 100644
--- a/src/openvic/types/IdentifierRegistry.cpp
+++ b/src/openvic/types/IdentifierRegistry.cpp
@@ -35,3 +35,11 @@ HasIdentifierAndColour::HasIdentifierAndColour(const std::string_view new_identi
const colour_t new_colour, bool can_be_null)
: HasIdentifier { new_identifier },
HasColour { new_colour, can_be_null } {}
+
+distribution_t::value_type OpenVic::get_largest_item(distribution_t const& dist) {
+ const distribution_t::const_iterator result = std::max_element(dist.begin(), dist.end(),
+ [](distribution_t::value_type a, distribution_t::value_type b) -> bool {
+ return a.second < b.second;
+ });
+ return result != dist.end() ? *result : distribution_t::value_type { nullptr, -1.0f };
+}
diff --git a/src/openvic/types/IdentifierRegistry.hpp b/src/openvic/types/IdentifierRegistry.hpp
index e5ac94b..989db01 100644
--- a/src/openvic/types/IdentifierRegistry.hpp
+++ b/src/openvic/types/IdentifierRegistry.hpp
@@ -64,7 +64,9 @@ namespace OpenVic {
HasIdentifierAndColour& operator=(HasIdentifierAndColour&&) = delete;
};
- using distribution_t = std::unordered_map<HasIdentifierAndColour const*, float>;
+ using distribution_t = std::map<HasIdentifierAndColour const*, float>;
+
+ distribution_t::value_type get_largest_item(distribution_t const& dist);
/*
* Template for a list of objects with unique string identifiers that can
@@ -102,7 +104,7 @@ namespace OpenVic {
Logger::error("Failed to lock ", name, " registry - already locked!");
} else {
locked = true;
- if (log) Logger::info("Locked ", name, " registry after registering ", get_item_count(), " items");
+ if (log) Logger::info("Locked ", name, " registry after registering ", size(), " items");
}
}
bool is_locked() const {
@@ -113,9 +115,19 @@ namespace OpenVic {
items.clear();
locked = false;
}
- size_t get_item_count() const {
+ size_t size() const {
return items.size();
}
+ bool empty() const {
+ return items.empty();
+ }
+ void reserve(size_t size) {
+ if (locked) {
+ Logger::error("Failed to reserve space for ", size, " items in ", name, " registry - already locked!");
+ } else {
+ items.reserve(size);
+ }
+ }
T* get_item_by_identifier(const std::string_view identifier) {
const identifier_index_map_t::const_iterator it = identifier_index_map.find(identifier);
if (it != identifier_index_map.end()) return &items[it->second];
diff --git a/src/openvic/types/fixed_point/FP.hpp b/src/openvic/types/fixed_point/FP.hpp
index 8b32906..42ddf79 100644
--- a/src/openvic/types/fixed_point/FP.hpp
+++ b/src/openvic/types/fixed_point/FP.hpp
@@ -1,16 +1,17 @@
#pragma once
-#include <cstdint>
-#include <cstdlib>
#include <cerrno>
#include <cmath>
+#include <cstdint>
+#include <cstdlib>
#include <limits>
-#include <cstring>
+#include <string_view>
-#include "FPLUT.hpp"
-#include "openvic/utility/FloatUtils.hpp"
-#include "openvic/utility/StringUtils.hpp"
#include "openvic/utility/Logger.hpp"
+#include "openvic/utility/NumberUtils.hpp"
+#include "openvic/utility/StringUtils.hpp"
+
+#include "FPLUT.hpp"
namespace OpenVic {
struct FP {
@@ -41,7 +42,7 @@ namespace OpenVic {
static constexpr FP _0() {
return 0;
- }
+ }
static constexpr FP _1() {
return 1;
@@ -195,13 +196,17 @@ namespace OpenVic {
return static_cast<int64_t>(178145LL);
}
+ constexpr bool is_negative() const {
+ return value < 0;
+ }
+
constexpr FP abs() const {
- return value >= 0 ? value : -value;
+ return !is_negative() ? value : -value;
}
- // Not including sign, so -1.1 -> 0.1
+ // Doesn't account for sign, so -n.abc -> 1 - 0.abc
constexpr FP get_frac() const {
- return abs().value & ((1 << FPLUT::PRECISION) - 1);
+ return value & (FPLUT::ONE - 1);
}
constexpr int64_t to_int64_t() const {
@@ -217,33 +222,35 @@ namespace OpenVic {
}
constexpr int32_t to_int32_t() const {
- return static_cast<int32_t>(value >> FPLUT::PRECISION);
+ return static_cast<int32_t>(to_int64_t());
}
constexpr float to_float() const {
- return value / 65536.0F;
+ return value / static_cast<float>(FPLUT::ONE);
}
constexpr float to_float_rounded() const {
- return static_cast<float>(FloatUtils::round_to_int64((value / 65536.0F) * 100000.0F)) / 100000.0F;
+ return static_cast<float>(NumberUtils::round_to_int64((value / static_cast<float>(FPLUT::ONE)) * 100000.0f)) / 100000.0f;
}
- constexpr float to_double() const {
- return value / 65536.0;
+ constexpr double to_double() const {
+ return value / static_cast<double>(FPLUT::ONE);
}
constexpr float to_double_rounded() const {
- return FloatUtils::round_to_int64((value / 65536.0) * 100000.0) / 100000.0;
+ return NumberUtils::round_to_int64((value / static_cast<double>(FPLUT::ONE)) * 100000.0) / 100000.0;
}
std::string to_string() const {
- std::string str = std::to_string(to_int64_t()) + ".";
- FP frac_part = get_frac();
+ FP val = abs();
+ std::string str = std::to_string(val.to_int64_t()) + ".";
+ if (is_negative()) str = "-" + str;
+ val = val.get_frac();
do {
- frac_part.value *= 10;
- str += std::to_string(frac_part.to_int64_t());
- frac_part = frac_part.get_frac();
- } while (frac_part > 0);
+ val *= 10;
+ str.push_back('0' + static_cast<char>(val.to_int64_t()));
+ val = val.get_frac();
+ } while (val > 0);
return str;
}
@@ -258,7 +265,7 @@ namespace OpenVic {
}
// Deterministic
- static constexpr FP parse(const char* str, const char* end, bool *successful = nullptr) {
+ static constexpr FP parse(char const* str, char const* const end, bool* successful = nullptr) {
if (successful != nullptr) *successful = false;
if (str == nullptr || str >= end) {
@@ -273,7 +280,7 @@ namespace OpenVic {
if (str == end) return _0();
}
- const char* dot_pointer = str;
+ char const* dot_pointer = str;
while (*dot_pointer != '.' && ++dot_pointer != end);
if (dot_pointer == str && dot_pointer + 1 == end) {
@@ -287,31 +294,35 @@ namespace OpenVic {
if (dot_pointer != str) {
// Non-empty integer part
bool int_successful = false;
- result += parse_integer(str, dot_pointer, &int_successful);
+ result += parse_integer(str, dot_pointer, &int_successful);
if (!int_successful && successful != nullptr) *successful = false;
}
if (dot_pointer + 1 < end) {
// Non-empty fractional part
bool frac_successful = false;
- result += parse_fraction(dot_pointer + 1, end, &frac_successful);
+ result += parse_fraction(dot_pointer + 1, end, &frac_successful);
if (!frac_successful && successful != nullptr) *successful = false;
}
return negative ? -result : result;
}
- static constexpr FP parse(const char* str, size_t length, bool *successful = nullptr) {
+ static constexpr FP parse(char const* str, size_t length, bool* successful = nullptr) {
return parse(str, str + length, successful);
}
+ static FP parse(const std::string_view str, bool* successful = nullptr) {
+ return parse(str.data(), str.length(), successful);
+ }
+
// Not Deterministic
static constexpr FP parse_unsafe(float value) {
return static_cast<int64_t>(value * FPLUT::ONE + 0.5f * (value < 0 ? -1 : 1));
}
// Not Deterministic
- static FP parse_unsafe(const char* value) {
+ static FP parse_unsafe(char const* value) {
char* endpointer;
double double_value = std::strtod(value, &endpointer);
@@ -325,7 +336,7 @@ namespace OpenVic {
}
constexpr operator int32_t() const {
- return to_int32_t();
+ return to_int32_t();
}
constexpr operator int64_t() const {
@@ -344,218 +355,225 @@ namespace OpenVic {
return to_string();
}
- friend std::ostream& operator<<(std::ostream& stream, const FP& obj) {
+ friend std::ostream& operator<<(std::ostream& stream, FP const& obj) {
return stream << obj.to_string();
}
- constexpr friend FP operator-(const FP& obj) {
+ constexpr friend FP operator-(FP const& obj) {
return -obj.value;
}
- constexpr friend FP operator+(const FP& obj) {
+ constexpr friend FP operator+(FP const& obj) {
return +obj.value;
}
- constexpr friend FP operator+(const FP& lhs, const FP& rhs) {
+ constexpr friend FP operator+(FP const& lhs, FP const& rhs) {
return lhs.value + rhs.value;
}
- constexpr friend FP operator+(const FP& lhs, const int32_t& rhs) {
+ constexpr friend FP operator+(FP const& lhs, int32_t const& rhs) {
return lhs.value + (static_cast<int64_t>(rhs) << FPLUT::PRECISION);
}
- constexpr friend FP operator+(const int32_t& lhs, const FP& rhs) {
+ constexpr friend FP operator+(int32_t const& lhs, FP const& rhs) {
return (static_cast<int64_t>(lhs) << FPLUT::PRECISION) + rhs.value;
}
- constexpr FP operator+=(const FP& obj) {
+ constexpr FP operator+=(FP const& obj) {
value += obj.value;
return *this;
}
- constexpr FP operator+=(const int32_t& obj) {
+ constexpr FP operator+=(int32_t const& obj) {
value += (static_cast<int64_t>(obj) << FPLUT::PRECISION);
return *this;
}
- constexpr friend FP operator-(const FP& lhs, const FP& rhs) {
+ constexpr friend FP operator-(FP const& lhs, FP const& rhs) {
return lhs.value - rhs.value;
}
- constexpr friend FP operator-(const FP& lhs, const int32_t& rhs) {
+ constexpr friend FP operator-(FP const& lhs, int32_t const& rhs) {
return lhs.value - (static_cast<int64_t>(rhs) << FPLUT::PRECISION);
}
- constexpr friend FP operator-(const int32_t& lhs, const FP& rhs) {
+ constexpr friend FP operator-(int32_t const& lhs, FP const& rhs) {
return (static_cast<int64_t>(lhs) << FPLUT::PRECISION) - rhs.value;
}
- constexpr FP operator-=(const FP& obj) {
+ constexpr FP operator-=(FP const& obj) {
value -= obj.value;
return *this;
}
- constexpr FP operator-=(const int32_t& obj) {
+ constexpr FP operator-=(int32_t const& obj) {
value -= (static_cast<int64_t>(obj) << FPLUT::PRECISION);
return *this;
}
- constexpr friend FP operator*(const FP& lhs, const FP& rhs) {
+ constexpr friend FP operator*(FP const& lhs, FP const& rhs) {
return lhs.value * rhs.value >> FPLUT::PRECISION;
}
- constexpr friend FP operator*(const FP& lhs, const int32_t& rhs) {
+ constexpr friend FP operator*(FP const& lhs, int32_t const& rhs) {
return lhs.value * rhs;
}
- constexpr friend FP operator*(const int32_t& lhs, const FP& rhs) {
+ constexpr friend FP operator*(int32_t const& lhs, FP const& rhs) {
return lhs * rhs.value;
}
- constexpr FP operator*=(const FP& obj) {
+ constexpr FP operator*=(FP const& obj) {
value *= obj.value >> FPLUT::PRECISION;
return *this;
}
- constexpr FP operator*=(const int32_t& obj) {
+ constexpr FP operator*=(int32_t const& obj) {
value *= obj;
return *this;
}
- constexpr friend FP operator/(const FP& lhs, const FP& rhs) {
- return (lhs.value << FPLUT::PRECISION) / rhs.value;
+ constexpr friend FP operator/(FP const& lhs, FP const& rhs) {
+ return (lhs.value << FPLUT::PRECISION) / rhs.value;
}
- constexpr friend FP operator/(const FP& lhs, const int32_t& rhs) {
+ constexpr friend FP operator/(FP const& lhs, int32_t const& rhs) {
return lhs.value / rhs;
}
- constexpr friend FP operator/(const int32_t& lhs, const FP& rhs) {
- return (static_cast<int64_t>(lhs) << (2 / FPLUT::PRECISION)) / rhs.value;
+ constexpr friend FP operator/(int32_t const& lhs, FP const& rhs) {
+ return (static_cast<int64_t>(lhs) << (2 * FPLUT::PRECISION)) / rhs.value;
}
- constexpr FP operator/=(const FP& obj) {
+ constexpr FP operator/=(FP const& obj) {
value = (value << FPLUT::PRECISION) / obj.value;
return *this;
}
- constexpr FP operator/=(const int32_t& obj) {
+ constexpr FP operator/=(int32_t const& obj) {
value /= obj;
return *this;
}
- constexpr friend FP operator%(const FP& lhs, const FP& rhs) {
+ constexpr friend FP operator%(FP const& lhs, FP const& rhs) {
return lhs.value % rhs.value;
}
- constexpr friend FP operator%(const FP& lhs, const int32_t& rhs) {
+ constexpr friend FP operator%(FP const& lhs, int32_t const& rhs) {
return lhs.value % (static_cast<int64_t>(rhs) << FPLUT::PRECISION);
}
- constexpr friend FP operator%(const int32_t& lhs, const FP& rhs) {
+ constexpr friend FP operator%(int32_t const& lhs, FP const& rhs) {
return (static_cast<int64_t>(lhs) << FPLUT::PRECISION) % rhs.value;
}
- constexpr FP operator%=(const FP& obj) {
+ constexpr FP operator%=(FP const& obj) {
value %= obj.value;
return *this;
}
- constexpr FP operator%=(const int32_t& obj) {
+ constexpr FP operator%=(int32_t const& obj) {
value %= (static_cast<int64_t>(obj) << FPLUT::PRECISION);
return *this;
}
- constexpr friend bool operator<(const FP& lhs, const FP& rhs) {
+ constexpr friend bool operator<(FP const& lhs, FP const& rhs) {
return lhs.value < rhs.value;
}
- constexpr friend bool operator<(const FP& lhs, const int32_t& rhs) {
+ constexpr friend bool operator<(FP const& lhs, int32_t const& rhs) {
return lhs.value < static_cast<int64_t>(rhs) << FPLUT::PRECISION;
}
- constexpr friend bool operator<(const int32_t& lhs, const FP& rhs) {
+ constexpr friend bool operator<(int32_t const& lhs, FP const& rhs) {
return static_cast<int64_t>(lhs) << FPLUT::PRECISION < rhs.value;
}
- constexpr friend bool operator<=(const FP& lhs, const FP& rhs) {
+ constexpr friend bool operator<=(FP const& lhs, FP const& rhs) {
return lhs.value <= rhs.value;
}
- constexpr friend bool operator<=(const FP& lhs, const int32_t& rhs) {
+ constexpr friend bool operator<=(FP const& lhs, int32_t const& rhs) {
return lhs.value <= static_cast<int64_t>(rhs) << FPLUT::PRECISION;
}
- constexpr friend bool operator<=(const int32_t& lhs, const FP& rhs) {
+ constexpr friend bool operator<=(int32_t const& lhs, FP const& rhs) {
return static_cast<int64_t>(lhs) << FPLUT::PRECISION <= rhs.value;
}
- constexpr friend bool operator>(const FP& lhs, const FP& rhs) {
+ constexpr friend bool operator>(FP const& lhs, FP const& rhs) {
return lhs.value > rhs.value;
}
- constexpr friend bool operator>(const FP& lhs, const int32_t& rhs) {
+ constexpr friend bool operator>(FP const& lhs, int32_t const& rhs) {
return lhs.value > static_cast<int64_t>(rhs) << FPLUT::PRECISION;
}
- constexpr friend bool operator>(const int32_t& lhs, const FP& rhs) {
+ constexpr friend bool operator>(int32_t const& lhs, FP const& rhs) {
return static_cast<int64_t>(lhs) << FPLUT::PRECISION > rhs.value;
}
- constexpr friend bool operator>=(const FP& lhs, const FP& rhs) {
+ constexpr friend bool operator>=(FP const& lhs, FP const& rhs) {
return lhs.value >= rhs.value;
}
- constexpr friend bool operator>=(const FP& lhs, const int32_t& rhs) {
+ constexpr friend bool operator>=(FP const& lhs, int32_t const& rhs) {
return lhs.value >= static_cast<int64_t>(rhs) << FPLUT::PRECISION;
}
- constexpr friend bool operator>=(const int32_t& lhs, const FP& rhs) {
+ constexpr friend bool operator>=(int32_t const& lhs, FP const& rhs) {
return static_cast<int64_t>(lhs) << FPLUT::PRECISION >= rhs.value;
}
- constexpr friend bool operator==(const FP& lhs, const FP& rhs) {
+ constexpr friend bool operator==(FP const& lhs, FP const& rhs) {
return lhs.value == rhs.value;
}
- constexpr friend bool operator==(const FP& lhs, const int32_t& rhs) {
+ constexpr friend bool operator==(FP const& lhs, int32_t const& rhs) {
return lhs.value == static_cast<int64_t>(rhs) << FPLUT::PRECISION;
}
- constexpr friend bool operator==(const int32_t& lhs, const FP& rhs) {
+ constexpr friend bool operator==(int32_t const& lhs, FP const& rhs) {
return static_cast<int64_t>(lhs) << FPLUT::PRECISION == rhs.value;
}
- constexpr friend bool operator!=(const FP& lhs, const FP& rhs) {
+ constexpr friend bool operator!=(FP const& lhs, FP const& rhs) {
return lhs.value != rhs.value;
}
- constexpr friend bool operator!=(const FP& lhs, const int32_t& rhs) {
+ constexpr friend bool operator!=(FP const& lhs, int32_t const& rhs) {
return lhs.value != static_cast<int64_t>(rhs) << FPLUT::PRECISION;
}
- constexpr friend bool operator!=(const int32_t& lhs, const FP& rhs) {
+ constexpr friend bool operator!=(int32_t const& lhs, FP const& rhs) {
return static_cast<int64_t>(lhs) << FPLUT::PRECISION != rhs.value;
}
-
private:
int64_t value;
- static constexpr FP parse_integer(const char* str, const char* end, bool* successful) {
+ static constexpr FP parse_integer(char const* str, char const* const end, bool* successful) {
int64_t parsed_value = StringUtils::string_to_int64(str, end, successful, 10);
return parse(parsed_value);
}
- static constexpr FP parse_fraction(const char* str, const char* end, bool* successful) {
- constexpr size_t READ_SIZE = 5;
- if (str + READ_SIZE < end) {
- Logger::error("Fixed point fraction parse will only use the first ", READ_SIZE,
- " characters of ", std::string_view { str, static_cast<size_t>(end - str) });
- end = str + READ_SIZE;
+ static constexpr FP parse_fraction(char const* str, char const* end, bool* successful) {
+ char const* const read_end = str + FPLUT::PRECISION;
+ if (read_end < end) end = read_end;
+ uint64_t parsed_value = StringUtils::string_to_uint64(str, end, successful, 10);
+ while (end++ < read_end) {
+ parsed_value *= 10;
}
- int64_t parsed_value = StringUtils::string_to_int64(str, end, successful, 10);
- return parse_raw(parsed_value * 65536 / 100000);
+ uint64_t decimal = NumberUtils::pow(static_cast<uint64_t>(10), FPLUT::PRECISION);
+ int64_t ret = 0;
+ for (int i = FPLUT::PRECISION - 1; i >= 0; --i) {
+ decimal >>= 1;
+ if (parsed_value > decimal) {
+ parsed_value -= decimal;
+ ret |= 1 << i;
+ }
+ }
+ return ret;
}
};
diff --git a/src/openvic/utility/FloatUtils.hpp b/src/openvic/utility/FloatUtils.hpp
deleted file mode 100644
index 4fc83fd..0000000
--- a/src/openvic/utility/FloatUtils.hpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#include <cstdint>
-
-namespace OpenVic::FloatUtils {
- constexpr int round_to_int(double num) {
- return (num > 0.0) ? (num + 0.5) : (num - 0.5);
- }
-
- constexpr int64_t round_to_int64(double num) {
- return (num > 0.0) ? (num + 0.5) : (num - 0.5);
- }
-}
diff --git a/src/openvic/utility/NumberUtils.hpp b/src/openvic/utility/NumberUtils.hpp
new file mode 100644
index 0000000..6211772
--- /dev/null
+++ b/src/openvic/utility/NumberUtils.hpp
@@ -0,0 +1,27 @@
+#include <cstdint>
+
+namespace OpenVic::NumberUtils {
+ constexpr int64_t round_to_int64(float num) {
+ return (num > 0.0f) ? (num + 0.5f) : (num - 0.5f);
+ }
+
+ constexpr int64_t round_to_int64(double num) {
+ return (num > 0.0) ? (num + 0.5) : (num - 0.5);
+ }
+
+ constexpr uint64_t pow(uint64_t base, size_t exponent) {
+ uint64_t ret = 1;
+ while (exponent-- > 0) {
+ ret *= base;
+ }
+ return ret;
+ }
+
+ constexpr int64_t pow(int64_t base, size_t exponent) {
+ int64_t ret = 1;
+ while (exponent-- > 0) {
+ ret *= base;
+ }
+ return ret;
+ }
+}
diff --git a/src/openvic/utility/StringUtils.hpp b/src/openvic/utility/StringUtils.hpp
index 72f4038..5d6001c 100644
--- a/src/openvic/utility/StringUtils.hpp
+++ b/src/openvic/utility/StringUtils.hpp
@@ -1,16 +1,17 @@
#include <cstdint>
#include <limits>
+#include <string_view>
namespace OpenVic::StringUtils {
- /* The constexpr function 'string_to_int64' will convert a string into a int64 integer value.
- * The function takes four parameters: the input string (as a pair of pointers marking the start and
- * end of the string), a bool pointer for reporting success, and the base for numerical conversion.
- * The base parameter defaults to 10 (decimal), but it can be any value between 2 and 36. If the base
- * given is 0, it will be set to 16 if the string starts with "0x" or "0X", otherwise 8 if the string
- * still starts with "0", otherwise 10. The success bool pointer parameter is used to report whether
- * or not conversion was successful. It can be nullptr if this information is not needed.
- */
- constexpr int64_t string_to_int64(char const* str, const char* end, bool* successful, int base = 10) {
+ /* The constexpr function 'string_to_uint64' will convert a string into a uint64_t integer value.
+ * The function takes four parameters: the input string (as a pair of pointers marking the start and
+ * end of the string), a bool pointer for reporting success, and the base for numerical conversion.
+ * The base parameter defaults to 10 (decimal), but it can be any value between 2 and 36. If the base
+ * given is 0, it will be set to 16 if the string starts with "0x" or "0X", otherwise 8 if the string
+ * still starts with "0", otherwise 10. The success bool pointer parameter is used to report whether
+ * or not conversion was successful. It can be nullptr if this information is not needed.
+ */
+ constexpr uint64_t string_to_uint64(char const* str, const char* const end, bool* successful = nullptr, int base = 10) {
if (successful != nullptr) *successful = false;
// Base value should be between 2 and 36. If it's not, return 0 as an invalid case.
@@ -18,24 +19,14 @@ namespace OpenVic::StringUtils {
return 0;
// The result of the conversion will be stored in this variable.
- int64_t result = 0;
- // This flag will be set if the number is negative.
- bool is_negative = false;
-
- // Check if there is a sign character.
- if (*str == '+' || *str == '-') {
- if (*str == '-')
- is_negative = true;
- ++str;
- if (str == end) return 0;
- }
+ uint64_t result = 0;
// If base is zero, base is determined by the string prefix.
if (base == 0) {
if (*str == '0') {
if (str + 1 != end && (str[1] == 'x' || str[1] == 'X')) {
base = 16; // Hexadecimal.
- str += 2; // Skip '0x' or '0X'
+ str += 2; // Skip '0x' or '0X'
if (str == end) return 0;
} else {
base = 8; // Octal.
@@ -69,15 +60,15 @@ namespace OpenVic::StringUtils {
}
// Check for overflow on multiplication
- if (result > std::numeric_limits<int64_t>::max() / base) {
- return is_negative ? std::numeric_limits<int64_t>::min() : std::numeric_limits<int64_t>::max();
+ if (result > std::numeric_limits<uint64_t>::max() / base) {
+ return std::numeric_limits<uint64_t>::max();
}
result *= base;
// Check for overflow on addition
- if (result > std::numeric_limits<int64_t>::max() - digit) {
- return is_negative ? std::numeric_limits<int64_t>::min() : std::numeric_limits<int64_t>::max();
+ if (result > std::numeric_limits<uint64_t>::max() - digit) {
+ return std::numeric_limits<uint64_t>::max();
}
result += digit;
@@ -87,7 +78,50 @@ namespace OpenVic::StringUtils {
// set *successful to true (if not it is already false).
if (successful != nullptr && str == end) *successful = true;
- // Return the result. If the number was negative, the result is negated.
- return is_negative ? -result : result;
+ return result;
+ }
+
+ constexpr uint64_t string_to_uint64(char const* str, size_t length, bool* successful = nullptr, int base = 10) {
+ return string_to_uint64(str, str + length, successful, base);
+ }
+
+ inline uint64_t string_to_uint64(const std::string_view str, bool* successful = nullptr, int base = 10) {
+ return string_to_uint64(str.data(), str.length(), successful, base);
+ }
+
+ constexpr int64_t string_to_int64(char const* str, const char* const end, bool* successful = nullptr, int base = 10) {
+ if (successful != nullptr) *successful = false;
+
+ if (str == nullptr || end <= str) return 0;
+
+ // This flag will be set if the number is negative.
+ bool is_negative = false;
+
+ // Check if there is a sign character.
+ if (*str == '+' || *str == '-') {
+ if (*str == '-')
+ is_negative = true;
+ ++str;
+ if (str == end) return 0;
+ }
+
+ const uint64_t result = string_to_uint64(str, end, successful, base);
+ if (!is_negative) {
+ if (result >= std::numeric_limits<int64_t>::max())
+ return std::numeric_limits<int64_t>::max();
+ return result;
+ } else {
+ if (result > std::numeric_limits<int64_t>::max())
+ return std::numeric_limits<int64_t>::min();
+ return -result;
+ }
+ }
+
+ constexpr int64_t string_to_int64(char const* str, size_t length, bool* successful = nullptr, int base = 10) {
+ return string_to_int64(str, str + length, successful, base);
+ }
+
+ inline int64_t string_to_int64(const std::string_view str, bool* successful = nullptr, int base = 10) {
+ return string_to_int64(str.data(), str.length(), successful, base);
}
}