/* * Object.h * * Created on: Apr 10, 2013 * Author: Martin Zak */ #ifndef OBJECT_H_ #define OBJECT_H_ #include <alib/variant> #include <object/AnyObject.h> #include <object/Void.h> namespace object { /** * Wrapper around object. */ class Object { /** * The wrapped data. */ ext::cow_shared_ptr < AnyObjectBase > m_data; /** * \brief * Unifies the shared pointers. For internal use when two pointer eval equal. */ void unify ( Object & other ) { if ( this->m_data.use_count ( ) > other.m_data.use_count ( ) ) other.m_data = this->m_data; else this->m_data = other.m_data; } /** * \brief * Helper method to detect variant content and call make method on the object from inside of the variant. */ template < class Variant > static Object processVariant ( Variant && data ) { auto visitor = [] ( auto && element ) { return Object ( std::forward < decltype ( element ) > ( element ) ); }; return ext::visit ( visitor, std::forward < Variant > ( data ) ); } /** * Constructor that wraps raw pointer. Takes ownership of the pointer. */ explicit Object ( AnyObjectBase * data ) : m_data ( data ) { } /** * Sets the wrapped object from raw pointer. Takes ownership of the pointer. * * Internally handles situation like storing the same value that is already wrapped. Usefull in normalisation. */ void setData ( AnyObjectBase * data ) { if ( & getData ( ) == data ) return; this->m_data = ext::cow_shared_ptr < AnyObjectBase > ( data ); } public: /** * \brief * Specialisation of the make method for c-strings. */ explicit Object ( const char * string ) : Object ( ( std::string ) string ) { } /** * \brief * Specialisation of the make method for objects that are not from the object hierarchy of Algorithms library */ template < class Type, typename Enable = std::enable_if < ! std::is_same_v < std::decay_t < Type >, Object >, void > > explicit Object ( Type && data ) : Object ( object::AnyObject < typename std::decay < Type >::type > ( std::forward < Type > ( data ) ) ) { } /** * \brief * Specialisation of the make method for variants. * * \details * The resulting object is not constructed from the variant itself but from the value stored inside. If the value stored inside the variant is variant again, the process is repeated. */ template < class ... Types > explicit Object ( ext::variant < Types ... > && data ) : Object ( processVariant ( std::move ( data ) ) ) { } /** * \brief * Specialisation of the make method for variants. * * \details * The resulting object is not constructed from the variant itself but from the value stored inside. If the value stored inside the variant is variant again, the process is repeated. */ template < class ... Types > explicit Object ( const ext::variant < Types ... > & data ) : Object ( processVariant ( data ) ) { } /** * Constructor that wraps an object given by a constant reference. Uses clone of the parameter internally. */ template < class Type > explicit Object ( const AnyObject < Type > & data ) : m_data ( data.clone ( ) ) { } /** * Constructor that wraps an object given by a reference. Uses clone of the parameter internally. */ template < class Type > explicit Object ( AnyObject < Type > & data ) : m_data ( data.clone ( ) ) { } /** * Constructor that wraps an object given by an r-value reference. Uses clone of the parameter internally. */ template < class Type > explicit Object ( AnyObject < Type > && data ) : m_data ( std::move ( data ).clone ( ) ) { } /** * Constructor that wraps an object given by constant reference. Uses clone of the parameter internally. */ explicit Object ( const AnyObject < object::Object > & data ) : Object ( data.getData ( ) ) { } /** * Constructor that wraps an object given by r-value reference. Uses clone of the parameter internally. */ explicit Object ( AnyObject < object::Object > && data ) : Object ( std::move ( data ).getData ( ) ) { } /** * Gets the wrapped object. * * \returns wrapped object. */ const AnyObjectBase & getData ( ) const { return * m_data; } /** * Gets the wrapped object. * * \returns wrapped object. */ AnyObjectBase & getData ( ) { return * m_data; } /** * Sets the wrapped object from constant reference. Uses clone of the parameter internally. */ void setData ( const AnyObjectBase & data ) { setData ( data.clone ( ) ); } /** * Sets the wrapped object from r-value reference. Uses clone of the parameter internally. */ void setData ( AnyObjectBase && data ) { setData ( std::move ( data ).clone ( ) ); } /** * Determines whether this object is bigger or equal in relation to the other object. * * \returns true if this object is bigger or equal than other object are not equal, false othervise */ bool operator >=( const Object & other ) const { return this->compare ( other ) >= 0; } /** * Determines whether this object is smaller or equal in relation to the other object. * * \returns true if this object is smaller or equal than other object are not equal, false othervise */ bool operator <=( const Object & other ) const { return this->compare ( other ) <= 0; } /** * Determines whether this object is strictly bigger in relation to the other object. * * \returns true if this object is strictly bigger than other object are not equal, false othervise */ bool operator >( const Object & other ) const { return this->compare ( other ) > 0; } /** * Determines whether this object is strictly smaller in relation to the other object. * * \returns true if this object is strictly smaller than other object are not equal, false othervise */ bool operator <( const Object & other ) const { return this->compare ( other ) < 0; } /** * Compares this object with other for inequality. * * \returns true if this and other objects are not equal, false othervise */ bool operator !=( const Object & other ) const { return this->compare ( other ) != 0; } /** * Compares this object with other for equality. * * \returns true if this and other objects are equal, false othervise */ bool operator ==( const Object & other ) const { return this->compare ( other ) == 0; } /** * \brief Compares this wrapper with another, establishing relationship between them. * * \returns result of actual comparison of wrapped objects returning: * value < 0 if this < other * value == 0 if this == other * value > 0 if this > other */ int compare ( const Object & other ) const { if ( this->m_data.get ( ) == other.m_data.get ( ) ) return 0; int res = ( * this->m_data ).compare ( * other.m_data ); if ( res == 0 ) const_cast < Object * > ( this )->unify ( const_cast < Object & > ( other ) ); return res; } /** * Print the wrapped object as raw representation to ostream. * * \param os ostream where to print * \param instance wrapper to print * * \returns modified output stream */ friend std::ostream & operator <<( std::ostream & os, const Object & instance ) { instance.getData ( ) >> os; return os; } /** * Casts the wrapped object to as compact as possible string representation. * * \returns string representation of the wrapped object */ explicit operator std::string ( ) const { return ( std::string ) * m_data; } /** * \brief * Increments the unique counter of the object by one. Prefix version. * * \return this instance */ Object & operator ++ ( ) { this->getData ( ).increment ( 1 ); return *this; } /** * \brief * Increments the unique counter of the object by one. Postfix version. * * \return this instance */ Object operator ++ ( int ) { Object res = * this; ++ * this; return res; } /** * \brief * Increments the unique counter of the object. * * \param by how much to increment */ Object operator += ( unsigned by ) { this->getData ( ).increment ( by ); return *this; } /** * Getter of unique identifier * * \return the unique identifier */ unsigned getId ( ) const { return this->getData ( ).getId ( ); } }; } /* namespace object */ namespace ext { /** * Helper for comparing everything that inherits from WrapperBaseBase. */ template < > struct compare < object::Object > { /** * Compare operator that determines relation between first and second object. * * \returns value < 0 if first < second * value == 0 if first == second * value > 0 if first > second */ int operator ()( const object::Object & first, const object::Object & second ) const { return first.compare ( second ); } }; } /* namespace ext */ #endif /* OBJECT_H_ */