From 70948572ef0fb5c6dae453c410fdaedfab36741b Mon Sep 17 00:00:00 2001 From: hop311 Date: Sat, 13 Jan 2024 20:14:06 +0000 Subject: Reworked UniqueKeyRegistry template params + added support for std::deque storage --- src/openvic-simulation/dataloader/Dataloader.cpp | 2 + src/openvic-simulation/interface/LoadBase.hpp | 40 +-- src/openvic-simulation/misc/Modifier.cpp | 4 +- src/openvic-simulation/misc/Modifier.hpp | 11 +- .../types/IdentifierRegistry.hpp | 335 +++++++++++++-------- 5 files changed, 243 insertions(+), 149 deletions(-) diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index fd4f2b0..0078ed2 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -836,8 +836,10 @@ bool Dataloader::load_defines(GameManager& game_manager) { ret = false; } if (!_load_technologies(game_manager)) { + Logger::error("Failed to load technologies!"); ret = false; } + game_manager.get_modifier_manager().lock_modifier_effects(); if (!game_manager.get_politics_manager().get_rule_manager().setup_rules( game_manager.get_economy_manager().get_building_type_manager() )) { diff --git a/src/openvic-simulation/interface/LoadBase.hpp b/src/openvic-simulation/interface/LoadBase.hpp index 3ee7c83..74aece9 100644 --- a/src/openvic-simulation/interface/LoadBase.hpp +++ b/src/openvic-simulation/interface/LoadBase.hpp @@ -5,27 +5,27 @@ namespace OpenVic { - template + template class LoadBase { protected: LoadBase() = default; - virtual bool _fill_key_map(NodeTools::key_map_t&, _Context...) = 0; + virtual bool _fill_key_map(NodeTools::key_map_t&, Context...) = 0; public: LoadBase(LoadBase&&) = default; virtual ~LoadBase() = default; - bool load(ast::NodeCPtr node, _Context... context) { + bool load(ast::NodeCPtr node, Context... context) { NodeTools::key_map_t key_map; bool ret = _fill_key_map(key_map, context...); ret &= NodeTools::expect_dictionary_key_map(std::move(key_map))(node); return ret; } - template> T, std::derived_from U> + template> T, std::derived_from U> static NodeTools::node_callback_t _expect_instance( - NodeTools::callback_t&&> callback, _Context... context + NodeTools::callback_t&&> callback, Context... context ) { return [callback, &context...](ast::NodeCPtr node) -> bool { std::unique_ptr instance { std::make_unique() }; @@ -38,14 +38,14 @@ namespace OpenVic { OV_DETAIL_GET_TYPE_BASE_CLASS(LoadBase) }; - template - class Named : public LoadBase<_Context...> { + template + class Named : public LoadBase { std::string PROPERTY(name); protected: Named() = default; - virtual bool _fill_key_map(NodeTools::key_map_t& key_map, _Context...) override { + virtual bool _fill_key_map(NodeTools::key_map_t& key_map, Context...) override { using namespace OpenVic::NodeTools; return add_key_map_entries(key_map, "name", ONE_EXACTLY, expect_string(assign_variable_callback_string(name))); } @@ -64,19 +64,21 @@ namespace OpenVic { OV_DETAIL_GET_TYPE }; - template - requires std::derived_from> - struct _get_name { - constexpr std::string_view operator()(T const* item) const { - return item->get_name(); + template + requires std::derived_from> + struct RegistryValueInfoNamed { + using value_type = Value; + + static constexpr std::string_view get_identifier(value_type const& item) { + return item.get_name(); } }; - template - requires std::derived_from> - using NamedRegistry = ValueRegistry>; + template + requires std::derived_from> + using NamedRegistry = ValueRegistry>; - template - requires std::derived_from> - using NamedInstanceRegistry = InstanceRegistry>; + template + requires std::derived_from> + using NamedInstanceRegistry = InstanceRegistry>; } diff --git a/src/openvic-simulation/misc/Modifier.cpp b/src/openvic-simulation/misc/Modifier.cpp index 8abafe3..b0dc1cf 100644 --- a/src/openvic-simulation/misc/Modifier.cpp +++ b/src/openvic-simulation/misc/Modifier.cpp @@ -98,9 +98,7 @@ bool ModifierManager::add_modifier_effect(std::string_view identifier, bool posi Logger::error("Invalid modifier effect identifier - empty!"); return false; } - return modifier_effects.add_item( - std::make_unique(std::move(identifier), std::move(positive_good), std::move(format)) - ); + return modifier_effects.add_item({ std::move(identifier), positive_good, format }); } bool ModifierManager::setup_modifier_effects() { diff --git a/src/openvic-simulation/misc/Modifier.hpp b/src/openvic-simulation/misc/Modifier.hpp index 83efe9b..abb3891 100644 --- a/src/openvic-simulation/misc/Modifier.hpp +++ b/src/openvic-simulation/misc/Modifier.hpp @@ -3,13 +3,12 @@ #include "openvic-simulation/scripts/ConditionScript.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" -#include "dataloader/NodeTools.hpp" - - namespace OpenVic { struct ModifierManager; struct ModifierEffect : HasIdentifier { + friend struct ModifierManager; + enum class format_t { PROPORTION_DECIMAL, /* An unscaled fraction/ratio, with 1 being "full"/"whole" */ PERCENTAGE_DECIMAL, /* A fraction/ratio scaled so that 100 is "full"/"whole" */ @@ -17,8 +16,6 @@ namespace OpenVic { INT /* A discrete quantity, e.g. building count limit */ }; - friend std::unique_ptr std::make_unique(std::string_view&&, bool&&, format_t&&); - private: /* If true, positive values will be green and negative values will be red. * If false, the colours will be switced. @@ -115,10 +112,10 @@ namespace OpenVic { struct ModifierManager { /* Some ModifierEffects are generated mid-load, such as max/min count modifiers for each building, so * we can't lock it until loading is over. This means we can't rely on locking for pointer stability, - * so instead we use an IdentifierInstanceRegistry (using std::unique_ptr's under the hood). + * so instead we store the effects in a deque which doesn't invalidate pointers on insert. */ private: - CaseInsensitiveIdentifierInstanceRegistry IDENTIFIER_REGISTRY(modifier_effect); + CaseInsensitiveIdentifierRegistry IDENTIFIER_REGISTRY(modifier_effect); case_insensitive_string_set_t complex_modifiers; IdentifierRegistry IDENTIFIER_REGISTRY(event_modifier); diff --git a/src/openvic-simulation/types/IdentifierRegistry.hpp b/src/openvic-simulation/types/IdentifierRegistry.hpp index 04198b0..bbaf52c 100644 --- a/src/openvic-simulation/types/IdentifierRegistry.hpp +++ b/src/openvic-simulation/types/IdentifierRegistry.hpp @@ -24,69 +24,177 @@ namespace OpenVic { ); return true; } - static bool duplicate_ignore_callback(std::string_view registry_name, std::string_view duplicate_identifier) { + static constexpr bool duplicate_ignore_callback(std::string_view registry_name, std::string_view duplicate_identifier) { return true; } - /* _GetIdentifier - takes _Type const* and returns std::string_view - * _GetPointer - takes _Storage [const]& and returns T [const]* - */ + /* Registry Value Info - the type that is being registered, and a unique identifier string getter. */ + template + concept RegistryValueInfo = requires(typename ValueInfo::value_type const& item) { + { ValueInfo::get_identifier(item) } -> std::same_as; + }; + template Value> + struct RegistryValueInfoHasIdentifier { + using value_type = Value; + + static constexpr std::string_view get_identifier(value_type const& item) { + return item.get_identifier(); + } + }; + + /* Registry Item Info - how individual elements of the registered type are stored, and type from item getters. */ + template typename ItemInfo, typename Value> + concept RegistryItemInfo = requires( + typename ItemInfo::item_type& item, typename ItemInfo::item_type const& const_item + ) { + { ItemInfo::get_value(item) } -> std::same_as; + { ItemInfo::get_value(const_item) } -> std::same_as; + }; + template + struct RegistryItemInfoValue { + using item_type = Value; + + static constexpr Value& get_value(item_type& item) { + return item; + } + static constexpr Value const& get_value(item_type const& item) { + return item; + } + }; + template + struct RegistryItemInfoInstance { + using item_type = std::unique_ptr; + + static constexpr Value& get_value(item_type& item) { + return *item.get(); + } + static constexpr Value const& get_value(item_type const& item) { + return *item.get(); + } + }; + + /* Registry Storage Info - how items are stored and indexed, and item-index conversion functions. */ + template typename StorageInfo, typename Item> + concept RegistryStorageInfo = + std::same_as::storage_type::value_type, Item> && + requires( + typename StorageInfo::storage_type& items, typename StorageInfo::storage_type const& const_items, + typename StorageInfo::index_type index + ) { + { StorageInfo::get_back_index(items) } -> std::same_as::index_type>; + { StorageInfo::get_item_from_index(items, index) } -> std::same_as; + { StorageInfo::get_item_from_index(const_items, index) } -> std::same_as; + }; + template + struct RegistryStorageInfoVector { + using storage_type = std::vector; + using index_type = std::size_t; + + static constexpr index_type get_back_index(storage_type& items) { + return items.size() - 1; + } + static constexpr Item& get_item_from_index(storage_type& items, index_type index) { + return items[index]; + } + static constexpr Item const& get_item_from_index(storage_type const& items, index_type index) { + return items[index]; + } + }; + template + struct RegistryStorageInfoDeque { + using storage_type = std::deque; + using index_type = Item*; + + static constexpr index_type get_back_index(storage_type& items) { + return std::addressof(items.back()); + } + static constexpr Item& get_item_from_index(storage_type& items, index_type index) { + return *index; + } + static constexpr Item const& get_item_from_index(storage_type const& items, index_type index) { + return *index; + } + }; + + /* Registry Identifier Map Info - how unique identifier strings are compared when looking up entries. */ + template + concept RegistryIdentifierMapInfo = requires(std::string_view identifier) { + { typename IdentifierMapInfo::hash {}(identifier) } -> std::same_as; + { typename IdentifierMapInfo::equal {}(identifier, identifier) } -> std::same_as; + }; + struct RegistryIdentifierMapInfoCaseSensitive { + using hash = container_hash; + using equal = std::equal_to<>; + }; + struct RegistryIdentifierMapInfoCaseInsensitive { + using hash = case_insensitive_string_hash; + using equal = case_insensitive_string_equal; + }; + template< - typename _Type, typename _Storage, typename _GetIdentifier, typename _GetPointer, - class Hash = container_hash, class KeyEqual = std::equal_to<>> + RegistryValueInfo ValueInfo, /* The type that is being registered and that has unique string identifiers */ + template typename _ItemInfo, /* How the type is being stored, usually either by value or std::unique_ptr */ + template typename _StorageInfo = RegistryStorageInfoVector, /* How items are stored, including indexing type */ + RegistryIdentifierMapInfo IdentifierMapInfo = RegistryIdentifierMapInfoCaseSensitive /* Identifier map parameters */ + > + requires ( + RegistryItemInfo<_ItemInfo, typename ValueInfo::value_type> && + RegistryStorageInfo<_StorageInfo, typename _ItemInfo::item_type> + ) class UniqueKeyRegistry { + public: + using value_type = typename ValueInfo::value_type; + using ItemInfo = _ItemInfo; + using item_type = typename ItemInfo::item_type; - using identifier_index_map_t = string_map_t; + private: + using StorageInfo = _StorageInfo; + using index_type = typename StorageInfo::index_type; + using identifier_index_map_t = + string_map_t; + + public: + using storage_type = typename StorageInfo::storage_type; + private: const std::string name; const bool log_lock; - std::vector<_Storage> PROPERTY_REF(items); + storage_type PROPERTY_REF(items); bool locked = false; identifier_index_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, _GetIdentifier new_GetIdentifier = {}, - _GetPointer new_GetPointer = {} - ) : name { new_name }, log_lock { new_log_lock }, GetIdentifier { new_GetIdentifier }, GetPointer { new_GetPointer } {} + constexpr UniqueKeyRegistry(std::string_view new_name, bool new_log_lock = true) + : name { new_name }, log_lock { new_log_lock } {} - std::string_view get_name() const { + constexpr std::string_view get_name() const { return name; } - bool add_item( - storage_type&& item, - NodeTools::callback_t duplicate_callback = duplicate_fail_callback + constexpr bool add_item( + item_type&& item, NodeTools::Callback auto duplicate_callback ) { if (locked) { Logger::error("Cannot add item to the ", name, " registry - locked!"); return false; } - const std::string_view new_identifier = GetIdentifier(GetPointer(item)); - if (duplicate_callback && - duplicate_callback.target() == duplicate_ignore_callback) { - if (has_identifier(new_identifier)) { - return true; - } - } else { - value_type const* old_item = get_item_by_identifier(new_identifier); - if (old_item != nullptr) { - return duplicate_callback(name, new_identifier); - } + + const std::string_view new_identifier = ValueInfo::get_identifier(ItemInfo::get_value(item)); + value_type const* old_item = get_item_by_identifier(new_identifier); + if (old_item != nullptr) { + return duplicate_callback(name, new_identifier); } - const std::pair ret = - identifier_index_map.emplace(std::move(new_identifier), items.size()); + items.emplace_back(std::move(item)); - return ret.second && ret.first->second + 1 == items.size(); + identifier_index_map.emplace(std::move(new_identifier), StorageInfo::get_back_index(items)); + return true; } - void lock() { + constexpr bool add_item(item_type&& item) { + return add_item(std::move(item), duplicate_fail_callback); + } + + constexpr void lock() { if (locked) { Logger::error("Failed to lock ", name, " registry - already locked!"); } else { @@ -97,25 +205,25 @@ namespace OpenVic { } } - bool is_locked() const { + constexpr bool is_locked() const { return locked; } - void reset() { + constexpr void reset() { identifier_index_map.clear(); items.clear(); locked = false; } - size_t size() const { + constexpr std::size_t size() const { return items.size(); } - bool empty() const { + constexpr bool empty() const { return items.empty(); } - void reserve(size_t size) { + constexpr void reserve(std::size_t size) { if (locked) { Logger::error("Failed to reserve space for ", size, " items in ", name, " registry - already locked!"); } else { @@ -124,7 +232,7 @@ namespace OpenVic { } } - static NodeTools::KeyValueCallback auto key_value_invalid_callback(std::string_view name) { + constexpr static NodeTools::KeyValueCallback auto key_value_invalid_callback(std::string_view name) { return [name](std::string_view key, ast::NodeCPtr) { Logger::error("Invalid ", name, ": ", key); return false; @@ -132,17 +240,17 @@ namespace OpenVic { } #define GETTERS(CONST) \ - value_type CONST* get_item_by_identifier(std::string_view identifier) CONST { \ + constexpr 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 std::addressof(ItemInfo::get_value(StorageInfo::get_item_from_index(items, it->second))); \ } \ return nullptr; \ } \ - value_type CONST* get_item_by_index(size_t index) CONST { \ - return index < items.size() ? GetPointer(items[index]) : nullptr; \ + constexpr value_type CONST* get_item_by_index(std::size_t index) CONST { \ + return index < items.size() ? std::addressof(ItemInfo::get_value(items[index])) : nullptr; \ } \ - NodeTools::Callback auto expect_item_str( \ + constexpr NodeTools::Callback auto expect_item_str( \ NodeTools::Callback auto callback, bool warn \ ) CONST { \ return [this, callback, warn](std::string_view identifier) -> bool { \ @@ -159,12 +267,12 @@ namespace OpenVic { } \ }; \ } \ - NodeTools::NodeCallback auto expect_item_identifier( \ + constexpr NodeTools::NodeCallback auto expect_item_identifier( \ NodeTools::Callback auto callback, bool warn \ ) CONST { \ return NodeTools::expect_identifier(expect_item_str(callback, warn)); \ } \ - NodeTools::NodeCallback auto expect_item_assign_and_default( \ + constexpr NodeTools::NodeCallback auto expect_item_assign_and_default( \ NodeTools::KeyValueCallback auto default_callback, \ NodeTools::Callback auto callback \ ) CONST { \ @@ -179,12 +287,12 @@ namespace OpenVic { } \ ); \ } \ - NodeTools::NodeCallback auto expect_item_assign( \ + constexpr NodeTools::NodeCallback auto expect_item_assign( \ NodeTools::Callback auto callback \ ) CONST { \ return expect_item_assign_and_default(key_value_invalid_callback(name), callback); \ } \ - NodeTools::NodeCallback auto expect_item_dictionary_and_length_and_default( \ + constexpr NodeTools::NodeCallback auto expect_item_dictionary_and_length_and_default( \ NodeTools::LengthCallback auto length_callback, \ NodeTools::KeyValueCallback auto default_callback, \ NodeTools::Callback auto callback \ @@ -193,7 +301,7 @@ namespace OpenVic { length_callback, expect_item_assign_and_default(default_callback, callback) \ ); \ } \ - NodeTools::NodeCallback auto expect_item_dictionary_and_length( \ + constexpr NodeTools::NodeCallback auto expect_item_dictionary_and_length( \ NodeTools::LengthCallback auto length_callback, \ NodeTools::Callback auto callback \ ) CONST { \ @@ -203,7 +311,7 @@ namespace OpenVic { callback \ ); \ } \ - NodeTools::NodeCallback auto expect_item_dictionary_and_default( \ + constexpr NodeTools::NodeCallback auto expect_item_dictionary_and_default( \ NodeTools::KeyValueCallback auto default_callback, \ NodeTools::Callback auto callback \ ) CONST { \ @@ -213,7 +321,7 @@ namespace OpenVic { callback \ ); \ } \ - NodeTools::NodeCallback auto expect_item_dictionary( \ + constexpr NodeTools::NodeCallback auto expect_item_dictionary( \ NodeTools::Callback auto callback \ ) CONST { \ return expect_item_dictionary_and_length_and_default( \ @@ -223,7 +331,7 @@ namespace OpenVic { ); \ } \ template \ - NodeTools::NodeCallback auto expect_item_dictionary_reserve_length_and_default( \ + constexpr NodeTools::NodeCallback auto expect_item_dictionary_reserve_length_and_default( \ T& t, \ NodeTools::KeyValueCallback auto default_callback, \ NodeTools::Callback auto callback \ @@ -235,7 +343,7 @@ namespace OpenVic { ); \ } \ template \ - NodeTools::NodeCallback auto expect_item_dictionary_reserve_length( \ + constexpr NodeTools::NodeCallback auto expect_item_dictionary_reserve_length( \ T& t, \ NodeTools::Callback auto callback \ ) CONST { \ @@ -259,11 +367,11 @@ namespace OpenVic { #undef GETTERS - bool has_identifier(std::string_view identifier) const { + constexpr bool has_identifier(std::string_view identifier) const { return identifier_index_map.contains(identifier); } - bool has_index(size_t index) const { + constexpr bool has_index(std::size_t index) const { return index < size(); } @@ -276,7 +384,7 @@ namespace OpenVic { return identifiers; } - NodeTools::NodeCallback auto expect_item_decimal_map( + constexpr NodeTools::NodeCallback auto expect_item_decimal_map( NodeTools::Callback&&> auto callback ) const { return [this, callback](ast::NodeCPtr node) -> bool { @@ -293,55 +401,42 @@ namespace OpenVic { } }; - /* Standard value storage */ - template - 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, class KeyEqual = std::equal_to<>> - using ValueRegistry = UniqueKeyRegistry<_Type, _Type, _GetIdentifier, _addressof<_Type>, Hash, KeyEqual>; - - /* std::unique_ptr dynamic storage */ - template - 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(); - } - }; + /* Item Specialisations */ + template< + RegistryValueInfo ValueInfo, template typename StorageInfo = RegistryStorageInfoVector, + RegistryIdentifierMapInfo IdentifierMapInfo = RegistryIdentifierMapInfoCaseSensitive + > + requires RegistryStorageInfo::item_type> + using ValueRegistry = UniqueKeyRegistry; - template, class KeyEqual = std::equal_to<>> - using InstanceRegistry = UniqueKeyRegistry<_Type, std::unique_ptr<_Type>, _GetIdentifier, _uptr_get<_Type>, Hash, KeyEqual>; + template< + RegistryValueInfo ValueInfo, template typename StorageInfo = RegistryStorageInfoVector, + RegistryIdentifierMapInfo IdentifierMapInfo = RegistryIdentifierMapInfoCaseSensitive + > + requires RegistryStorageInfo::item_type> + using InstanceRegistry = UniqueKeyRegistry; - /* HasIdentifier versions */ - template T> - struct _get_identifier { - constexpr std::string_view operator()(T const* item) const { - return item->get_identifier(); - } - }; + /* HasIdentifier Specialisations */ + template< + std::derived_from Value, template typename StorageInfo = RegistryStorageInfoVector, + RegistryIdentifierMapInfo IdentifierMapInfo = RegistryIdentifierMapInfoCaseSensitive + > + using IdentifierRegistry = ValueRegistry, StorageInfo, IdentifierMapInfo>; - template _Type, class Hash = container_hash, class KeyEqual = std::equal_to<>> - using IdentifierRegistry = ValueRegistry<_Type, _get_identifier<_Type>, Hash, KeyEqual>; + template< + std::derived_from Value, template typename StorageInfo = RegistryStorageInfoVector, + RegistryIdentifierMapInfo IdentifierMapInfo = RegistryIdentifierMapInfoCaseSensitive + > + using IdentifierInstanceRegistry = InstanceRegistry, StorageInfo, IdentifierMapInfo>; - template _Type> + /* Case-Insensitive HasIdentifier Specialisations */ + template Value, template typename StorageInfo = RegistryStorageInfoVector> using CaseInsensitiveIdentifierRegistry = - IdentifierRegistry<_Type, case_insensitive_string_hash, case_insensitive_string_equal>; - - template _Type, class Hash = container_hash, class KeyEqual = std::equal_to<>> - using IdentifierInstanceRegistry = InstanceRegistry<_Type, _get_identifier<_Type>, Hash, KeyEqual>; + IdentifierRegistry; - template _Type> + template Value, template typename StorageInfo = RegistryStorageInfoVector> using CaseInsensitiveIdentifierInstanceRegistry = - IdentifierInstanceRegistry<_Type, case_insensitive_string_hash, case_insensitive_string_equal>; + IdentifierInstanceRegistry; /* Macros to generate declaration and constant accessor methods for a UniqueKeyRegistry member variable. */ @@ -357,25 +452,25 @@ namespace OpenVic { #define IDENTIFIER_REGISTRY_FULL_CUSTOM(singular, plural, registry, debug_name, index_offset) \ registry { #debug_name };\ public: \ - void lock_##plural() { \ + constexpr void lock_##plural() { \ registry.lock(); \ } \ - bool plural##_are_locked() const { \ + constexpr bool plural##_are_locked() const { \ return registry.is_locked(); \ } \ - bool has_##singular##_identifier(std::string_view identifier) const { \ + constexpr bool has_##singular##_identifier(std::string_view identifier) const { \ return registry.has_identifier(identifier); \ } \ - size_t get_##singular##_count() const { \ + constexpr std::size_t get_##singular##_count() const { \ return registry.size(); \ } \ - bool plural##_empty() const { \ + constexpr bool plural##_empty() const { \ return registry.empty(); \ } \ std::vector get_##singular##_identifiers() const { \ return registry.get_item_identifiers(); \ } \ - NodeTools::NodeCallback auto expect_##singular##_decimal_map( \ + constexpr NodeTools::NodeCallback auto expect_##singular##_decimal_map( \ NodeTools::Callback&&> auto callback \ ) const { \ return registry.expect_item_decimal_map(callback); \ @@ -398,56 +493,56 @@ private: IDENTIFIER_REGISTRY_INTERNAL_SHARED(singular, plural, registry, index_offset,) #define IDENTIFIER_REGISTRY_INTERNAL_SHARED(singular, plural, registry, index_offset, const_kw) \ - decltype(registry)::value_type const_kw* get_##singular##_by_identifier(std::string_view identifier) const_kw { \ + constexpr decltype(registry)::value_type const_kw* get_##singular##_by_identifier(std::string_view identifier) const_kw { \ return registry.get_item_by_identifier(identifier); \ } \ - decltype(registry)::value_type const_kw* get_##singular##_by_index(size_t index) const_kw { \ + constexpr decltype(registry)::value_type const_kw* get_##singular##_by_index(std::size_t index) const_kw { \ return index >= index_offset ? registry.get_item_by_index(index - index_offset) : nullptr; \ } \ - std::vector const_kw& get_##plural() const_kw { \ + constexpr decltype(registry)::storage_type const_kw& get_##plural() const_kw { \ return registry.get_items(); \ } \ - NodeTools::Callback auto expect_##singular##_str( \ + constexpr NodeTools::Callback auto expect_##singular##_str( \ NodeTools::Callback auto callback, bool warn = false \ ) const_kw { \ return registry.expect_item_str(callback, warn); \ } \ - NodeTools::NodeCallback auto expect_##singular##_identifier( \ + constexpr NodeTools::NodeCallback auto expect_##singular##_identifier( \ NodeTools::Callback auto callback, bool warn = false \ ) const_kw { \ return registry.expect_item_identifier(callback, warn); \ } \ - NodeTools::NodeCallback auto expect_##singular##_assign_and_default( \ + constexpr NodeTools::NodeCallback auto expect_##singular##_assign_and_default( \ NodeTools::KeyValueCallback auto default_callback, \ NodeTools::Callback auto callback \ ) const_kw { \ return registry.expect_item_assign_and_default(default_callback, callback); \ } \ - NodeTools::NodeCallback auto expect_##singular##_assign( \ + constexpr NodeTools::NodeCallback auto expect_##singular##_assign( \ NodeTools::Callback auto callback \ ) const_kw { \ return registry.expect_item_assign(callback); \ } \ - NodeTools::NodeCallback auto expect_##singular##_dictionary_and_length_and_default( \ + constexpr NodeTools::NodeCallback auto expect_##singular##_dictionary_and_length_and_default( \ NodeTools::LengthCallback auto length_callback, \ NodeTools::KeyValueCallback auto default_callback, \ NodeTools::Callback auto callback \ ) const_kw { \ return registry.expect_item_dictionary_and_length_and_default(length_callback, default_callback, callback); \ } \ - NodeTools::NodeCallback auto expect_##singular##_dictionary_and_default( \ + constexpr NodeTools::NodeCallback auto expect_##singular##_dictionary_and_default( \ NodeTools::KeyValueCallback auto default_callback, \ NodeTools::Callback auto callback \ ) const_kw { \ return registry.expect_item_dictionary_and_default(default_callback, callback); \ } \ - NodeTools::NodeCallback auto expect_##singular##_dictionary( \ + constexpr NodeTools::NodeCallback auto expect_##singular##_dictionary( \ NodeTools::Callback auto callback \ ) const_kw { \ return registry.expect_item_dictionary(callback); \ } \ template \ - NodeTools::NodeCallback auto expect_##singular##_dictionary_reserve_length_and_default( \ + constexpr NodeTools::NodeCallback auto expect_##singular##_dictionary_reserve_length_and_default( \ T& t, \ NodeTools::KeyValueCallback auto default_callback, \ NodeTools::Callback auto callback \ @@ -455,7 +550,7 @@ private: return registry.expect_item_dictionary_reserve_length_and_default(t, default_callback, callback); \ } \ template \ - NodeTools::NodeCallback auto expect_##singular##_dictionary_reserve_length( \ + constexpr NodeTools::NodeCallback auto expect_##singular##_dictionary_reserve_length( \ T& t, \ NodeTools::Callback auto callback \ ) const_kw { \ -- cgit v1.2.3-56-ga3b1