Skip to content
Snippets Groups Projects
Object.h 6.75 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include <alib/variant>
    #include <object/AnyObject.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 ) );
    		};
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		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 {
    
    	 * 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 ( ) );
    	}
    
    	/**
    
    	 * The three way comparison implementation
    
    	 * \param other the other object to compare with.
    
    	 * \returns the strong ordering between this object and the @p other.
    
    	std::strong_ordering operator <=> ( const Object & other ) const {
    		if ( this->m_data.get ( ) == other.m_data.get ( ) )
    			return std::strong_ordering::equal;
    
    		std::strong_ordering res = ( * this->m_data ) <=> ( * other.m_data );
    		if ( res == 0 )
    			const_cast < Object * > ( this )->unify ( const_cast < Object & > ( other ) );
    
    	 * The equality comparison implementation.
    
    	 * \param other the other object to compare with.
    
    	 *
    	 * \returns true if this and other objects are equal, false othervise
    	 */
    	bool operator ==( const Object & other ) const {
    
    		if ( this->m_data.get ( ) == other.m_data.get ( ) )
    			return true;
    
    		bool res = ( * this->m_data ) == ( * other.m_data );
    		if ( res )
    			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 m_data->operator std::string ( );
    
    	 * \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 */