From 4281ba83e4fc3eb452e4848ff4d5607c715a26e4 Mon Sep 17 00:00:00 2001 From: andrei Date: Sat, 20 Jan 2024 02:26:19 +0200 Subject: [PATCH] item: review suggestions Co-authored-by: Andrew Krieger --- src/item.cpp | 52 +++++++++++++++++----------- src/item.h | 6 ++++ src/item_tname.h | 88 +++++++++++++++++++++++++----------------------- 3 files changed, 85 insertions(+), 61 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 4ea44add25187..ab2a051e7442d 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -12207,10 +12207,11 @@ const item_category &item::get_category_shallow() const const item_category &item::get_category_of_contents( int depth, int maxdepth ) const { - if( depth++ < maxdepth && type->category_force == item_category_container ) { + if( depth < maxdepth && type->category_force == item_category_container ) { if( cached_category.timestamp == calendar::turn ) { return cached_category.id.obj(); } + ++depth; if( item::aggregate_t const aggi = aggregated_contents( depth, maxdepth ); aggi ) { item_category const &cat = aggi.header->get_category_of_contents( depth, maxdepth ); cached_category = { cat.get_id(), calendar::turn }; @@ -14845,6 +14846,33 @@ bool item::contents_only_one_type() const } ) ); } +namespace +{ +template +void _aggregate( C &container, typename C::key_type const &key, item const *it, + item::aggregate_t *&running_max, item::aggregate_t *&max_type, int depth, + int maxdepth ) +{ + auto const [iter, emplaced] = container.emplace( key, it ); + if( emplaced && running_max == nullptr ) { + running_max = &iter->second; + max_type = running_max; + } else if( !emplaced ) { + iter->second.info.bits &= + iter->second.header->stacks_with( *it, false, false, true, depth, maxdepth ).bits; + ++iter->second.count; + + if constexpr( std::is_same_v ) { + max_type = max_type->count < iter->second.count ? &iter->second : max_type; + } else { + iter->second.info.bits.reset( tname::segments::TYPE ); + } + + running_max = running_max->count < iter->second.count ? &iter->second : running_max; + } +} +} // namespace + item::aggregate_t item::aggregated_contents( int depth, int maxdepth ) const { constexpr double cutoff = 0.5; @@ -14857,6 +14885,7 @@ item::aggregate_t item::aggregated_contents( int depth, int maxdepth ) const auto const cont_and_soft = []( item_pocket const & pkt ) { return pkt.is_type( pocket_type::CONTAINER ) || pkt.is_type( pocket_type::SOFTWARE ); }; + for( item_pocket const *pk : contents.get_pockets( cont_and_soft ) ) { for( item const *pkit : pk->all_items_top() ) { total++; @@ -14864,25 +14893,9 @@ item::aggregate_t item::aggregated_contents( int depth, int maxdepth ) const bool const type_ok = pkit->type->category_force != item_category_container || cat == item_category_container; if( type_ok ) { - if( auto const rt = types.emplace( pkit->typeId(), pkit ); rt.second && running_max == nullptr ) { - running_max = &rt.first->second; - max_type = running_max; - } else if( !rt.second ) { - rt.first->second.info.bits &= - rt.first->second.header->stacks_with( *pkit, false, false, true, depth, maxdepth ).bits; - running_max = running_max->count < ++rt.first->second.count ? &rt.first->second : running_max; - max_type = max_type->count < rt.first->second.count ? &rt.first->second : max_type; - } - } - if( auto const rc = cats.emplace( cat, pkit ); rc.second && running_max == nullptr ) { - running_max = &rc.first->second; - max_type = running_max; - } else if( !rc.second ) { - rc.first->second.info.bits &= - rc.first->second.header->stacks_with( *pkit, false, false, true, depth, maxdepth ).bits; - rc.first->second.info.bits.reset( tname::segments::TYPE ); - running_max = running_max->count < ++rc.first->second.count ? &rc.first->second : running_max; + _aggregate( types, pkit->typeId(), pkit, running_max, max_type, depth, maxdepth ); } + _aggregate( cats, cat, pkit, running_max, max_type, depth, maxdepth ); } } if( running_max == nullptr ) { @@ -14892,6 +14905,7 @@ item::aggregate_t item::aggregated_contents( int depth, int maxdepth ) const unsigned int const cutoff_check = total < 3 ? total - 1 : static_cast( std::floor( total * cutoff ) ); + // alow a type to still dominate over its own category if( max_type->count > cutoff_check && max_type->header->type->category_force != item_category_container && max_type->header->cached_category.id == running_max->header->cached_category.id ) { diff --git a/src/item.h b/src/item.h index 8d7e27b5c159f..4e98c4d7e7507 100644 --- a/src/item.h +++ b/src/item.h @@ -620,6 +620,12 @@ class item : public visitable * stacks like "3 items-count-by-charge (5)". */ bool display_stacked_with( const item &rhs, bool check_components = false ) const; + /** + * Check wether each element of tname::segments stacks, ie. wether the respective + * pieces of information are considered equal for display purposes + * + * stacking_info is implicitly convertible to bool and will be true only if ALL segments stack + */ stacking_info stacks_with( const item &rhs, bool check_components = false, bool combine_liquid = false, bool check_cat = false, int depth = 0, int maxdepth = 2, bool precise = false ) const; diff --git a/src/item_tname.h b/src/item_tname.h index 9d0cdac881458..d2396b692ca5d 100644 --- a/src/item_tname.h +++ b/src/item_tname.h @@ -13,6 +13,9 @@ class item; namespace tname { +// segments for item::tname() +// Each element corresponds to a piece of information about an item and is displayed in the item's name +// Each element is checked individually for stacking in item::stacks_with(), and all elements much stack for any 2 items to stack enum class segments : std::size_t { FAULTS = 0, DIRT, @@ -71,42 +74,43 @@ enum class segments : std::size_t { using segment_bitset = enum_bitset; #ifndef CATA_IN_TOOL -using decl_fsegment = std::string( item const &it, unsigned int quantity, - segment_bitset const &segments ); -decl_fsegment faults; -decl_fsegment dirt_symbol; -decl_fsegment overheat_symbol; -decl_fsegment pre_asterisk; -decl_fsegment durability; -decl_fsegment engine_displacement; -decl_fsegment wheel_diameter; -decl_fsegment burn; -decl_fsegment label; -decl_fsegment category; -decl_fsegment mods; -decl_fsegment craft; -decl_fsegment wbl_mark; -decl_fsegment contents; -decl_fsegment contents_abrev; -decl_fsegment food_traits; -decl_fsegment location_hint; -decl_fsegment ethereal; -decl_fsegment food_status; -decl_fsegment food_irradiated; -decl_fsegment temperature; -decl_fsegment clothing_size; -decl_fsegment filthy; -decl_fsegment broken; -decl_fsegment cbm_status; -decl_fsegment ups; -decl_fsegment wetness; -decl_fsegment active; -decl_fsegment sealed; -decl_fsegment post_asterisk; -decl_fsegment weapon_mods; -decl_fsegment relic_charges; -decl_fsegment tags; -decl_fsegment vars; +// function type that prints an element of tname::segments +using decl_f_print_segment = std::string( item const &it, unsigned int quantity, + segment_bitset const &segments ); +decl_f_print_segment faults; +decl_f_print_segment dirt_symbol; +decl_f_print_segment overheat_symbol; +decl_f_print_segment pre_asterisk; +decl_f_print_segment durability; +decl_f_print_segment engine_displacement; +decl_f_print_segment wheel_diameter; +decl_f_print_segment burn; +decl_f_print_segment label; +decl_f_print_segment category; +decl_f_print_segment mods; +decl_f_print_segment craft; +decl_f_print_segment wbl_mark; +decl_f_print_segment contents; +decl_f_print_segment contents_abrev; +decl_f_print_segment food_traits; +decl_f_print_segment location_hint; +decl_f_print_segment ethereal; +decl_f_print_segment food_status; +decl_f_print_segment food_irradiated; +decl_f_print_segment temperature; +decl_f_print_segment clothing_size; +decl_f_print_segment filthy; +decl_f_print_segment broken; +decl_f_print_segment cbm_status; +decl_f_print_segment ups; +decl_f_print_segment wetness; +decl_f_print_segment active; +decl_f_print_segment sealed; +decl_f_print_segment post_asterisk; +decl_f_print_segment weapon_mods; +decl_f_print_segment relic_charges; +decl_f_print_segment tags; +decl_f_print_segment vars; inline std::string noop( item const & /* it */, unsigned int /* quantity */, segment_bitset const & /* segments */ ) @@ -114,7 +118,7 @@ inline std::string noop( item const & /* it */, unsigned int /* quantity */, return {}; } -inline std::unordered_map const segment_map = { +inline std::unordered_map const segment_map = { { segments::FAULTS, faults }, { segments::DIRT, dirt_symbol }, { segments::OVERHEAT, overheat_symbol }, @@ -163,18 +167,18 @@ struct enum_traits { namespace tname { -constexpr unsigned long long default_tname_bits = - std::numeric_limits::max() & +constexpr uint64_t default_tname_bits = + std::numeric_limits::max() & ~( 1ULL << static_cast( tname::segments::CATEGORY ) ); -constexpr unsigned long long tname_prefix_bits = +constexpr uint64_t tname_prefix_bits = 1ULL << static_cast( tname::segments::FAVORITE_PRE ) | 1ULL << static_cast( tname::segments::DURABILITY ) | 1ULL << static_cast( tname::segments::BURN ); -constexpr unsigned long long tname_contents_bits = +constexpr uint64_t tname_contents_bits = 1ULL << static_cast( tname::segments::CONTENTS ) | 1ULL << static_cast( tname::segments::CONTENTS_FULL ) | 1ULL << static_cast( tname::segments::CONTENTS_ABREV ); -constexpr unsigned long long tname_conditional_bits = // TODO: fine grain? +constexpr uint64_t tname_conditional_bits = // TODO: fine grain? 1ULL << static_cast( tname::segments::COMPONENTS ) | 1ULL << static_cast( tname::segments::TAGS ) | 1ULL << static_cast( tname::segments::VARS );