#pragma once #include #include #include #include #include #include #include "openvic-simulation/types/Colour.hpp" #include "openvic-simulation/types/Date.hpp" #include "openvic-simulation/types/HasIdentifier.hpp" #include "openvic-simulation/types/OrderedContainers.hpp" #include "openvic-simulation/types/Vector.hpp" namespace OpenVic { namespace ast = ovdl::v2script::ast; /* Template for map from strings to Ts, in which string_views can be * searched for without needing to be copied into a string */ template, class KeyEqual = std::equal_to<>> using string_map_t = ordered_map; template using case_insensitive_string_map_t = string_map_t; /* String set type supporting heterogeneous key lookup */ using string_set_t = ordered_set; using case_insensitive_string_set_t = case_insensitive_ordered_set; using name_list_t = std::vector; std::ostream& operator<<(std::ostream& stream, name_list_t const& name_list); namespace NodeTools { template concept Functor = requires(Fn&& fn, Args&&... args) { { std::invoke(std::forward(fn), std::forward(args)...) } -> std::same_as; }; template concept FunctorConvertible = requires(Fn&& fn, Args&&... args) { { std::invoke(std::forward(fn), std::forward(args)...) } -> std::convertible_to; }; template concept Callback = Functor; template concept NodeCallback = Callback; template concept KeyValueCallback = Callback; template concept LengthCallback = Functor; template using callback_t = std::function; using node_callback_t = callback_t; constexpr bool success_callback(ast::NodeCPtr) { return true; } using key_value_callback_t = callback_t; constexpr bool key_value_success_callback(std::string_view, ast::NodeCPtr) { return true; } inline bool key_value_invalid_callback(std::string_view key, ast::NodeCPtr) { Logger::error("Invalid dictionary key: ", key); return false; } node_callback_t expect_identifier(callback_t callback); node_callback_t expect_string(callback_t callback, bool allow_empty = false); node_callback_t expect_identifier_or_string(callback_t callback, bool allow_empty = false); node_callback_t expect_bool(callback_t callback); node_callback_t expect_int_bool(callback_t callback); node_callback_t expect_int64(callback_t callback, int base = 10); node_callback_t expect_uint64(callback_t callback, int base = 10); template NodeCallback auto expect_int(callback_t callback, int base = 10) { return expect_int64([callback](int64_t val) -> bool { if (static_cast(std::numeric_limits::lowest()) <= val && val <= static_cast(std::numeric_limits::max())) { return callback(val); } Logger::error( "Invalid int: ", val, " (valid range: [", static_cast(std::numeric_limits::lowest()), ", ", static_cast(std::numeric_limits::max()), "])" ); return false; }, base); } template NodeCallback auto expect_uint(callback_t callback, int base = 10) { return expect_uint64([callback](uint64_t val) -> bool { if (val <= static_cast(std::numeric_limits::max())) { return callback(val); } Logger::error( "Invalid uint: ", val, " (valid range: [0, ", static_cast(std::numeric_limits::max()), "])" ); return false; }, base); } callback_t expect_fixed_point_str(callback_t callback); node_callback_t expect_fixed_point(callback_t callback); /* Expect a list of 3 base 10 values, each either in the range [0, 1] or (1, 255], representing RGB components. */ node_callback_t expect_colour(callback_t callback); /* Expect a hexadecimal value representing a colour in ARGB format. */ node_callback_t expect_colour_hex(callback_t callback); callback_t expect_date_str(callback_t callback); node_callback_t expect_date(callback_t callback); node_callback_t expect_years(callback_t callback); node_callback_t expect_months(callback_t callback); node_callback_t expect_days(callback_t callback); node_callback_t expect_ivec2(callback_t callback); node_callback_t expect_fvec2(callback_t callback); node_callback_t expect_assign(key_value_callback_t callback); using length_callback_t = std::function; constexpr size_t default_length_callback(size_t size) { return size; }; node_callback_t expect_list_and_length(length_callback_t length_callback, node_callback_t callback); node_callback_t expect_list_of_length(size_t length, node_callback_t callback); node_callback_t expect_list(node_callback_t callback); node_callback_t expect_length(callback_t callback); node_callback_t expect_key( std::string_view key, node_callback_t callback, bool* key_found = nullptr, bool allow_duplicates = false ); node_callback_t expect_dictionary_and_length(length_callback_t length_callback, key_value_callback_t callback); node_callback_t expect_dictionary(key_value_callback_t callback); struct dictionary_entry_t { enum class expected_count_t : uint8_t { _MUST_APPEAR = 0b01, _CAN_REPEAT = 0b10, ZERO_OR_ONE = 0, ONE_EXACTLY = _MUST_APPEAR, ZERO_OR_MORE = _CAN_REPEAT, ONE_OR_MORE = _MUST_APPEAR | _CAN_REPEAT } expected_count; node_callback_t callback; size_t count; dictionary_entry_t(expected_count_t new_expected_count, node_callback_t new_callback) : expected_count { new_expected_count }, callback { new_callback }, count { 0 } {} constexpr bool must_appear() const { return static_cast(expected_count) & static_cast(expected_count_t::_MUST_APPEAR); } constexpr bool can_repeat() const { return static_cast(expected_count) & static_cast(expected_count_t::_CAN_REPEAT); } }; using enum dictionary_entry_t::expected_count_t; using key_map_t = string_map_t; bool add_key_map_entry( key_map_t& key_map, std::string_view key, dictionary_entry_t::expected_count_t expected_count, node_callback_t callback ); bool remove_key_map_entry(key_map_t& key_map, std::string_view key); key_value_callback_t dictionary_keys_callback(key_map_t& key_map, key_value_callback_t default_callback); bool check_key_map_counts(key_map_t& key_map); constexpr bool add_key_map_entries(key_map_t& key_map) { return true; } template bool add_key_map_entries( key_map_t& key_map, std::string_view key, dictionary_entry_t::expected_count_t expected_count, NodeCallback auto callback, Args... args ) { bool ret = add_key_map_entry(key_map, key, expected_count, callback); ret &= add_key_map_entries(key_map, args...); return ret; } node_callback_t expect_dictionary_key_map_and_length_and_default( key_map_t key_map, length_callback_t length_callback, key_value_callback_t default_callback ); node_callback_t expect_dictionary_key_map_and_length(key_map_t key_map, length_callback_t length_callback); node_callback_t expect_dictionary_key_map_and_default(key_map_t key_map, key_value_callback_t default_callback); node_callback_t expect_dictionary_key_map(key_map_t key_map); template NodeCallback auto expect_dictionary_key_map_and_length_and_default( key_map_t key_map, length_callback_t length_callback, key_value_callback_t default_callback, Args... args ) { // TODO - pass return value back up (part of big key_map_t rewrite?) add_key_map_entries(key_map, args...); return expect_dictionary_key_map_and_length_and_default(std::move(key_map), length_callback, default_callback); } template NodeCallback auto expect_dictionary_keys_and_length_and_default( LengthCallback auto length_callback, KeyValueCallback auto default_callback, Args... args ) { return expect_dictionary_key_map_and_length_and_default({}, length_callback, default_callback, args...); } template NodeCallback auto expect_dictionary_keys_and_length(LengthCallback auto length_callback, Args... args) { return expect_dictionary_key_map_and_length_and_default({}, length_callback, key_value_invalid_callback, args...); } template NodeCallback auto expect_dictionary_keys_and_default(KeyValueCallback auto default_callback, Args... args) { return expect_dictionary_key_map_and_length_and_default({}, default_length_callback, default_callback, args...); } template NodeCallback auto expect_dictionary_keys(Args... args) { return expect_dictionary_key_map_and_length_and_default( {}, default_length_callback, key_value_invalid_callback, args... ); } template concept Reservable = requires(T& t) { { t.size() } -> std::same_as; t.reserve(size_t {}); }; template LengthCallback auto reserve_length_callback(T& t) { return [&t](size_t size) -> size_t { t.reserve(size); return size; }; } template NodeCallback auto expect_list_reserve_length(T& t, NodeCallback auto callback) { return expect_list_and_length(reserve_length_callback(t), callback); } template NodeCallback auto expect_dictionary_reserve_length(T& t, KeyValueCallback auto callback) { return expect_list_reserve_length(t, expect_assign(callback)); } node_callback_t name_list_callback(callback_t callback); template Callback auto expect_mapped_string( string_map_t const& map, Callback auto callback ) { return [&map, callback](std::string_view string) -> bool { const typename string_map_t::const_iterator it = map.find(string); if (it != map.end()) { return callback(it->second); } Logger::error("String not found in map: ", string); return false; }; } template Callback auto assign_variable_callback_cast(auto& var) { return [&var](T val) -> bool { var = val; return true; }; } template requires std::is_integral_v || std::is_enum_v callback_t assign_variable_callback_cast(auto& var) { return [&var](T val) -> bool { var = val; return true; }; } template Callback auto assign_variable_callback(T& var) { return assign_variable_callback_cast(var); } callback_t assign_variable_callback_string(std::string& var); template Callback auto move_variable_callback(T& var) { return [&var](T&& val) -> bool { var = std::move(val); return true; }; } template requires requires(T& t) { t += T {}; } Callback auto add_variable_callback(T& var) { return [&var](T val) -> bool { var += val; return true; }; } template requires requires(T& t) { t++; } KeyValueCallback auto increment_callback(T& var) { return [&var](std::string_view, ast::NodeCPtr) -> bool { var++; return true; }; } template Callback auto assign_variable_callback_pointer(T const*& var) { return [&var](T const& val) -> bool { var = &val; return true; }; } template Callback auto assign_variable_callback_pointer(std::optional& var) { return [&var](T const& val) -> bool { var = &val; return true; }; } template Callback auto vector_callback(std::vector& vec) { return [&vec](T val) -> bool { vec.emplace_back(std::move(val)); return true; }; } template Callback auto vector_callback(std::vector& vec) { return vector_callback(vec); } template Callback auto vector_callback_pointer(std::vector& vec) { return [&vec](T const& val) -> bool { vec.emplace_back(&val); return true; }; } template Callback auto set_callback(tsl::ordered_set& set) { return [&set](T val) -> bool { if (!set.emplace(std::move(val)).second) { Logger::warning("Duplicate set entry: \"", val, "\""); } return true; }; } template T, typename...SetArgs> Callback auto set_callback_pointer(tsl::ordered_set& set) { return [&set](T const& val) -> bool { if (!set.emplace(&val).second) { Logger::warning("Duplicate set entry: \"", &val, "\""); } return true; }; } template Key, typename Value, typename... MapArgs> Callback auto map_callback(tsl::ordered_map& map, Key const* key) { return [&map, key](Value value) -> bool { if (!map.emplace(key, std::move(value)).second) { Logger::warning("Duplicate map entry with key: \"", key, "\""); } return true; }; } } }