peerplays-fc/include/fc/shared_impl.hpp
Daniel Larimer 161ce54cb8 windows port
2012-12-18 14:37:14 -05:00

163 lines
5.4 KiB
C++

#pragma once
#include <fc/shared_ptr.hpp>
namespace fc {
/**
* @class shared_impl<T>
* @brief used to create types with reference semantics
*
* A type with reference semantics is effectively a shared pointer except that
* it is used like a Java or C# type using '.' notation instead of -> notation.
*
* It is ideal for use with classes that almost always get managed by a shared
* pointer (sockets and long-lived resources). These types are rarely, if ever
* copied by value and often by-value copy or 'deep-copy' has no real meaning.
*
* An additional feature of shared_impl<T> is that your classes implementation
* should be private and defined entirely in your source file. There should be
* no member variables defined in your types header.
*
* To make this design pattern work requires a lot of 'boiler-plate' code for
* handling assignments, moves, copies, etc that cannot be provided via tradtional
* means such as templates or base classes.
*
* To create a new type with reference semantics you place FC_REFERENCE_TYPE(type)
* inside the private section of 'type'. Then in your source file you will
* need to define your 'private' data.
*
* @code
* #include <your_type.hpp>
*
* FC_START_SHARED_IMPL( your_namespace::your_type )
* impl( int x, int y ); // custom constructor
*
* ...
* int member_variable;
* your private member variables / methods go here.
* ...
* FC_END_SHARED_IMPL
* #include <fc/shared_impl.cpp>
* @endcode
*
*
* Lastly, you will need to provide the implementation your class below. This
* implementation will need to provide the matching implementations for the
* methods declared by FC_REFERENCE_TYPE(type) in your header. To do this
* use the FC_REFERENCE_TYPE_IMPL(type)
*
* @code
* namespace your_namespace {
* FC_REFERENCE_TYPE(your_type)
* ... your methods here...
* }
* @endcode
*
* Within the body of your methods you can access your private data and members
* via using 'my->member_variable'
*
* If you want to define custom constructors for your reference type, you will
* need to implement them inside the FC_START_SHARED_IMPL block using the pattern:
*
* @code
* FC_START_SHARED_IMPL( your_namespace::your_type )
* impl( int x, int y ){} // custom constructor
* FC_END_SHARED_IMPL
* @code
*
* A limited number (3) of arguments are supported for custom constructors.
*
* Once you have defined your reference type you can use it like so:
*
* @code
* your_type val = nullptr; // create a null type
* your_type val2 = new your_type(...); // construct a new instance, unnecessary temporary heap alloc
* your_type val3(...); // constructs a new instance, more effecient
*
* val2.your_method();
* val2 = nullptr; // reset val2 to a null object
*
* val2 = val3; // val2 and val3 now reference the same data
* if( !!val2 ){} // val2 is not null
* else{} // val2 is null
* @endcode
*
* As you can see, when creating types with this method your code will
* look and act like a Java or C# garbage collected type.
*
* Often times your private methods will need to call your public methods, to achieve
* this you can use the following techinque:
*
* @code
* FC_START_SHARED_IMPL( your_namespace::your_type )
* void private_method( int x, int y ){
* auto s = self();
* s.public_method();
* }
* FC_END_SHARED_IMPL
* @code
*
* For performance reasons, it is best to only call 'self()' once and save the
* result to avoid unnecessary copies of shared pointers which require atomic
* operations.
*
*/
template<typename T>
struct shared_impl {
class impl;
impl& operator* ()const;
impl* operator-> ()const;
bool operator !()const;
template<typename U>
explicit shared_impl( U&& u );
shared_impl( const shared_impl& u );
// shared_impl( shared_impl& u );
shared_impl( shared_impl&& u );
shared_impl& operator=( shared_impl&& u );
shared_impl& operator=( const shared_impl& u );
~shared_impl();
fc::shared_ptr<typename shared_impl<T>::impl> _impl;
};
}
#define FC_REFERENCE_TYPE( TYPE ) \
public:\
TYPE(); \
TYPE( std::nullptr_t ); \
TYPE( TYPE* ); \
TYPE( TYPE&& ); \
TYPE( const TYPE& ); \
template<typename A1> \
TYPE( A1&& ); \
template<typename A1,typename A2> \
TYPE( A1&&, A2&& ); \
template<typename A1,typename A2, typename A3> \
TYPE( A1&&, A2&&, A3&& ); \
~TYPE(); \
bool operator !()const; \
friend bool operator==( const TYPE& a, const TYPE& b ); \
friend bool operator!=( const TYPE& a, const TYPE& b ); \
TYPE& operator = ( const TYPE& ); \
TYPE& operator = ( TYPE&& );\
TYPE& operator = ( TYPE* );\
TYPE& operator = ( std::nullptr_t );\
private: \
friend class shared_impl<TYPE>::impl; \
TYPE( shared_impl<TYPE>::impl* m ); \
shared_impl<TYPE> my;
#define FC_START_SHARED_IMPL( SCOPED_TYPE ) \
namespace fc { \
template<> \
class fc::shared_impl<SCOPED_TYPE>::impl : public fc::retainable { \
public:\
SCOPED_TYPE self() { return SCOPED_TYPE(this); } \
#define FC_END_SHARED_IMPL }; }