Newer
Older
* This file is part of Algorithms library toolkit.
* Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz)
* Algorithms library toolkit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* Algorithms library toolkit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Algorithms library toolkit. If not, see <http://www.gnu.org/licenses/>.
*
* Created on: May 1, 2015
* Author: Jan Travnicek
*/
#ifndef __MEMORY_HPP_
#define __MEMORY_HPP_
#include <memory>
#include <utility>
#include "compare.hpp"
#include "type_traits.hpp"
#include "clone.hpp"
/**
* \brief
* Predeclaration of copy on write shared ptr class.
*/
/**
* \brief
* Base class of classes used inside copy on write pointers.
*/
/**
* Constructor of the copy on write shared ptr base class. The use count is initialized to zero.
*/
/**
* Caries the number of uses of this instance as a managed pointer inside copy on write pointer.
*/
unsigned m_UseCount;
/**
* To make m_UseCount accessible from copy on write pointer class.
*/
template < typename T, typename Enable >
friend class cow_shared_ptr;
/**
* \brief
* Specialisation of copy on write pointer for classes based with copy on write pointer base.
*
* The class is essentially mimicking the behavior of shared_ptr. Additionaly the use of dereference (either through operator* or operator->) in non-constant context causes the managed pointer to ensure the referenced object is referenced from this class only.
*
* The class also uniques the referenced instances when they are equal.
*
* \tparam T the type of managed objects
*/
template < class T >
class cow_shared_ptr < T, typename std::enable_if < std::is_base_of < cow_shared_ptr_base, T >::value >::type > {
/**
* \brief
* Default initialization to null.
*/
/**
* \brief
* Constructor which takes ownership of the provided pointer.
*/
/**
* \brief
* Copy constructor to create new instance of shared pointer reffering the same data.
*
* \param other the source instance
*/
cow_shared_ptr ( const cow_shared_ptr & other ) {
attach ( other.m_Data );
}
/**
* \brief
* Move constructor to create new instance of shared pointer reffering the same data.
*
* \param other the source instance
*/
cow_shared_ptr ( cow_shared_ptr && other ) noexcept {
m_Data = other.m_Data;
other.m_Data = NULL;
}
/**
* \brief
* The destructor of the shared pointer.
*/
/**
* \brief
* Copy assignment operator to change reffered instace to source one.
*
* \param other the source instance
*/
cow_shared_ptr & operator =( const cow_shared_ptr & other ) {
/**
* \brief
* Move assignment operator to change reffered instace to source one.
*
* \param other the source instance
*/
cow_shared_ptr & operator =( cow_shared_ptr && other ) noexcept {
/**
* \brief
* Operator arrow to chain dereferece to inner managed pointer.
*
* \return the managed pointer
*/
/**
* \brief
* Operator arrow to chain dereferece to inner managed pointer.
*
* \return the managed pointer
*/
/**
* \brief
* Operator dereference to access the inner managed pointer.
*
* \return reference to managed data
*/
T & operator *( ) {
make_unique ( );
return * m_Data;
/**
* \brief
* Operator dereference to access the inner managed pointer.
*
* \return reference to managed data
*/
/**
* Getter of the raw managed pointer.
*
* \return the managed pointer
*/
/**
* Getter of the raw managed pointer.
*
* \return the managed pointer
*/
/**
* \brief
* Tests whether the managed pointer is referenced from one location only (or the class stores null pointer).
*
* \return bool true if the managed pointer is referenced from one location only, false otherwise
*/
bool unique ( ) const {
return m_Data == NULL || m_Data->m_UseCount == 1;
}
/**
* \brief
* Getter of the number how many times the managed pointer is referenced.
*
* \return the use count
*/
unsigned getUseCount ( ) const {
return m_Data->m_UseCount;
}
/**
* Tests the instance whether the managed pointer is valid
*
* \return true if the managed pointer is not null and the use count is nonzero, false otherwise
*/
explicit operator bool( ) const {
/**
* \brief
* Changes the managed pointer and increases its use count
*
* \param data the new value of managed pointer
*/
void attach ( T * data ) {
m_Data = data;
/**
* \brief
* Decreases the use count of managed pointer, if needed the pointer is freed. Managed pointer stored in this instance is set to null.
*/
if ( m_Data && ( --( m_Data->m_UseCount ) <= 0 ) ) delete m_Data;
/**
* \brief
* Ensures the managed pointer is unique by copy constructing the managed instance if needed.
*/
/**
* \brief
* The managed pointer
*/
/**
* \brief
* Specialisation of swap method to copy on write shared pointers.
*
* \param first the first instance
* \param second the second instance
*/
friend void swap ( cow_shared_ptr & first, cow_shared_ptr & second ) {
/**
* \brief
* Specialisation of copy on write pointer for classes not based with copy on write pointer base.
*
* The class is essentially mimicking the behavior of shared_ptr. Additionaly the use of dereference (either through operator* or operator->) in non-constant context causes the managed pointer to ensure the referenced object is referenced from this class only.
*
* The class also uniques the referenced instances when they are equal.
*
* \tparam T the type of managed objects
*/
template < class T >
class cow_shared_ptr < T, typename std::enable_if < !std::is_base_of < cow_shared_ptr_base, T >::value >::type > {
/**
* \brief
* The inner structure to hold managed pointer and its use count (the number how many times it is referenced).
*/
/**
* \brief
* The managed pointer.
*/
/**
* Caries the number of uses of this instance as a managed pointer inside copy on write pointer.
*/
unsigned m_UseCount;
/**
* \brief
* Contructs the inner shared resource based on the managed pointer.
*
* The class takes ownership of the provided pointer
*/
cow_shared_ptr_data ( T * data ) : m_Data ( data ), m_UseCount ( 0 ) { }
/**
* \brief
* Destructor to free the managed pointer.
*/
~cow_shared_ptr_data ( ) {
delete m_Data;
}
/**
* Disable copy construction.
*/
cow_shared_ptr_data ( const cow_shared_ptr_data & ) = delete;
/**
* Disable copy operator of assignment.
*/
cow_shared_ptr_data & operator = ( const cow_shared_ptr_data & ) = delete;
/**
* Disable move construction.
*/
cow_shared_ptr_data ( cow_shared_ptr_data && ) = delete;
/**
* Disable move operator of assignment.
*/
cow_shared_ptr_data & operator = ( cow_shared_ptr_data && ) = delete;
/**
* \brief
* Default initialization to null.
*/
/**
* \brief
* Constructor which takes ownership of the provided pointer.
*/
attach ( data ? new cow_shared_ptr_data ( data ) : NULL );
/**
* \brief
* Copy constructor to create new instance of shared pointer reffering the same data.
*
* \param other the source instance
*/
cow_shared_ptr ( const cow_shared_ptr & other ) {
/**
* \brief
* Move constructor to create new instance of shared pointer reffering the same data.
*
* \param other the source instance
*/
cow_shared_ptr ( cow_shared_ptr && other ) noexcept {
m_Data = other.m_Data;
other.m_Data = NULL;
/**
* \brief
* The destructor of the shared pointer.
*/
/**
* \brief
* Copy assignment operator to change reffered instace to source one.
*
* \param other the source instance
*/
cow_shared_ptr & operator =( const cow_shared_ptr & other ) {
/**
* \brief
* Move assignment operator to change reffered instace to source one.
*
* \param other the source instance
*/
cow_shared_ptr & operator =( cow_shared_ptr && other ) noexcept {
/**
* \brief
* Operator arrow to chain dereferece to inner managed pointer.
*
* \return the managed pointer
*/
/**
* \brief
* Operator arrow to chain dereferece to inner managed pointer.
*
* \return the managed pointer
*/
/**
* \brief
* Operator dereference to access the inner managed pointer.
*
* \return reference to managed data
*/
T & operator *( ) {
make_unique ( );
return * ( m_Data->m_Data );
/**
* \brief
* Operator dereference to access the inner managed pointer.
*
* \return reference to managed data
*/
T const & operator *( ) const {
return * ( m_Data->m_Data );
* Getter of the raw managed pointer.
*
* \return the managed pointer
*/
* Getter of the raw managed pointer.
*
* \return the managed pointer
*/
/**
* \brief
* Tests whether the managed pointer is referenced from one location only (or the class stores null pointer).
*
* \return bool true if the managed pointer is referenced from one location only, false otherwise
*/
return m_Data == NULL || m_Data->m_UseCount == 1;
/**
* \brief
* Getter of the number how many times the managed pointer is referenced.
*
* \return the use count
*/
unsigned getUseCount ( ) const {
if ( m_Data == NULL ) return 0;
return m_Data->m_UseCount;
}
* Tests the instance whether the managed pointer is valid
*
* \return true if the managed pointer is not null and the use count is nonzero, false otherwise
*/
explicit operator bool( ) const {
/**
* \brief
* Changes the managed pointer and increases its use count
*
* \param data the new value of managed pointer
*/
void attach ( typename cow_shared_ptr < T >::cow_shared_ptr_data * data ) {
/**
* \brief
* Decreases the use count of managed pointer, if needed the pointer is freed. Managed pointer stored in this instance is set to null.
*/
if ( m_Data && ( --( m_Data->m_UseCount ) <= 0 ) ) delete m_Data;
/**
* \brief
* Ensures the managed pointer is unique by copy constructing the managed instance if needed.
*/
typename cow_shared_ptr < T >::cow_shared_ptr_data * tmp = m_Data;
detach ( );
attach ( new cow_shared_ptr_data ( ext::clone ( * tmp->m_Data ) ) );
/**
* \brief
* The instance of sturucture containing managed pointer and its use count.
*/
/**
* \brief
* Specialisation of swap method to copy on write shared pointers.
*
* \param first the first instance
* \param second the second instance
*/
friend void swap ( cow_shared_ptr & first, cow_shared_ptr & second ) {
typename cow_shared_ptr < T >::cow_shared_ptr_data * tmp = first.m_Data;
/**
* \brief
* Managed pointer simulating value like behavior.
*
* The class is supposed to be similar to unique_ptr but allows copying of managed instance by clone method or its copy constructor.
*
* \tparam T type of managed instance
*/
/**
* \brief
* Pointer to managed object.
*/
/**
* \brief
* Default initialization to null.
*/
/**
* \brief
* Constructor which takes ownership of the provided pointer.
*/
/**
* \brief
* Conversion constructor to simplify type casting.
*
* \tparam R the type of the managed resource of the source smart pointer
*
* \param other the source instance
*/
template < class R >
smart_ptr ( smart_ptr < R > other ) : m_Data ( other.release ( ) ) {
}
/**
* \brief
* Copy constructor of the smart pointer. Internally uses clone (if available) or copy constructor of the managed resource.
*
* \param other the source instance
*/
smart_ptr ( const smart_ptr & other ) : m_Data ( ext::clone ( * other.m_Data ) ) {
/**
* \brief
* Move constructor of the smart pointer. Passes ownership of the managed resource from source to constructed instance
*
* \param other the source instance
*/
smart_ptr ( smart_ptr && other ) noexcept : m_Data ( other.release ( ) ) {
/**
* \brief
* The destructor of the shared pointer, responsible for freeing the managed resource.
*/
~smart_ptr ( ) noexcept {
delete m_Data;
}
/**
* \brief
* Copy operator of assignment. Internally uses clone (if available) or copy constructor of the managed resource.
*
* \param other the source instance
*/
smart_ptr & operator =( const smart_ptr & other ) {
if ( this == & other ) return * this;
delete m_Data;
m_Data = ext::clone ( * other.m_Data );
/**
* \brief
* Copy operator of assignment. Passes ownership of the managed resource from source to this instance.
*
* \param other the source instance
*/
smart_ptr & operator =( smart_ptr && other ) noexcept {
swap ( this->m_Data, other.m_Data );
return * this;
}
/**
* \brief
* Operator arrow to chain dereferece to inner managed pointer.
*
* \return the managed pointer
*/
/**
* \brief
* Operator arrow to chain dereferece to inner managed pointer.
*
* \return the managed pointer
*/
/**
* \brief
* Operator dereference to access the inner managed pointer.
*
* \return reference to managed data
*/
T & operator *( ) {
return * m_Data;
}
/**
* \brief
* Operator dereference to access the inner managed pointer.
*
* \return reference to managed data
*/
* Getter of the raw managed pointer.
*
* \return the managed pointer
*/
* Getter of the raw managed pointer.
*
* \return the managed pointer
*/
/**
* \brief
* Releases the shared resource and returns it.
*
* \return the released shared resource
*/
* Tests the instance whether the managed pointer is valid
*
* \return true if the managed pointer is not null, false otherwise
*/
* Operator to print the copy on write shared pointer to the output stream.
*
* \param out the output stream
* \param map the copy on write shared pointer to print
*
* \tparam T the type of managed instances inside the copy on write shared pointer
*
* \return the output stream from the \p out
*/
std::ostream & operator <<( std::ostream & out, const ext::cow_shared_ptr < T > & ptr ) {
* Operator to print the smart pointer to the output stream.
*
* \param out the output stream
* \param map the smart pointer to print
*
* \tparam T the type of managed instances inside the smart pointer
*
* \return the output stream from the \p out
*/
std::ostream & operator <<( std::ostream & out, const ext::smart_ptr < T > & ptr ) {
* Specialisation of the compare structure implementing the three-way comparison
*
* \tparam T the type of managed resource inside the copy on write shared pointer
*/
struct compare < ext::cow_shared_ptr < T > > {
* Implementation of the three-way comparison
*
* \param first the left operand of the comparison
* \param second the right operand of the comparison
*
* \return negative value of left < right, positive value if left > right, zero if left == right
*/
int operator ()( const ext::cow_shared_ptr < T > & first, const ext::cow_shared_ptr < T > & second ) const {
if ( first.get ( ) == second.get ( ) ) return 0;
if ( !first ) return -1;
if ( !second ) return 1;
static compare < typename std::decay < T >::type > comp;
return comp ( * first, * second );
}
};
* Specialisation of the compare structure implementing the three-way comparison
*
* \tparam T the type of managed resource inside the shared pointer
*/
* Implementation of the three-way comparison
*
* \param first the left operand of the comparison
* \param second the right operand of the comparison
*
* \return negative value of left < right, positive value if left > right, zero if left == right
*/
int operator ()( const std::shared_ptr < T > & first, const std::shared_ptr < T > & second ) const {
if ( first.get ( ) == second.get ( ) ) return 0;
if ( !first ) return -1;
if ( !second ) return 1;
static compare < typename std::decay < T >::type > comp;
return comp ( * first, * second );
}
};
* Specialisation of the compare structure implementing the three-way comparison
*
* \tparam T the type of managed resource inside the unique pointer
*/
* Implementation of the three-way comparison
*
* \param first the left operand of the comparison
* \param second the right operand of the comparison
*
* \return negative value of left < right, positive value if left > right, zero if left == right
*/
int operator ()( const std::unique_ptr < T > & first, const std::unique_ptr < T > & second ) const {
if ( first.get ( ) == second.get ( ) ) return 0;
if ( !first ) return -1;
if ( !second ) return 1;
static compare < typename std::decay < T >::type > comp;
return comp ( * first, * second );
}
* Specialisation of the compare structure implementing the three-way comparison
*
* \tparam T the type of managed resource inside the smart pointer
*/
struct compare < ext::smart_ptr < T > > {
/**
* Implementation of the three-way comparison
*
* \param first the left operand of the comparison
* \param second the right operand of the comparison
*
* \return negative value of left < right, positive value if left > right, zero if left == right
*/
int operator ()( const ext::smart_ptr < T > & first, const ext::smart_ptr < T > & second ) const {
if ( first.get ( ) == second.get ( ) ) return 0;
if ( !first ) return -1;
if ( !second ) return 1;
static compare < typename std::decay < T >::type > comp;