Skip to content

Commit

Permalink
item: review suggestions
Browse files Browse the repository at this point in the history
Co-authored-by: Andrew Krieger <[email protected]>
  • Loading branch information
andrei8l and akrieger committed Jan 20, 2024
1 parent b4b36bc commit 4281ba8
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 61 deletions.
52 changes: 33 additions & 19 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down Expand Up @@ -14845,6 +14846,33 @@ bool item::contents_only_one_type() const
} ) );
}

namespace
{
template <class C>
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<itype_id, typename C::key_type> ) {
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;
Expand All @@ -14857,32 +14885,17 @@ 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++;
item_category_id const cat = pkit->get_category_of_contents( depth, maxdepth ).get_id();
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 ) {
Expand All @@ -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<int>( 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 ) {
Expand Down
6 changes: 6 additions & 0 deletions src/item.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
88 changes: 46 additions & 42 deletions src/item_tname.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -71,50 +74,51 @@ enum class segments : std::size_t {
using segment_bitset = enum_bitset<tname::segments>;

#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 */ )
{
return {};
}

inline std::unordered_map<segments, decl_fsegment *> const segment_map = {
inline std::unordered_map<segments, decl_f_print_segment *> const segment_map = {
{ segments::FAULTS, faults },
{ segments::DIRT, dirt_symbol },
{ segments::OVERHEAT, overheat_symbol },
Expand Down Expand Up @@ -163,18 +167,18 @@ struct enum_traits<tname::segments> {

namespace tname
{
constexpr unsigned long long default_tname_bits =
std::numeric_limits<unsigned long long>::max() &
constexpr uint64_t default_tname_bits =
std::numeric_limits<uint64_t>::max() &
~( 1ULL << static_cast<size_t>( tname::segments::CATEGORY ) );
constexpr unsigned long long tname_prefix_bits =
constexpr uint64_t tname_prefix_bits =
1ULL << static_cast<size_t>( tname::segments::FAVORITE_PRE ) |
1ULL << static_cast<size_t>( tname::segments::DURABILITY ) |
1ULL << static_cast<size_t>( tname::segments::BURN );
constexpr unsigned long long tname_contents_bits =
constexpr uint64_t tname_contents_bits =
1ULL << static_cast<size_t>( tname::segments::CONTENTS ) |
1ULL << static_cast<size_t>( tname::segments::CONTENTS_FULL ) |
1ULL << static_cast<size_t>( 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<size_t>( tname::segments::COMPONENTS ) |
1ULL << static_cast<size_t>( tname::segments::TAGS ) |
1ULL << static_cast<size_t>( tname::segments::VARS );
Expand Down

0 comments on commit 4281ba8

Please sign in to comment.