From d26f9c2fb5a9666822a0f702d76b764600a390d7 Mon Sep 17 00:00:00 2001 From: hop311 Date: Fri, 13 Oct 2023 22:04:12 +0100 Subject: Further CLI and modifier reading work --- src/headless/main.cpp | 80 +++++----- src/openvic-simulation/Modifier.cpp | 64 ++++++-- src/openvic-simulation/Modifier.hpp | 18 +++ src/openvic-simulation/dataloader/Dataloader.cpp | 4 +- src/openvic-simulation/economy/Building.hpp | 2 +- src/openvic-simulation/map/TerrainType.cpp | 8 +- src/openvic-simulation/map/TerrainType.hpp | 4 +- .../types/IdentifierRegistry.hpp | 162 ++++++++++----------- src/openvic-simulation/utility/Logger.cpp | 16 +- src/openvic-simulation/utility/Logger.hpp | 33 +++-- 10 files changed, 220 insertions(+), 171 deletions(-) diff --git a/src/headless/main.cpp b/src/headless/main.cpp index e15005b..6cb6661 100644 --- a/src/headless/main.cpp +++ b/src/headless/main.cpp @@ -7,36 +7,17 @@ using namespace OpenVic; -static char const* get_program_name(char const* name) { - static constexpr char const* missing_name = ""; - if (name == nullptr) return missing_name; - char const* last_separator = name; - while (*name != '\0') { - if (*name == '/' || *name == '\\') { - last_separator = name + 1; - } - ++name; - } - if (*last_separator == '\0') return missing_name; - return last_separator; -} - -static void print_help(char const* program_name) { - std::cout +static void print_help(std::ostream& stream, char const* program_name) { + stream << "Usage: " << program_name << " [-h] [-t] [-b ] [path]+\n" << " -h : Print this help message and exit the program.\n" << " -t : Run tests after loading defines.\n" << " -b : Use the following path as the base directory (instead of searching for one).\n" + << " -s : Use the following path as a hint to search for a base directory.\n" << "Any following paths are read as mod directories, with priority starting at one above the base directory.\n" << "(Paths with spaces need to be enclosed in \"quotes\").\n"; } -static void setup_logger_funcs() { - Logger::set_info_func([](std::string&& str) { std::cout << str; }); - Logger::set_warning_func([](std::string&& str) { std::cerr << str; }); - Logger::set_error_func([](std::string&& str) { std::cerr << str; }); -} - static bool headless_load(GameManager& game_manager, Dataloader const& dataloader) { bool ret = true; @@ -63,8 +44,6 @@ static bool headless_load(GameManager& game_manager, Dataloader const& dataloade static bool run_headless(Dataloader::path_vector_t const& roots, bool run_tests) { bool ret = true; - setup_logger_funcs(); - Dataloader dataloader; if (!dataloader.set_roots(roots)) { Logger::error("Failed to set dataloader roots!"); @@ -93,36 +72,51 @@ static bool run_headless(Dataloader::path_vector_t const& roots, bool run_tests) */ int main(int argc, char const* argv[]) { - char const* program_name = get_program_name(argc > 0 ? argv[0] : nullptr); + Logger::set_logger_funcs(); + char const* program_name = Logger::get_filename(argc > 0 ? argv[0] : nullptr, ""); fs::path root; bool run_tests = false; - int argn = 0; + + /* Reads the next argument and converts it to a path via path_transform. If reading or converting fails, an error + * message and the help text are displayed, along with returning false to signify the program should exit. + */ + const auto _read = [&root, &argn, argc, argv, program_name](std::string_view command, std::string_view path_use, auto path_transform) -> bool { + if (root.empty()) { + if (++argn < argc) { + char const* path = argv[argn]; + root = path_transform(path); + if (!root.empty()) { + return true; + } else { + std::cerr << "Empty path after giving \"" << path << "\" to " << path_use << " command line argument \"" << command << "\"." << std::endl; + } + } else { + std::cerr << "Missing path after " << path_use << " command line argument \"" << command << "\"." << std::endl; + } + } else { + std::cerr << "Duplicate " << path_use << " command line argument \"-b\"." << std::endl; + } + print_help(std::cerr, program_name); + return false; + }; + while (++argn < argc) { char const* arg = argv[argn]; if (strcmp(arg, "-h") == 0) { - print_help(program_name); + print_help(std::cout, program_name); return 0; } else if (strcmp(arg, "-t") == 0) { run_tests = true; } else if (strcmp(arg, "-b") == 0) { - if (root.empty()) { - if (++argn < argc) { - root = argv[argn]; - if (!root.empty()) { - continue; - } else { - std::cerr << "Empty path after base directory command line argument \"-b\"." << std::endl; - } - } else { - std::cerr << "Missing path after base directory command line argument \"-b\"." << std::endl; - } - } else { - std::cerr << "Duplicate base directory command line argument \"-b\"." << std::endl; + if (!_read("-b", "base directory", std::identity{})) { + return -1; + } + } else if (strcmp(arg, "-s") == 0) { + if (!_read("-s", "search hint", Dataloader::search_for_game_path)) { + return -1; } - print_help(program_name); - return -1; } else { break; } @@ -131,7 +125,7 @@ int main(int argc, char const* argv[]) { root = Dataloader::search_for_game_path(); if (root.empty()) { std::cerr << "Search for base directory path failed!" << std::endl; - print_help(program_name); + print_help(std::cerr, program_name); return -1; } } diff --git a/src/openvic-simulation/Modifier.cpp b/src/openvic-simulation/Modifier.cpp index 1273fdd..fc5dcaf 100644 --- a/src/openvic-simulation/Modifier.cpp +++ b/src/openvic-simulation/Modifier.cpp @@ -154,38 +154,72 @@ bool ModifierManager::setup_modifier_effects() { ret &= add_modifier_effect("min_build_university", true, ModifierEffect::format_t::INT); ret &= add_modifier_effect("max_bank", true, ModifierEffect::format_t::INT); ret &= add_modifier_effect("min_build_bank", true, ModifierEffect::format_t::INT); - + modifier_effects.lock(); return ret; } -node_callback_t ModifierManager::expect_modifier_value_and_default(callback_t modifier_callback, key_value_callback_t default_callback) const { - return [this, modifier_callback, default_callback](ast::NodeCPtr root) -> bool { - ModifierValue modifier; - bool ret = expect_dictionary( - [this, &modifier, default_callback](std::string_view key, ast::NodeCPtr value) -> bool { - ModifierEffect const* effect = get_modifier_effect_by_identifier(key); - if (effect != nullptr) { - if (modifier.values.find(effect) == modifier.values.end()) { - return expect_fixed_point( - assign_variable_callback(modifier.values[effect]) - )(value); - } +key_value_callback_t ModifierManager::_modifier_effect_callback( + ModifierValue& modifier, key_value_callback_t default_callback, + ModifierEffectValidator auto effect_validator) const { + + return [this, &modifier, default_callback, effect_validator](std::string_view key, ast::NodeCPtr value) -> bool { + ModifierEffect const* effect = get_modifier_effect_by_identifier(key); + if (effect != nullptr) { + if (effect_validator(*effect)) { + if (modifier.values.find(effect) == modifier.values.end()) { + return expect_fixed_point( + assign_variable_callback(modifier.values[effect]) + )(value); + } else { Logger::error("Duplicate modifier effect: ", key); return false; } - return default_callback(key, value); + } else { + Logger::error("Failed to validate modifier effect: ", key); + return false; } - )(root); + } + return default_callback(key, value); + }; +} + +node_callback_t ModifierManager::expect_validated_modifier_value_and_default(callback_t modifier_callback, + key_value_callback_t default_callback, ModifierEffectValidator auto effect_validator) const { + return [this, modifier_callback, default_callback, effect_validator](ast::NodeCPtr root) -> bool { + ModifierValue modifier; + bool ret = expect_dictionary(_modifier_effect_callback(modifier, default_callback, effect_validator))(root); ret &= modifier_callback(std::move(modifier)); return ret; }; } +node_callback_t ModifierManager::expect_validated_modifier_value(callback_t modifier_callback, + ModifierEffectValidator auto effect_validator) const { + return expect_validated_modifier_value_and_default(modifier_callback, key_value_invalid_callback, effect_validator); +} + +node_callback_t ModifierManager::expect_modifier_value_and_default(callback_t modifier_callback, key_value_callback_t default_callback) const { + return expect_validated_modifier_value_and_default(modifier_callback, default_callback, + [](ModifierEffect const&) -> bool { return true; } + ); +} node_callback_t ModifierManager::expect_modifier_value(callback_t modifier_callback) const { return expect_modifier_value_and_default(modifier_callback, key_value_invalid_callback); } +node_callback_t ModifierManager::expect_whitelisted_modifier_value_and_default(callback_t modifier_callback, std::set> const& whitelist, key_value_callback_t default_callback) const { + return expect_validated_modifier_value_and_default(modifier_callback, default_callback, + [&whitelist](ModifierEffect const& effect) -> bool { + return whitelist.contains(effect.get_identifier()); + } + ); +} + +node_callback_t ModifierManager::expect_whitelisted_modifier_value(callback_t modifier_callback, std::set> const& whitelist) const { + return expect_whitelisted_modifier_value_and_default(modifier_callback, whitelist, key_value_invalid_callback); +} + node_callback_t ModifierManager::expect_modifier_value_and_key_map_and_default(callback_t modifier_callback, key_value_callback_t default_callback, key_map_t&& key_map) const { return [this, modifier_callback, key_map = std::move(key_map)](ast::NodeCPtr node) mutable -> bool { bool ret = expect_modifier_value_and_default( diff --git a/src/openvic-simulation/Modifier.hpp b/src/openvic-simulation/Modifier.hpp index 663d359..0801aa5 100644 --- a/src/openvic-simulation/Modifier.hpp +++ b/src/openvic-simulation/Modifier.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include "openvic-simulation/types/IdentifierRegistry.hpp" namespace OpenVic { @@ -92,12 +94,20 @@ namespace OpenVic { Date const& get_expiry_date() const; }; + template + concept ModifierEffectValidator = std::predicate; + struct ModifierManager { private: IdentifierRegistry modifier_effects; IdentifierRegistry modifiers; + /* effect_validator takes in ModifierEffect const& */ + NodeTools::key_value_callback_t _modifier_effect_callback(ModifierValue& modifier, + NodeTools::key_value_callback_t default_callback, + ModifierEffectValidator auto effect_validator) const; + public: ModifierManager(); @@ -109,9 +119,17 @@ namespace OpenVic { bool setup_modifier_effects(); + NodeTools::node_callback_t expect_validated_modifier_value_and_default(NodeTools::callback_t modifier_callback, + NodeTools::key_value_callback_t default_callback, ModifierEffectValidator auto effect_validator) const; + NodeTools::node_callback_t expect_validated_modifier_value(NodeTools::callback_t modifier_callback, + ModifierEffectValidator auto effect_validator) const; + NodeTools::node_callback_t expect_modifier_value_and_default(NodeTools::callback_t modifier_callback, NodeTools::key_value_callback_t default_callback) const; NodeTools::node_callback_t expect_modifier_value(NodeTools::callback_t modifier_callback) const; + NodeTools::node_callback_t expect_whitelisted_modifier_value_and_default(NodeTools::callback_t modifier_callback, std::set> const& whitelist, NodeTools::key_value_callback_t default_callback) const; + NodeTools::node_callback_t expect_whitelisted_modifier_value(NodeTools::callback_t modifier_callback, std::set> const& whitelist) const; + NodeTools::node_callback_t expect_modifier_value_and_key_map_and_default(NodeTools::callback_t modifier_callback, NodeTools::key_value_callback_t default_callback, NodeTools::key_map_t&& key_map) const; NodeTools::node_callback_t expect_modifier_value_and_key_map(NodeTools::callback_t modifier_callback, NodeTools::key_map_t&& key_map) const; diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index 5134054..72e3113 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -46,8 +46,8 @@ constexpr bool path_equals(std::string_view lhs, std::string_view rhs) { } template -constexpr bool filename_equals(const LT& lhs, const RT& rhs) { - std::string_view left, right; +bool filename_equals(const LT& lhs, const RT& rhs) { + std::string left, right; if constexpr (std::same_as) left = lhs.filename().string(); else left = lhs; diff --git a/src/openvic-simulation/economy/Building.hpp b/src/openvic-simulation/economy/Building.hpp index cbf5bfd..b56c9a2 100644 --- a/src/openvic-simulation/economy/Building.hpp +++ b/src/openvic-simulation/economy/Building.hpp @@ -32,7 +32,7 @@ namespace OpenVic { private: BuildingType const& type; - ModifierValue modifier; + const ModifierValue modifier; const std::string on_completion; //probably sound played on completion const fixed_point_t completion_size; const level_t max_level; diff --git a/src/openvic-simulation/map/TerrainType.cpp b/src/openvic-simulation/map/TerrainType.cpp index 017b220..8624cdb 100644 --- a/src/openvic-simulation/map/TerrainType.cpp +++ b/src/openvic-simulation/map/TerrainType.cpp @@ -5,8 +5,12 @@ using namespace OpenVic; using namespace OpenVic::NodeTools; -TerrainType::TerrainType(std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_values, bool new_is_water) - : HasIdentifierAndColour { new_identifier, new_colour, true, false }, ModifierValue { std::move(new_values) }, is_water { new_is_water } {} +TerrainType::TerrainType(std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_modifier, bool new_is_water) + : HasIdentifierAndColour { new_identifier, new_colour, true, false }, modifier { std::move(new_modifier) }, is_water { new_is_water } {} + +ModifierValue const& TerrainType::get_modifier() const { + return modifier; +} bool TerrainType::get_is_water() const { return is_water; diff --git a/src/openvic-simulation/map/TerrainType.hpp b/src/openvic-simulation/map/TerrainType.hpp index 1353130..edda0a9 100644 --- a/src/openvic-simulation/map/TerrainType.hpp +++ b/src/openvic-simulation/map/TerrainType.hpp @@ -9,13 +9,15 @@ namespace OpenVic { friend struct TerrainTypeManager; private: + const ModifierValue modifier; const bool is_water; - TerrainType(std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_values, bool new_is_water); + TerrainType(std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_modifier, bool new_is_water); public: TerrainType(TerrainType&&) = default; + ModifierValue const& get_modifier() const; bool get_is_water() const; }; diff --git a/src/openvic-simulation/types/IdentifierRegistry.hpp b/src/openvic-simulation/types/IdentifierRegistry.hpp index b2f52b2..1a03e75 100644 --- a/src/openvic-simulation/types/IdentifierRegistry.hpp +++ b/src/openvic-simulation/types/IdentifierRegistry.hpp @@ -103,11 +103,10 @@ namespace OpenVic { return true; } - template - using get_identifier_func_t = std::string_view(T::*)(void) const; - - template _Type, get_identifier_func_t<_Base> get_identifier, - typename _Storage, _Type* (*get_ptr)(_Storage&), _Type const* (*get_cptr)(_Storage const&)> + /* _GetIdentifier - takes _Type const* and returns std::string_view + * _GetPointer - takes _Storage [const]& and returns T [const]* + */ + template class UniqueKeyRegistry { const std::string name; @@ -116,12 +115,15 @@ namespace OpenVic { bool locked = false; string_map_t identifier_index_map; + _GetIdentifier GetIdentifier; + _GetPointer GetPointer; + public: using value_type = _Type; using storage_type = _Storage; - UniqueKeyRegistry(std::string_view new_name, bool new_log_lock = true) - : name { new_name }, log_lock { new_log_lock } {} + UniqueKeyRegistry(std::string_view new_name, bool new_log_lock = true, _GetIdentifier new_GetIdentifier = {}, _GetPointer new_GetPointer = {}) + : name { new_name }, log_lock { new_log_lock }, GetIdentifier { new_GetIdentifier }, GetPointer { new_GetPointer } {} std::string_view get_name() const { return name; @@ -132,8 +134,7 @@ namespace OpenVic { Logger::error("Cannot add item to the ", name, " registry - locked!"); return false; } - value_type const* new_item = (*get_cptr)(item); - const std::string_view new_identifier = (new_item->*get_identifier)(); + const std::string_view new_identifier = GetIdentifier(GetPointer(item)); value_type const* old_item = get_item_by_identifier(new_identifier); if (old_item != nullptr) { return duplicate_callback(name, new_identifier); @@ -178,30 +179,47 @@ namespace OpenVic { } } - value_type* get_item_by_identifier(std::string_view identifier) { - const typename decltype(identifier_index_map)::const_iterator it = identifier_index_map.find(identifier); - if (it != identifier_index_map.end()) return (*get_ptr)(items[it->second]); - return nullptr; +#define GETTERS \ + value_type _const* get_item_by_identifier(std::string_view identifier) _const { \ + const typename decltype(identifier_index_map)::const_iterator it = identifier_index_map.find(identifier); \ + if (it != identifier_index_map.end()) return GetPointer(items[it->second]); \ + return nullptr; \ + } \ + value_type _const* get_item_by_index(size_t index) _const { \ + return index < items.size() ? &items[index] : nullptr; \ + } \ + NodeTools::callback_t expect_item_identifier(NodeTools::callback_t callback) _const { \ + return [this, callback](std::string_view identifier) -> bool { \ + value_type _const* item = get_item_by_identifier(identifier); \ + if (item != nullptr) return callback(*item); \ + Logger::error("Invalid ", name, ": ", identifier); \ + return false; \ + }; \ + } \ + NodeTools::node_callback_t expect_item_dictionary(NodeTools::callback_t callback) _const { \ + return NodeTools::expect_dictionary([this, callback](std::string_view key, ast::NodeCPtr value) -> bool { \ + value_type _const* item = get_item_by_identifier(key); \ + if (item != nullptr) { \ + return callback(*item, value); \ + } \ + Logger::error("Invalid ", name, " identifier: ", key); \ + return false; \ + }); \ } - value_type const* get_item_by_identifier(std::string_view identifier) const { - const typename decltype(identifier_index_map)::const_iterator it = identifier_index_map.find(identifier); - if (it != identifier_index_map.end()) return (*get_cptr)(items[it->second]); - return nullptr; - } +#define _const +GETTERS +#undef _const +#define _const const +GETTERS +#undef _const + +#undef GETTERS bool has_identifier(std::string_view identifier) const { return get_item_by_identifier(identifier) != nullptr; } - value_type* get_item_by_index(size_t index) { - return index < items.size() ? &items[index] : nullptr; - } - - value_type const* get_item_by_index(size_t index) const { - return index < items.size() ? &items[index] : nullptr; - } - bool has_index(size_t index) const { return get_item_by_index(index) != nullptr; } @@ -217,46 +235,6 @@ namespace OpenVic { return identifiers; } - NodeTools::callback_t expect_item_identifier(NodeTools::callback_t callback) { - return [this, callback](std::string_view identifier) -> bool { - value_type* item = get_item_by_identifier(identifier); - if (item != nullptr) return callback(*item); - Logger::error("Invalid ", name, ": ", identifier); - return false; - }; - } - - NodeTools::callback_t expect_item_identifier(NodeTools::callback_t callback) const { - return [this, callback](std::string_view identifier) -> bool { - value_type const* item = get_item_by_identifier(identifier); - if (item != nullptr) return callback(*item); - Logger::error("Invalid ", name, ": ", identifier); - return false; - }; - } - - NodeTools::node_callback_t expect_item_dictionary(NodeTools::callback_t callback) { - return NodeTools::expect_dictionary([this, callback](std::string_view key, ast::NodeCPtr value) -> bool { - value_type* item = get_item_by_identifier(key); - if (item != nullptr) { - return callback(*item, value); - } - Logger::error("Invalid ", name, " identifier: ", key); - return false; - }); - } - - NodeTools::node_callback_t expect_item_dictionary(NodeTools::callback_t callback) const { - return NodeTools::expect_dictionary([this, callback](std::string_view key, ast::NodeCPtr value) -> bool { - value_type const* item = get_item_by_identifier(key); - if (item != nullptr) { - return callback(*item, value); - } - Logger::error("Invalid ", name, " identifier: ", key); - return false; - }); - } - NodeTools::node_callback_t expect_item_decimal_map(NodeTools::callback_t&&> callback) const { return [this, callback](ast::NodeCPtr node) -> bool { decimal_map_t map; @@ -272,35 +250,47 @@ namespace OpenVic { } }; + /* Standard value storage */ template - [[nodiscard]] inline constexpr T* _addressof(T& v) noexcept { - return std::addressof(v); - } + struct _addressof { + constexpr T* operator()(T& item) const { + return std::addressof(item); + } + constexpr T const* operator()(T const& item) const { + return std::addressof(item); + } + }; + template + using ValueRegistry = UniqueKeyRegistry<_Type, _Type, _GetIdentifier, _addressof<_Type>>; + + /* std::unique_ptr dynamic storage */ template - const T* _addressof(const T&&) = delete; + struct _uptr_get { + constexpr T* operator()(std::unique_ptr& item) const { + return item.get(); + } + constexpr T const* operator()(std::unique_ptr const& item) const { + return item.get(); + } + }; - template _Type, get_identifier_func_t<_Base> get_identifier> - using ValueRegistry = UniqueKeyRegistry<_Base, _Type, get_identifier, _Type, _addressof<_Type>, _addressof>; + template + using InstanceRegistry = UniqueKeyRegistry<_Type, std::unique_ptr<_Type>, _GetIdentifier, _uptr_get<_Type>>; - template - constexpr _Type* get_ptr(std::unique_ptr<_Type>& storage) { - return storage.get(); - } - template - constexpr _Type const* get_cptr(std::unique_ptr<_Type> const& storage) { - return storage.get(); - } - - template _Type, get_identifier_func_t<_Base> get_identifier> - using InstanceRegistry = UniqueKeyRegistry<_Base, _Type, get_identifier, std::unique_ptr<_Type>, - get_ptr<_Type>, get_cptr<_Type>>; + /* HasIdentifier versions */ + template T> + struct _get_identifier { + constexpr std::string_view operator()(T const* item) const { + return item->get_identifier(); + } + }; template _Type> - using IdentifierRegistry = ValueRegistry; + using IdentifierRegistry = ValueRegistry<_Type, _get_identifier<_Type>>; template _Type> - using IdentifierInstanceRegistry = InstanceRegistry; + using IdentifierInstanceRegistry = InstanceRegistry<_Type, _get_identifier<_Type>>; #define IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(singular, plural) \ void lock_##plural() { plural.lock(); } \ diff --git a/src/openvic-simulation/utility/Logger.cpp b/src/openvic-simulation/utility/Logger.cpp index fca08a5..68c43dd 100644 --- a/src/openvic-simulation/utility/Logger.cpp +++ b/src/openvic-simulation/utility/Logger.cpp @@ -4,19 +4,19 @@ using namespace OpenVic; -Logger::log_func_t Logger::info_func {}; -Logger::log_queue_t Logger::info_queue {}; -Logger::log_func_t Logger::warning_func {}; -Logger::log_queue_t Logger::warning_queue {}; -Logger::log_func_t Logger::error_func {}; -Logger::log_queue_t Logger::error_queue {}; +void Logger::set_logger_funcs() { + Logger::set_info_func([](std::string&& str) { std::cout << str; }); + Logger::set_warning_func([](std::string&& str) { std::cerr << str; }); + Logger::set_error_func([](std::string&& str) { std::cerr << str; }); +} -char const* Logger::get_filename(char const* filepath) { - if (filepath == nullptr) return nullptr; +char const* Logger::get_filename(char const* filepath, char const* default_path) { + if (filepath == nullptr) return default_path; char const* last_slash = filepath; while (*filepath != '\0') { if (*filepath == '\\' || *filepath == '/') last_slash = filepath + 1; filepath++; } + if (*last_slash == '\0') return default_path; return last_slash; } diff --git a/src/openvic-simulation/utility/Logger.hpp b/src/openvic-simulation/utility/Logger.hpp index 11cada5..d60e59e 100644 --- a/src/openvic-simulation/utility/Logger.hpp +++ b/src/openvic-simulation/utility/Logger.hpp @@ -32,7 +32,7 @@ namespace OpenVic { }; #endif - class Logger { + class Logger final { using log_func_t = std::function; using log_queue_t = std::queue; @@ -42,39 +42,46 @@ namespace OpenVic { using source_location = OpenVic::source_location; #endif - static char const* get_filename(char const* filepath); + public: + static void set_logger_funcs(); + static char const* get_filename(char const* filepath, char const* default_path = nullptr); + + private: + struct log_channel_t { + log_func_t func; + log_queue_t queue; + }; template struct log { - log(log_func_t log_func, log_queue_t& log_queue, Ts&&... ts, source_location const& location) { + log(log_channel_t& log_channel, Ts&&... ts, source_location const& location) { std::stringstream stream; stream << "\n" << get_filename(location.file_name()) << "(" //<< location.line() << ") `" << location.function_name() << "`: "; << location.line() << "): "; ((stream << std::forward(ts)), ...); stream << std::endl; - log_queue.push(stream.str()); - if (log_func) { + log_channel.queue.push(stream.str()); + if (log_channel.func) { do { - log_func(std::move(log_queue.front())); - log_queue.pop(); - } while (!log_queue.empty()); + log_channel.func(std::move(log_channel.queue.front())); + log_channel.queue.pop(); + } while (!log_channel.queue.empty()); } } }; #define LOG_FUNC(name) \ private: \ - static log_func_t name##_func; \ - static log_queue_t name##_queue; \ + static inline log_channel_t name##_channel{}; \ public: \ - static void set_##name##_func(log_func_t log_func) { \ - name##_func = log_func; \ + static inline void set_##name##_func(log_func_t log_func) { \ + name##_channel.func = log_func; \ } \ template \ struct name { \ name(Ts&&... ts, source_location const& location = source_location::current()) { \ - log{ name##_func, name##_queue, std::forward(ts)..., location }; \ + log{ name##_channel, std::forward(ts)..., location }; \ } \ }; \ template \ -- cgit v1.2.3-56-ga3b1