diff --git a/src/item.cpp b/src/item.cpp index d97521755db83..c324501367a3b 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -5994,15 +5994,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } // does the item fit in any holsters? - std::vector holsters = Item_factory::find( [this]( const itype & e ) { - if( !e.can_use( "holster" ) ) { - return false; - } - const holster_actor *ptr = dynamic_cast - ( e.get_use( "holster" )->get_actor_ptr() ); - const item holster_item( &e ); - return ptr->can_holster( holster_item, *this ) && !item_is_blacklisted( holster_item.typeId() ); - } ); + std::vector holsters = item_controller->find_holster_for( *type ); if( !holsters.empty() && parts->test( iteminfo_parts::DESCRIPTION_HOLSTERS ) ) { insert_separation_line( info ); diff --git a/src/item_factory.cpp b/src/item_factory.cpp index ab112f3fb4ae7..fc30ef91da4d0 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -4832,6 +4832,7 @@ void Item_factory::reset() void Item_factory::clear() { m_template_groups.clear(); + type_contained_in_holsters.clear(); iuse_function_list.clear(); @@ -5469,6 +5470,27 @@ std::vector Item_factory::find( const std::function &Item_factory::find_holster_for( const itype &it ) +{ + const itype_id iid = it.get_id(); + if( type_contained_in_holsters.count( iid ) > 0 ) { + return type_contained_in_holsters.at( iid ); + } + const item itm( &it ); + + type_contained_in_holsters[iid] = Item_factory::find( [&itm]( const itype & e ) { + if( !e.can_use( "holster" ) ) { + return false; + } + const holster_actor *ptr = dynamic_cast + ( e.get_use( "holster" )->get_actor_ptr() ); + const item holster_item( &e ); + return ptr->can_holster( holster_item, itm ); + } ); + + return type_contained_in_holsters[iid]; +} + std::list Item_factory::subtype_replacement( const itype_id &base ) const { std::list ret; diff --git a/src/item_factory.h b/src/item_factory.h index 8a51f583a4d10..d0549d92d7795 100644 --- a/src/item_factory.h +++ b/src/item_factory.h @@ -266,6 +266,14 @@ class Item_factory /** Find all item templates (both static and runtime) matching UnaryPredicate function */ static std::vector find( const std::function &func ); + /** + * Find all holsters for itype. Uses type_contained_in_holsters cache, so it's much faster + * than constructing the result on the fly. + * + * This internally constructs an empty item from the itype. It should not be used as replacement + * for item::can_holster (for non-empty items). Ignores blacklist too. + */ + const std::vector &find_holster_for( const itype & ); std::list subtype_replacement( const itype_id & ) const; @@ -285,6 +293,9 @@ class Item_factory std::unordered_map migrated_ammo; std::unordered_map migrated_magazines; + // cache for holsters + std::unordered_map> type_contained_in_holsters; + /** Checks that ammo is listed in ammunition_type::name(). * At least one instance of this ammo type should be defined. * If any of checks fails, prints a message to the msg stream.