diff --git a/data/json/statistics.json b/data/json/statistics.json index 16998e5dce683..ffebffbdc4fc3 100644 --- a/data/json/statistics.json +++ b/data/json/statistics.json @@ -478,7 +478,7 @@ "id": "avatar_consumes_allergen_milk", "type": "event_transformation", "event_transformation": "avatar_consumes_item_flag", - "value_constraints": { "flag": { "equals": [ "flag_str_id", "ALLERGEN_MILK" ] } }, + "value_constraints": { "flag": { "equals": [ "flag_id", "ALLERGEN_MILK" ] } }, "drop_fields": [ "flag" ] }, { @@ -492,7 +492,7 @@ "id": "avatar_consumes_allergen_eggs", "type": "event_transformation", "event_transformation": "avatar_consumes_item_flag", - "value_constraints": { "flag": { "equals": [ "flag_str_id", "ALLERGEN_EGG" ] } }, + "value_constraints": { "flag": { "equals": [ "flag_id", "ALLERGEN_EGG" ] } }, "drop_fields": [ "flag" ] }, { @@ -506,7 +506,7 @@ "id": "avatar_consumes_allergen_meat", "type": "event_transformation", "event_transformation": "avatar_consumes_item_flag", - "value_constraints": { "flag": { "equals": [ "flag_str_id", "ALLERGEN_MEAT" ] } }, + "value_constraints": { "flag": { "equals": [ "flag_id", "ALLERGEN_MEAT" ] } }, "drop_fields": [ "flag" ] }, { diff --git a/src/cata_variant.cpp b/src/cata_variant.cpp index 71d9e71a3d39a..f07b6d79fa6e5 100644 --- a/src/cata_variant.cpp +++ b/src/cata_variant.cpp @@ -49,7 +49,6 @@ std::string enum_to_string( cata_variant_type type ) case cata_variant_type::furn_id: return "furn_id"; case cata_variant_type::furn_str_id: return "furn_str_id"; case cata_variant_type::flag_id: return "flag_id"; - case cata_variant_type::flag_str_id: return "flag_str_id"; case cata_variant_type::int_: return "int"; case cata_variant_type::itype_id: return "itype_id"; case cata_variant_type::matype_id: return "matype_id"; diff --git a/src/cata_variant.h b/src/cata_variant.h index f1c47e30633ad..aaf62bd1bb69b 100644 --- a/src/cata_variant.h +++ b/src/cata_variant.h @@ -47,7 +47,6 @@ enum class cata_variant_type : int { furn_id, furn_str_id, flag_id, - flag_str_id, int_, itype_id, matype_id, @@ -174,7 +173,7 @@ struct convert_enum { }; // These are the specializations of convert for each value type. -static_assert( static_cast( cata_variant_type::num_types ) == 34, +static_assert( static_cast( cata_variant_type::num_types ) == 33, "This assert is a reminder to add conversion support for any new types to the " "below specializations" ); @@ -260,10 +259,7 @@ template<> struct convert : convert_string_id {}; template<> -struct convert : convert_string_id {}; - -template<> -struct convert : convert_int_id {}; +struct convert : convert_string_id {}; template<> struct convert { diff --git a/src/editmap.cpp b/src/editmap.cpp index ceed5f8eed01f..8aacf4e591b51 100644 --- a/src/editmap.cpp +++ b/src/editmap.cpp @@ -1444,7 +1444,7 @@ void editmap::edit_itm() imenu.addentry( imenu_tags, true, -1, pgettext( "item manipulation debug menu entry", "tags: %s" ), debug_menu::iterable_to_string( it.get_flags(), " ", []( const flag_id & f ) { - return f.id().str(); + return f.str(); } ) ); imenu.addentry( imenu_sep, false, 0, pgettext( "item manipulation debug menu entry", "-[ light emission ]-" ) ); @@ -1476,7 +1476,7 @@ void editmap::edit_itm() case imenu_tags: strval = debug_menu::iterable_to_string( it.get_flags(), " ", []( const flag_id & f ) { - return f.id().str(); + return f.str(); } ); break; } @@ -1517,7 +1517,7 @@ void editmap::edit_itm() } imenu.entries[imenu_tags].txt = debug_menu::iterable_to_string( it.get_flags(), " ", []( const flag_id & f ) { - return f.id().str(); + return f.str(); } ); break; } diff --git a/src/effect.cpp b/src/effect.cpp index a065d71eeb16b..cd1bd8c007a72 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -401,14 +401,7 @@ bool effect_type::load_mod_data( const JsonObject &jo, const std::string &member bool effect_type::has_flag( const flag_id &flag ) const { - // initialize int_flags cache on first usage - if( flags.size() > int_flags.size() ) { - int_flags.clear(); - for( const flag_str_id &f : flags ) { - int_flags.insert( f ); - } - } - return int_flags.count( flag ); + return flags.count( flag ); } effect_rating effect_type::get_rating() const diff --git a/src/effect.h b/src/effect.h index 93ed132f99948..dcd7457afcd7e 100644 --- a/src/effect.h +++ b/src/effect.h @@ -111,7 +111,6 @@ class effect_type time_duration int_dur_factor = 0_turns; std::set flags; - mutable cata::flat_set int_flags; bool main_parts_only = false; diff --git a/src/event_field_transformations.cpp b/src/event_field_transformations.cpp index c9851603fe41f..056a5e2548b03 100644 --- a/src/event_field_transformations.cpp +++ b/src/event_field_transformations.cpp @@ -16,7 +16,7 @@ static std::vector flags_of_itype( const cata_variant &v ) std::vector result; result.reserve( flags.size() ); for( const flag_id &s : flags ) { - result.push_back( cata_variant::make( s.id() ) ); + result.push_back( cata_variant::make( s ) ); } return result; } @@ -69,7 +69,7 @@ static std::vector species_of_monster( const cata_variant &v ) const std::unordered_map event_field_transformations = { { "flags_of_itype", - {flags_of_itype, cata_variant_type::flag_str_id, { cata_variant_type::itype_id}} + {flags_of_itype, cata_variant_type::flag_id, { cata_variant_type::itype_id}} }, { "flags_of_terrain", diff --git a/src/flag.cpp b/src/flag.cpp index 23ab4ad3f114f..632ab343f43bf 100644 --- a/src/flag.cpp +++ b/src/flag.cpp @@ -321,66 +321,25 @@ const flag_str_id flag_NOT_FOOTWEAR( "NOT_FOOTWEAR" ); const flag_str_id flag_SOFT( "SOFT" ); const flag_str_id flag_HARD( "HARD" ); - namespace { generic_factory json_flags_all( "json_flags" ); } // namespace -/** @relates int_id */ -template<> -bool flag_id ::is_valid() const -{ - return json_flags_all.is_valid( *this ); -} - -/** @relates int_id */ -template<> -const json_flag &flag_id::obj() const -{ - return json_flags_all.obj( *this ); -} - -/** @relates int_id */ -template<> -const flag_str_id &flag_id::id() const -{ - return json_flags_all.convert( *this ); -} - /** @relates string_id */ template<> -bool flag_str_id ::is_valid() const +bool flag_id::is_valid() const { return json_flags_all.is_valid( *this ); } /** @relates string_id */ template<> -const json_flag &flag_str_id::obj() const +const json_flag &flag_id::obj() const { return json_flags_all.obj( *this ); } -template<> -flag_id flag_str_id::id_or( const flag_id &fallback ) const -{ - return json_flags_all.convert( *this, fallback, false ); -} - -/** @relates string_id */ -template<> -flag_id flag_str_id::id() const -{ - return json_flags_all.convert( *this, flag_id( -1 ) ); -} - -/** @relates int_id */ -template<> -flag_id::int_id( const flag_str_id &id ) : _id( id.id() ) -{ -} - json_flag::operator bool() const { return id.is_valid(); diff --git a/src/item.cpp b/src/item.cpp index 089999b2ed191..b6a5c68392ec6 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1635,7 +1635,7 @@ void item::debug_info( std::vector &info, const iteminfo_query *parts, info.push_back( iteminfo( "BASE", _( "burn: " ), "", iteminfo::lower_is_better, burnt ) ); const std::string tags_listed = enumerate_as_string( item_tags, []( const flag_id & f ) { - return f.id().str(); + return f.str(); }, enumeration_conjunction::none ); info.push_back( iteminfo( "BASE", string_format( _( "tags: %s" ), tags_listed ) ) ); @@ -5320,7 +5320,7 @@ bool item::has_flag( const flag_id &f ) const { bool ret = false; if( !f.is_valid() ) { - debugmsg( "Attempted to check invalid flag_id %d", f.to_i() ); + debugmsg( "Attempted to check invalid flag_id %s", f.str() ); return false; } @@ -5350,7 +5350,7 @@ item &item::set_flag( const flag_id &flag ) item_tags.insert( flag ); requires_tags_processing = true; } else { - debugmsg( "Attempted to set invalid flag_id %d", flag.to_i() ); + debugmsg( "Attempted to set invalid flag_id %s", flag.str() ); } return *this; } diff --git a/src/item_factory.cpp b/src/item_factory.cpp index c2041f91c2e37..8dca5a43be8b5 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -139,7 +139,7 @@ void Item_factory::finalize_pre( itype &obj ) { // TODO: separate repairing from reinforcing/enhancement if( obj.damage_max() == obj.damage_min() ) { - obj.item_tags_str_tmp.insert( flag_NO_REPAIR ); + obj.item_tags.insert( flag_NO_REPAIR ); } if( obj.has_flag( flag_STAB ) || obj.has_flag( flag_SPEAR ) ) { @@ -209,15 +209,15 @@ void Item_factory::finalize_pre( itype &obj ) } // set light_emission based on LIGHT_[X] flag - for( const auto &f : obj.item_tags_str_tmp ) { + for( const auto &f : obj.item_tags ) { int ll; if( sscanf( f.c_str(), "LIGHT_%i", &ll ) == 1 && ll > 0 ) { obj.light_emission = ll; } } // remove LIGHT_[X] flags - erase_if( obj.item_tags_str_tmp, []( const flag_str_id & f ) { - return f.str().find( "LIGHT_" ) == 0; + erase_if( obj.item_tags, []( const flag_str_id & f ) { + return string_starts_with( f.str(), "LIGHT_" ); } ); // for ammo not specifying loudness (or an explicit zero) derive value from other properties @@ -394,8 +394,8 @@ void Item_factory::finalize_pre( itype &obj ) // TODO: Move to jsons? if( obj.gun->skill_used == skill_id( "archery" ) || obj.gun->skill_used == skill_id( "throw" ) ) { - obj.item_tags_str_tmp.insert( flag_WATERPROOF_GUN ); - obj.item_tags_str_tmp.insert( flag_NEVER_JAMS ); + obj.item_tags.insert( flag_WATERPROOF_GUN ); + obj.item_tags.insert( flag_NEVER_JAMS ); obj.gun->ammo_effects.insert( "NEVER_MISFIRES" ); } } @@ -495,25 +495,14 @@ void Item_factory::register_cached_uses( const itype &obj ) void Item_factory::finalize_post( itype &obj ) { - // copy string flags into int flags - if( !obj.item_tags.empty() ) { - debugmsg( "during finalization, itype '%s' has non-empty int_id flags set: [%s]", obj.id.str(), - debug_menu::iterable_to_string( obj.item_tags, ", ", - []( const flag_id & f ) { - return f.id().str() + " (id: " + std::to_string( f.to_i() ) + ")"; - } ) ); - obj.item_tags.clear(); - } - for( const flag_str_id &f : obj.item_tags_str_tmp ) { + erase_if( obj.item_tags, [&]( const flag_str_id & f ) { if( !f.is_valid() ) { debugmsg( "itype '%s' uses undefined flag '%s'. Please add corresponding 'json_flag' entry to json.", obj.id.str(), f.str() ); - } else { - obj.item_tags.insert( f ); + return true; } - } - // now `has_flags` will use `item_tags` for all lookups - obj.item_tags_str_tmp.clear(); + return false; + } ); // handle complex firearms as a special case if( obj.gun && !obj.has_flag( flag_PRIMITIVE_RANGED_WEAPON ) ) { @@ -2501,7 +2490,7 @@ void Item_factory::set_allergy_flags( itype &item_template ) const auto &mats = item_template.materials; for( const auto &pr : all_pairs ) { if( std::find( mats.begin(), mats.end(), pr.first ) != mats.end() ) { - item_template.item_tags_str_tmp.insert( pr.second ); + item_template.item_tags.insert( pr.second ); } } } @@ -2523,29 +2512,29 @@ void hflesh_to_flesh( itype &item_template ) void Item_factory::npc_implied_flags( itype &item_template ) { if( item_template.use_methods.count( "explosion" ) > 0 ) { - item_template.item_tags_str_tmp.insert( flag_DANGEROUS ); + item_template.item_tags.insert( flag_DANGEROUS ); } if( item_template.has_flag( flag_DANGEROUS ) > 0 ) { - item_template.item_tags_str_tmp.insert( flag_NPC_THROW_NOW ); + item_template.item_tags.insert( flag_NPC_THROW_NOW ); } if( item_template.has_flag( flag_BOMB ) > 0 ) { - item_template.item_tags_str_tmp.insert( flag_NPC_ACTIVATE ); + item_template.item_tags.insert( flag_NPC_ACTIVATE ); } if( item_template.has_flag( flag_NPC_THROW_NOW ) > 0 ) { - item_template.item_tags_str_tmp.insert( flag_NPC_THROWN ); + item_template.item_tags.insert( flag_NPC_THROWN ); } if( item_template.has_flag( flag_NPC_ACTIVATE ) > 0 || item_template.has_flag( flag_NPC_THROWN ) > 0 ) { - item_template.item_tags_str_tmp.insert( flag_NPC_ALT_ATTACK ); + item_template.item_tags.insert( flag_NPC_ALT_ATTACK ); } if( item_template.has_flag( flag_DANGEROUS ) > 0 || item_template.has_flag( flag_PSEUDO ) > 0 ) { - item_template.item_tags_str_tmp.insert( flag_TRADER_AVOID ); + item_template.item_tags.insert( flag_TRADER_AVOID ); } } @@ -2908,7 +2897,7 @@ void Item_factory::load_basic_info( const JsonObject &jo, itype &def, const std: def.explosion = load_explosion_data( je ); } - assign( jo, "flags", def.item_tags_str_tmp ); + assign( jo, "flags", def.item_tags ); assign( jo, "faults", def.faults ); if( jo.has_member( "qualities" ) ) { diff --git a/src/item_pocket.cpp b/src/item_pocket.cpp index cf166482bfd90..c1c6196ac1b1f 100644 --- a/src/item_pocket.cpp +++ b/src/item_pocket.cpp @@ -144,7 +144,7 @@ void pocket_data::load( const JsonObject &jo ) optional( jo, was_loaded, "watertight", watertight, false ); optional( jo, was_loaded, "airtight", airtight, false ); optional( jo, was_loaded, "open_container", open_container, false ); - optional( jo, was_loaded, "flag_restriction", flag_restrictions_str ); + optional( jo, was_loaded, "flag_restriction", flag_restrictions ); optional( jo, was_loaded, "rigid", rigid, false ); optional( jo, was_loaded, "holster", holster ); optional( jo, was_loaded, "sealed_data", sealed_data ); @@ -178,19 +178,12 @@ bool pocket_data::operator==( const pocket_data &rhs ) const const pocket_data::FlagsSetType &pocket_data::get_flag_restrictions() const { - if( !flag_restrictions_str.empty() ) { - for( const auto &f : flag_restrictions_str ) { - flag_restrictions_int.insert( f ); - } - flag_restrictions_str.clear(); - } - return flag_restrictions_int; + return flag_restrictions; } void pocket_data::add_flag_restriction( const flag_str_id &flag ) { - flag_restrictions_str.insert( flag ); - flag_restrictions_int.insert( flag ); + flag_restrictions.insert( flag ); } bool item_pocket::same_contents( const item_pocket &rhs ) const diff --git a/src/item_pocket.h b/src/item_pocket.h index 425657e3cff55..93d8b7475cdc0 100644 --- a/src/item_pocket.h +++ b/src/item_pocket.h @@ -396,11 +396,8 @@ class pocket_data void load( const JsonObject &jo ); void deserialize( JsonIn &jsin ); private: - // `flag_restrictions_str` is filled on load and might be changed by `add_flag_restriction` - // when the accessor, `get_flag_restrictions`, is called, flags are moved from - // `flag_restrictions_str` into `flag_restrictions_int` and `flag_restrictions_str` is cleared. - mutable std::set flag_restrictions_str; - mutable FlagsSetType flag_restrictions_int; + + FlagsSetType flag_restrictions; }; template<> diff --git a/src/itype.cpp b/src/itype.cpp index 8e020dbd9052a..e0d1090582a7e 100644 --- a/src/itype.cpp +++ b/src/itype.cpp @@ -69,18 +69,6 @@ bool itype::has_use() const return !use_methods.empty(); } -bool itype::has_flag( const flag_str_id &flag ) const -{ - // whichever collection is not empty is used - // if both are empty, either will do - // (see `item_tags_str_tmp` and Item_factory::finalize_post) - if( item_tags_str_tmp.size() > item_tags.size() ) { - return item_tags_str_tmp.count( flag ); - } else { - return has_flag( flag.id() ); - } -} - bool itype::has_flag( const flag_id &flag ) const { return item_tags.count( flag ); diff --git a/src/itype.h b/src/itype.h index b8a4ff5877207..9b4fad0de63f9 100644 --- a/src/itype.h +++ b/src/itype.h @@ -1024,10 +1024,6 @@ struct itype { int damage_max_ = +4000; /// @} - // Temporary storage of flags before entity is finalized. - // During finalization, flags are moved into `item_tags` and `item_tags_str_tmp` is cleared. - // This deferred flag conversion is necessary, as some flags might not be loaded yet when `itype` is loaded. - std::set item_tags_str_tmp; FlagsSetType item_tags; protected: @@ -1121,7 +1117,6 @@ struct itype { bool has_use() const; bool has_flag( const flag_id &flag ) const; - bool has_flag( const flag_str_id &flag ) const; // returns read-only set of all item tags/flags const FlagsSetType &get_flags() const; diff --git a/src/type_id.h b/src/type_id.h index f4e4e9b712909..68665025c7578 100644 --- a/src/type_id.h +++ b/src/type_id.h @@ -209,7 +209,8 @@ using construction_id = int_id; using construction_str_id = string_id; class json_flag; -using flag_id = int_id; -using flag_str_id = string_id; +// flag_id and flag_str_id are synonyms for now +using flag_id = string_id; +using flag_str_id = flag_id; #endif // CATA_SRC_TYPE_ID_H diff --git a/src/wish.cpp b/src/wish.cpp index 79bc5f78c8ccb..d12cc73c9f5d3 100644 --- a/src/wish.cpp +++ b/src/wish.cpp @@ -483,7 +483,7 @@ class wish_item_callback: public uilist_callback // grab default flags for the itype flags = debug_menu::iterable_to_string( selected_itype.get_flags(), " ", []( const flag_id & f ) { - return f.id().str(); + return f.str(); } ); } diff --git a/tests/generic_factory_test.cpp b/tests/generic_factory_test.cpp index 948d37dd60919..4f1f705db61ee 100644 --- a/tests/generic_factory_test.cpp +++ b/tests/generic_factory_test.cpp @@ -2,7 +2,6 @@ #include "catch/catch.hpp" #include "colony_list_test_helpers.h" -#include "flag.h" #include "generic_factory.h" #ifdef _MSC_VER @@ -257,16 +256,44 @@ namespace { struct dyn_test_obj {}; using dyn_str_id = string_id; + +struct stat_test_obj { + string_id id; + bool was_loaded = false; +}; +using stat_str_id = string_id; +using stat_int_id = int_id; +int_id stat_int_id_null( -1 ); + +generic_factory stat_test_obj_factory( "stat_test_obj" ); } // namespace +// standard "generic_factory" methods to support the benchmark below +template<> int_id string_id::id() const +{ + return stat_test_obj_factory.convert( *this, stat_int_id_null ); +} +template<> int_id::int_id( const string_id &id ) : _id( id.id() ) {} +template<> const stat_test_obj &string_id::obj() const +{ + return stat_test_obj_factory.obj( *this ); +} + // mark string_id as dynamic/non-interned template<> struct string_id_params { static constexpr bool dynamic = true; }; // compares the lookup performance of different flag container implementations -TEST_CASE( "flags_benchmark", "[.][generic_factory][int_id][string_id][benchmark]" ) +TEST_CASE( "string_and_int_ids_benchmark", "[.][generic_factory][int_id][string_id][benchmark]" ) { + stat_test_obj_factory.reset(); + for( int i = 0; i < 1000; i ++ ) { + stat_test_obj_factory.insert( { + string_id( "stat_test_id_" + std::to_string( i ) ) + } ); + } + static constexpr int bit_flags_size = 100; static constexpr int bloom_size = 64; @@ -278,21 +305,21 @@ TEST_CASE( "flags_benchmark", "[.][generic_factory][int_id][string_id][benchmark struct fake_item { int dummy; std::bitset bit_flags; - std::set std_set_string_ids; - cata::flat_set flat_set_string_ids; - std::unordered_set uo_set_string_ids; + std::set std_set_string_ids; + cata::flat_set flat_set_string_ids; + std::unordered_set uo_set_string_ids; std::set std_set_dyn_string_ids; cata::flat_set flat_set_dyn_string_ids; std::unordered_set uo_set_dyn_string_ids; std::bitset bloom; - std::set std_set_int_ids; - std::unordered_set std_uo_set_int_ids; + std::set std_set_int_ids; + std::unordered_set std_uo_set_int_ids; std::set std_set_std_strings; cata::flat_set flat_set_std_strings; - cata::flat_set flat_set_int_ids; - std::vector vector_int_ids; + cata::flat_set flat_set_int_ids; + std::vector vector_int_ids; - void set_flag( const flag_str_id &flag ) { + void set_flag( const stat_str_id &flag ) { const auto int_id = flag.id(); const int i = int_id.to_i(); bit_flags[i % bit_flags_size] = true; @@ -315,7 +342,7 @@ TEST_CASE( "flags_benchmark", "[.][generic_factory][int_id][string_id][benchmark } } item; - const auto &all_flags = json_flag::get_all(); + const auto &all_flags = stat_test_obj_factory.get_all(); const int all_flags_n = static_cast( all_flags.size() ); REQUIRE( all_flags_n >= 10 ); @@ -328,7 +355,7 @@ TEST_CASE( "flags_benchmark", "[.][generic_factory][int_id][string_id][benchmark item.set_flag( all_flags[xor_rand() % all_flags_n].id ); } - std::vector test_flags; + std::vector test_flags; bool hits = GENERATE( false, true ); if( hits ) { // populate only with flags that exist in the item @@ -413,8 +440,7 @@ TEST_CASE( "flags_benchmark", "[.][generic_factory][int_id][string_id][benchmark }; BENCHMARK( "std::vector" ) { - const std::vector &v = item.vector_int_ids; + const std::vector &v = item.vector_int_ids; return std::find( v.begin(), v.end(), test_flags[( i++ ) % test_flags_size] ) != v.end(); }; - }