Skip to content

Commit

Permalink
Merge pull request #33927 from jbytheway/overhaul_object_cloning
Browse files Browse the repository at this point in the history
Overhaul object cloning
  • Loading branch information
ZhilkinSerg authored Sep 10, 2019
2 parents 93a6db1 + 4cacdd9 commit 9b0e434
Show file tree
Hide file tree
Showing 13 changed files with 270 additions and 233 deletions.
65 changes: 65 additions & 0 deletions src/clone_ptr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#ifndef CATA_CLONE_PTR_H
#define CATA_CLONE_PTR_H

#include <memory>

namespace cata
{

template<typename T>
class clone_ptr
{
public:
clone_ptr() = default;
clone_ptr( std::nullptr_t ) {}
clone_ptr( const clone_ptr &other ) : p_( other.p_ ? other.p_->clone() : nullptr ) {}
clone_ptr( clone_ptr && ) = default;
clone_ptr &operator=( const clone_ptr &other ) {
p_ = other.p_ ? other.p_->clone() : nullptr;
return *this;
}
clone_ptr &operator=( clone_ptr && ) = default;

// implicit conversion from unique_ptr
template<typename U>
clone_ptr( std::unique_ptr<U> p ) : p_( std::move( p ) ) {}

T &operator*() {
return *p_;
}
const T &operator*() const {
return *p_;
}
T *operator->() {
return p_.get();
}
const T *operator->() const {
return p_.get();
}
T *get() {
return p_.get();
}
const T *get() const {
return p_.get();
}

explicit operator bool() const {
return !!*this;
}
bool operator!() const {
return !p_;
}

friend bool operator==( const clone_ptr &l, const clone_ptr &r ) {
return l.p_ == r.p_;
}
friend bool operator!=( const clone_ptr &l, const clone_ptr &r ) {
return l.p_ != r.p_;
}
private:
std::unique_ptr<T> p_;
};

} // namespace cata

#endif // CATA_CLONE_PTR_H
3 changes: 2 additions & 1 deletion src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3027,7 +3027,8 @@ nc_color item::color_in_inventory() const
nc_color ret = is_favorite ? c_white : c_light_gray;
if( type->can_use( "learn_spell" ) ) {
const use_function *iuse = get_use( "learn_spell" );
const learn_spell_actor *actor_ptr = static_cast<learn_spell_actor *>( iuse->get_actor_ptr() );
const learn_spell_actor *actor_ptr =
static_cast<const learn_spell_actor *>( iuse->get_actor_ptr() );
for( const std::string spell_id_str : actor_ptr->spells ) {
const spell_id sp_id( spell_id_str );
if( u.magic.knows_spell( sp_id ) && !u.magic.get_spell( sp_id ).is_max_level() ) {
Expand Down
91 changes: 46 additions & 45 deletions src/item_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,8 +524,8 @@ class iuse_function_wrapper : public iuse_actor
iuse tmp;
return ( tmp.*cpp_function )( &p, &it, a, pos );
}
iuse_actor *clone() const override {
return new iuse_function_wrapper( *this );
std::unique_ptr<iuse_actor> clone() const override {
return std::make_unique<iuse_function_wrapper>( *this );
}

void load( JsonObject & ) override {}
Expand All @@ -543,13 +543,13 @@ class iuse_function_wrapper_with_info : public iuse_function_wrapper
void info( const item &, std::vector<iteminfo> &info ) const override {
info.emplace_back( "DESCRIPTION", _( info_string ) );
}
iuse_actor *clone() const override {
return new iuse_function_wrapper_with_info( *this );
std::unique_ptr<iuse_actor> clone() const override {
return std::make_unique<iuse_function_wrapper_with_info>( *this );
}
};

use_function::use_function( const std::string &type, const use_function_pointer f )
: use_function( new iuse_function_wrapper( type, f ) ) {}
: use_function( std::make_unique<iuse_function_wrapper>( type, f ) ) {}

void Item_factory::add_iuse( const std::string &type, const use_function_pointer f )
{
Expand All @@ -560,12 +560,13 @@ void Item_factory::add_iuse( const std::string &type, const use_function_pointer
const std::string &info )
{
iuse_function_list[ type ] =
use_function( new iuse_function_wrapper_with_info( type, f, info ) );
use_function( std::make_unique<iuse_function_wrapper_with_info>( type, f, info ) );
}

void Item_factory::add_actor( iuse_actor *ptr )
void Item_factory::add_actor( std::unique_ptr<iuse_actor> ptr )
{
iuse_function_list[ ptr->type ] = use_function( ptr );
std::string type = ptr->type;
iuse_function_list[ type ] = use_function( std::move( ptr ) );
}

void Item_factory::add_item_type( const itype &def )
Expand Down Expand Up @@ -778,42 +779,42 @@ void Item_factory::init()
add_iuse( "BREAK_STICK", &iuse::break_stick );
add_iuse( "MAGNESIUM_TABLET", &iuse::magnesium_tablet );

add_actor( new ammobelt_actor() );
add_actor( new bandolier_actor() );
add_actor( new cauterize_actor() );
add_actor( new consume_drug_iuse() );
add_actor( new delayed_transform_iuse() );
add_actor( new enzlave_actor() );
add_actor( new explosion_iuse() );
add_actor( new firestarter_actor() );
add_actor( new fireweapon_off_actor() );
add_actor( new fireweapon_on_actor() );
add_actor( new heal_actor() );
add_actor( new holster_actor() );
add_actor( new inscribe_actor() );
add_actor( new iuse_transform() );
add_actor( new countdown_actor() );
add_actor( new manualnoise_actor() );
add_actor( new musical_instrument_actor() );
add_actor( new pick_lock_actor() );
add_actor( new deploy_furn_actor() );
add_actor( new place_monster_iuse() );
add_actor( new reveal_map_actor() );
add_actor( new salvage_actor() );
add_actor( new unfold_vehicle_iuse() );
add_actor( new ups_based_armor_actor() );
add_actor( new place_trap_actor() );
add_actor( new emit_actor() );
add_actor( new saw_barrel_actor() );
add_actor( new install_bionic_actor() );
add_actor( new detach_gunmods_actor() );
add_actor( new mutagen_actor() );
add_actor( new mutagen_iv_actor() );
add_actor( new deploy_tent_actor() );
add_actor( new learn_spell_actor() );
add_actor( new cast_spell_actor() );
add_actor( new weigh_self_actor() );
add_actor( new sew_advanced_actor() );
add_actor( std::make_unique<ammobelt_actor>() );
add_actor( std::make_unique<bandolier_actor>() );
add_actor( std::make_unique<cauterize_actor>() );
add_actor( std::make_unique<consume_drug_iuse>() );
add_actor( std::make_unique<delayed_transform_iuse>() );
add_actor( std::make_unique<enzlave_actor>() );
add_actor( std::make_unique<explosion_iuse>() );
add_actor( std::make_unique<firestarter_actor>() );
add_actor( std::make_unique<fireweapon_off_actor>() );
add_actor( std::make_unique<fireweapon_on_actor>() );
add_actor( std::make_unique<heal_actor>() );
add_actor( std::make_unique<holster_actor>() );
add_actor( std::make_unique<inscribe_actor>() );
add_actor( std::make_unique<iuse_transform>() );
add_actor( std::make_unique<countdown_actor>() );
add_actor( std::make_unique<manualnoise_actor>() );
add_actor( std::make_unique<musical_instrument_actor>() );
add_actor( std::make_unique<pick_lock_actor>() );
add_actor( std::make_unique<deploy_furn_actor>() );
add_actor( std::make_unique<place_monster_iuse>() );
add_actor( std::make_unique<reveal_map_actor>() );
add_actor( std::make_unique<salvage_actor>() );
add_actor( std::make_unique<unfold_vehicle_iuse>() );
add_actor( std::make_unique<ups_based_armor_actor>() );
add_actor( std::make_unique<place_trap_actor>() );
add_actor( std::make_unique<emit_actor>() );
add_actor( std::make_unique<saw_barrel_actor>() );
add_actor( std::make_unique<install_bionic_actor>() );
add_actor( std::make_unique<detach_gunmods_actor>() );
add_actor( std::make_unique<mutagen_actor>() );
add_actor( std::make_unique<mutagen_iv_actor>() );
add_actor( std::make_unique<deploy_tent_actor>() );
add_actor( std::make_unique<learn_spell_actor>() );
add_actor( std::make_unique<cast_spell_actor>() );
add_actor( std::make_unique<weigh_self_actor>() );
add_actor( std::make_unique<sew_advanced_actor>() );
// An empty dummy group, it will not spawn anything. However, it makes that item group
// id valid, so it can be used all over the place without need to explicitly check for it.
m_template_groups["EMPTY_GROUP"] = std::make_unique<Item_group>( Item_group::G_COLLECTION, 100, 0,
Expand Down Expand Up @@ -2649,7 +2650,7 @@ std::pair<std::string, use_function> Item_factory::usage_from_object( JsonObject
if( type == "repair_item" ) {
type = obj.get_string( "item_action_type" );
if( !has_iuse( type ) ) {
add_actor( new repair_item_actor( type ) );
add_actor( std::make_unique<repair_item_actor>( type ) );
repair_actions.insert( type );
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/item_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ class Item_factory
void add_iuse( const std::string &type, use_function_pointer f );
void add_iuse( const std::string &type, use_function_pointer f,
const std::string &info );
void add_actor( iuse_actor *ptr );
void add_actor( std::unique_ptr<iuse_actor> );

std::map<itype_id, migration> migrations;

Expand Down
17 changes: 0 additions & 17 deletions src/iuse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9740,23 +9740,6 @@ int iuse::magic_8_ball( player *p, item *it, bool, const tripoint & )
return 0;
}

use_function::use_function( const use_function &other )
: actor( other.actor ? other.actor->clone() : nullptr )
{
}

use_function &use_function::operator=( iuse_actor *const f )
{
*this = use_function( f );
return *this;
}

use_function &use_function::operator=( const use_function &other )
{
actor.reset( other.actor ? other.actor->clone() : nullptr );
return *this;
}

void use_function::dump_info( const item &it, std::vector<iteminfo> &dump ) const
{
if( actor != nullptr ) {
Expand Down
28 changes: 12 additions & 16 deletions src/iuse.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <string>
#include <vector>

#include "clone_ptr.h"
#include "units.h"

class item;
Expand Down Expand Up @@ -252,7 +253,6 @@ using use_function_pointer = int ( iuse::* )( player *, item *, bool, const trip

class iuse_actor
{

protected:
iuse_actor( const std::string &type, int cost = -1 ) : type( type ), cost( cost ) {}

Expand All @@ -275,14 +275,14 @@ class iuse_actor
* Returns a deep copy of this object. Example implementation:
* \code
* class my_iuse_actor {
* iuse_actor *clone() const override {
* return new my_iuse_actor( *this );
* std::unique_ptr<iuse_actor> clone() const override {
* return std::make_unique<my_iuse_actor>( *this );
* }
* };
* \endcode
* The returned value should behave like the original item and must have the same type.
*/
virtual iuse_actor *clone() const = 0;
virtual std::unique_ptr<iuse_actor> clone() const = 0;
/**
* Returns whether the actor is valid (exists in the generator).
*/
Expand All @@ -299,21 +299,21 @@ class iuse_actor

struct use_function {
protected:
std::unique_ptr<iuse_actor> actor;
cata::clone_ptr<iuse_actor> actor;

public:
use_function() = default;
use_function( const std::string &type, use_function_pointer f );
use_function( iuse_actor *f ) : actor( f ) {}
use_function( use_function && ) = default;
use_function( const use_function &other );

~use_function() = default;
use_function( std::unique_ptr<iuse_actor> f ) : actor( std::move( f ) ) {}

int call( player &, item &, bool, const tripoint & ) const;
ret_val<bool> can_call( const player &p, const item &it, bool t, const tripoint &pos ) const;
ret_val<bool> can_call( const player &, const item &, bool t, const tripoint &pos ) const;

iuse_actor *get_actor_ptr() {
return actor.get();
}

iuse_actor *get_actor_ptr() const {
const iuse_actor *get_actor_ptr() const {
return actor.get();
}

Expand All @@ -327,10 +327,6 @@ struct use_function {
std::string get_name() const;
/** @return Used by @ref item::info to get description of the actor */
void dump_info( const item &, std::vector<iteminfo> & ) const;

use_function &operator=( iuse_actor *f );
use_function &operator=( use_function && ) = default;
use_function &operator=( const use_function &other );
};

#endif
Loading

0 comments on commit 9b0e434

Please sign in to comment.