#pragma once #include namespace fc { /** * @class shared_impl * @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 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 * * 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 * @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 struct shared_impl { class impl; impl& operator* ()const; impl* operator-> ()const; bool operator !()const; template 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::impl> _impl; }; } #define FC_REFERENCE_TYPE( TYPE ) \ public:\ TYPE(); \ TYPE( std::nullptr_t ); \ TYPE( TYPE* ); \ TYPE( TYPE&& ); \ TYPE( const TYPE& ); \ template \ TYPE( A1&& ); \ template \ TYPE( A1&&, A2&& ); \ template \ 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::impl; \ TYPE( shared_impl::impl* m ); \ shared_impl my; #define FC_START_SHARED_IMPL( SCOPED_TYPE ) \ namespace fc { \ template<> \ class fc::shared_impl::impl : public fc::retainable { \ public:\ SCOPED_TYPE self() { return SCOPED_TYPE(this); } \ #define FC_END_SHARED_IMPL }; }