Skip to content
Snippets Groups Projects
Object.h 8.58 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * 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 ) );
    		};
    
    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 ( ) );
    	}
    
    	/**
    	 * 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_ */