diff --git a/include/fc/smart_ref_fwd.hpp b/include/fc/smart_ref_fwd.hpp new file mode 100644 index 0000000..145dae5 --- /dev/null +++ b/include/fc/smart_ref_fwd.hpp @@ -0,0 +1,41 @@ +#pragma once + +namespace fc { + /** + * @brief Used to forward declare value types and break circular dependencies or use heap allocation + * + * A smart reference is heap allocated, move-aware, and is gauranteed to never be null (except after a move) + */ + template + class smart_ref { + public: + template smart_ref( U&& u ); + template smart_ref( U&& u, V&& v ); + template smart_ref( U&& u, V&& v, X&&, Y&& ); + smart_ref(); + + smart_ref( const smart_ref& f ); + smart_ref( smart_ref&& f ); + + operator const T&()const; + operator T&(); + + T& operator*(); + const T& operator*()const; + const T* operator->()const; + + T* operator->(); + bool operator !()const; + + template + T& operator = ( U&& u ); + + T& operator = ( smart_ref&& u ); + T& operator = ( const smart_ref& u ); + + ~smart_ref(); + + private: + T* impl; + }; +} diff --git a/include/fc/smart_ref_impl.hpp b/include/fc/smart_ref_impl.hpp new file mode 100644 index 0000000..7c31cea --- /dev/null +++ b/include/fc/smart_ref_impl.hpp @@ -0,0 +1,105 @@ +#pragma once + +#include +#include +#include + +namespace fc { + + namespace detail { + + template + struct insert_op { + typedef decltype( *((A*)0) << *((typename fc::remove_reference::type*)0) ) type; + }; + + template + struct extract_op { + A* a; + U* u; + typedef decltype( *a >> *u ) type; + }; + } + + template + auto operator << ( U& u, const smart_ref& f ) -> typename detail::insert_op::type { return u << *f; } + + template + auto operator >> ( U& u, smart_ref& f ) -> typename detail::extract_op::type { return u >> *f; } + + template + bool smart_ref::operator !()const { return !(**this); } + + template + template + smart_ref::smart_ref( U&& u ) { + impl = new (this) T( fc::forward(u) ); + } + + template + template + smart_ref::smart_ref( U&& u, V&& v ) { + impl = new T( fc::forward(u), fc::forward(v) ); + } + template + template + smart_ref::smart_ref( U&& u, V&& v, X&& x, Y&& y ) { + impl = new T( fc::forward(u), fc::forward(v), fc::forward(x), fc::forward(y) ); + } + + template + smart_ref::smart_ref() { + impl = new T; + } + template + smart_ref::smart_ref( const smart_ref& f ){ + impl = new T( *f ); + } + template + smart_ref::smart_ref( smart_ref&& f ){ + impl = new T( fc::move(*f) ); + } + + template + smart_ref::operator T&() { return *impl; } + template + smart_ref::operator const T&()const { return *impl; } + + template + T& smart_ref::operator*() { return *impl; } + template + const T& smart_ref::operator*()const { return *impl; } + template + const T* smart_ref::operator->()const { return impl; } + + template + T* smart_ref::operator->(){ return impl; } + + template + smart_ref::~smart_ref() { + delete impl; + } + + template + template + T& smart_ref::operator = ( U&& u ) { + return **this = fc::forward(u); + } + + template + T& smart_ref::operator = ( smart_ref&& u ) { + if( &u == this ) return *impl; + if( impl ) delete impl; + impl = u.impl; + u.impl = nullptr; + return *impl; + } + + template + T& smart_ref::operator = ( const smart_ref& u ) { + if( &u == this ) return *impl; + return **this = *u; + } + +} // namespace fc +