From 84fccb72fcfbbdaf21aa7d6e556cec85b873a2b6 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Sun, 4 Nov 2018 09:38:27 +0100
Subject: [PATCH] simplify cow_shared_ptr implementation

---
 alib2common/src/object/AnyObjectBase.h       |   2 +-
 alib2common/src/object/Object.h              |   2 +-
 alib2std/src/extensions/memory.hpp           | 407 +------------------
 alib2std/test-src/extensions/SharedPtrTest.h |   2 +-
 4 files changed, 22 insertions(+), 391 deletions(-)

diff --git a/alib2common/src/object/AnyObjectBase.h b/alib2common/src/object/AnyObjectBase.h
index 0bc59e4d6e..46ba0cbf6e 100644
--- a/alib2common/src/object/AnyObjectBase.h
+++ b/alib2common/src/object/AnyObjectBase.h
@@ -31,7 +31,7 @@
 
 namespace object {
 
-class AnyObjectBase : public ext::cow_shared_ptr_base {
+class AnyObjectBase {
 public:
 	/**
 	 * \brief
diff --git a/alib2common/src/object/Object.h b/alib2common/src/object/Object.h
index 14b53b5de1..d1f7dcdbf0 100644
--- a/alib2common/src/object/Object.h
+++ b/alib2common/src/object/Object.h
@@ -28,7 +28,7 @@ class Object {
 	 * Unifies the shared pointers. For internal use when two pointer eval equal.
 	 */
 	void unify ( Object & other ) {
-		if ( this->m_data.getUseCount ( ) > other.m_data.getUseCount ( ) )
+		if ( this->m_data.use_count ( ) > other.m_data.use_count ( ) )
 			other.m_data = this->m_data;
 		else
 			this->m_data = other.m_data;
diff --git a/alib2std/src/extensions/memory.hpp b/alib2std/src/extensions/memory.hpp
index 0fa5458ee7..4d9e2a64c6 100644
--- a/alib2std/src/extensions/memory.hpp
+++ b/alib2std/src/extensions/memory.hpp
@@ -33,37 +33,6 @@
 
 namespace ext {
 
-/**
- * \brief
- * Predeclaration of copy on write shared ptr class.
- */
-template < typename T, typename Enable = void >
-class cow_shared_ptr;
-
-/**
- * \brief
- * Base class of classes used inside copy on write pointers.
- */
-class cow_shared_ptr_base {
-public:
-	/**
-	 * Constructor of the copy on write shared ptr base class. The use count is initialized to zero.
-	 */
-	cow_shared_ptr_base ( ) : m_UseCount ( 0 ) { }
-
-private:
-	/**
-	 * 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.
@@ -75,24 +44,20 @@ private:
  * \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 > {
+class cow_shared_ptr : std::shared_ptr < T > {
 public:
 	/**
 	 * \brief
 	 * Default initialization to null.
 	 */
-	explicit cow_shared_ptr ( ) {
-		attach ( NULL );
+	explicit cow_shared_ptr ( ) : std::shared_ptr < T > ( nullptr ) {
 	}
 
 	/**
 	 * \brief
 	 * Constructor which takes ownership of the provided pointer.
 	 */
-	explicit cow_shared_ptr ( T * data ) {
-		if ( data ) data->m_UseCount = 0;
-
-		attach ( data );
+	explicit cow_shared_ptr ( T * data ) : std::shared_ptr < T > ( data ) {
 	}
 
 	/**
@@ -101,8 +66,7 @@ public:
 	 *
 	 * \param other the source instance
 	 */
-	cow_shared_ptr ( const cow_shared_ptr & other ) {
-		attach ( other.m_Data );
+	cow_shared_ptr ( const cow_shared_ptr & other ) : std::shared_ptr < T > ( other ) {
 	}
 
 	/**
@@ -111,9 +75,7 @@ public:
 	 *
 	 * \param other the source instance
 	 */
-	cow_shared_ptr ( cow_shared_ptr && other ) noexcept {
-		m_Data = other.m_Data;
-		other.m_Data = NULL;
+	cow_shared_ptr ( cow_shared_ptr && other ) noexcept : std::shared_ptr < T > ( std::move ( other ) ) {
 	}
 
 	/**
@@ -121,7 +83,6 @@ public:
 	 * The destructor of the shared pointer.
 	 */
 	~cow_shared_ptr ( ) noexcept {
-		detach ( );
 	}
 
 	/**
@@ -131,11 +92,7 @@ public:
 	 * \param other the source instance
 	 */
 	cow_shared_ptr & operator =( const cow_shared_ptr & other ) {
-		if ( this == & other ) return * this;
-
-		detach ( );
-		attach ( other.m_Data );
-
+		static_cast < std::shared_ptr < T > & > ( * this ) = static_cast < const std::shared_ptr < T > & > ( other );
 		return * this;
 	}
 
@@ -146,7 +103,7 @@ public:
 	 * \param other the source instance
 	 */
 	cow_shared_ptr & operator =( cow_shared_ptr && other ) noexcept {
-		swap ( * this, other );
+		static_cast < std::shared_ptr < T > & > ( * this ) = static_cast < std::shared_ptr < T > && > ( other );
 		return * this;
 	}
 
@@ -157,8 +114,7 @@ public:
 	 * \return the managed pointer
 	 */
 	T * operator ->( ) {
-		make_unique ( );
-		return m_Data;
+		return this->get ( );
 	}
 
 	/**
@@ -168,7 +124,7 @@ public:
 	 * \return the managed pointer
 	 */
 	T const * operator ->( ) const {
-		return m_Data;
+		return this->get ( );
 	}
 
 	/**
@@ -178,8 +134,7 @@ public:
 	 * \return reference to managed data
 	 */
 	T & operator *( ) {
-		make_unique ( );
-		return * m_Data;
+		return * this->get ( );
 	}
 
 	/**
@@ -189,7 +144,7 @@ public:
 	 * \return reference to managed data
 	 */
 	T const & operator *( ) const {
-		return * m_Data;
+		return * this->get ( );
 	}
 
 	/**
@@ -199,7 +154,7 @@ public:
 	 */
 	T * get ( ) {
 		make_unique ( );
-		return m_Data;
+		return std::shared_ptr < T >::get ( );
 	}
 
 	/**
@@ -208,7 +163,7 @@ public:
 	 * \return the managed pointer
 	 */
 	T const * get ( ) const {
-		return m_Data;
+		return std::shared_ptr < T >::get ( );
 	}
 
 	/**
@@ -218,7 +173,7 @@ public:
 	 * \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;
+		return std::shared_ptr < T >::unique ( );
 	}
 
 	/**
@@ -227,10 +182,8 @@ public:
 	 *
 	 * \return the use count
 	 */
-	unsigned getUseCount ( ) const {
-		if ( m_Data == NULL ) return 0;
-
-		return m_Data->m_UseCount;
+	unsigned use_count ( ) const {
+		return std::shared_ptr < T >::use_count ( );
 	}
 
 	/**
@@ -239,31 +192,10 @@ public:
 	 * \return true if the managed pointer is not null and the use count is nonzero, false otherwise
 	 */
 	explicit operator bool( ) const {
-		return getUseCount ( ) != 0;
+		return use_count ( ) != 0;
 	}
 
 private:
-	/**
-	 * \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;
-
-		if ( m_Data ) m_Data->m_UseCount++;
-	}
-
-	/**
-	 * \brief
-	 * Decreases the use count of managed pointer, if needed the pointer is freed. Managed pointer stored in this instance is set to null.
-	 */
-	void detach ( ) {
-		if ( m_Data && ( --( m_Data->m_UseCount ) <= 0 ) ) delete m_Data;
-
-		m_Data = NULL;
-	}
 
 	/**
 	 * \brief
@@ -272,308 +204,9 @@ private:
 	void make_unique ( ) {
 		if ( unique ( ) ) return;
 
-		T * tmp = m_Data;
-		detach ( );
-		tmp = ext::clone ( * tmp );
-		tmp->m_UseCount = 0;
-		attach ( tmp );
-	}
-
-	/**
-	 * \brief
-	 * The managed pointer
-	 */
-	T * m_Data;
-
-	/**
-	 * \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 ) {
-		T * tmp = first.m_Data;
-
-		first.m_Data = second.m_Data;
-		second.m_Data = tmp;
-	}
-
-};
-
-/**
- * \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).
-	 */
-	struct cow_shared_ptr_data {
-		/**
-		 * \brief
-		 * The managed pointer.
-		 */
-		T * m_Data;
-
-		/**
-		 * 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;
-	};
-
-public:
-	/**
-	 * \brief
-	 * Default initialization to null.
-	 */
-	explicit cow_shared_ptr ( ) {
-		attach ( NULL );
-	}
-
-	/**
-	 * \brief
-	 * Constructor which takes ownership of the provided pointer.
-	 */
-	explicit cow_shared_ptr ( T * data ) {
-		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 ) {
-		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.
-	 */
-	~cow_shared_ptr ( ) noexcept {
-		detach ( );
-	}
-
-	/**
-	 * \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 ) {
-		if ( this == & other ) return * this;
-
-		detach ( );
-		attach ( other.m_Data );
-
-		return * this;
+		static_cast < std::shared_ptr < T > & > ( * this ) = std::shared_ptr < T > ( ext::clone ( * std::shared_ptr < T >::get ( ) ) );
 	}
 
-	/**
-	 * \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 {
-		swap ( * this, other );
-		return * this;
-	}
-
-	/**
-	 * \brief
-	 * Operator arrow to chain dereferece to inner managed pointer.
-	 *
-	 * \return the managed pointer
-	 */
-	T * operator ->( ) {
-		make_unique ( );
-		return m_Data->m_Data;
-	}
-
-	/**
-	 * \brief
-	 * Operator arrow to chain dereferece to inner managed pointer.
-	 *
-	 * \return the managed pointer
-	 */
-	T const * operator ->( ) const {
-		return m_Data->m_Data;
-	}
-
-	/**
-	 * \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 );
-	}
-
-	/**
-	 * \brief
-	 * Getter of the raw managed pointer.
-	 *
-	 * \return the managed pointer
-	 */
-	T * get ( ) {
-		make_unique ( );
-		return m_Data->m_Data;
-	}
-
-	/**
-	 * \brief
-	 * Getter of the raw managed pointer.
-	 *
-	 * \return the managed pointer
-	 */
-	T const * get ( ) const {
-		return m_Data->m_Data;
-	}
-
-	/**
-	 * \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 {
-		if ( m_Data == NULL ) return 0;
-
-		return m_Data->m_UseCount;
-	}
-
-	/**
-	 * \brief
-	 * 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 {
-		return getUseCount ( ) != 0;
-	}
-
-private:
-	/**
-	 * \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 ) {
-		m_Data = data;
-
-		if ( m_Data ) m_Data->m_UseCount++;
-	}
-
-	/**
-	 * \brief
-	 * Decreases the use count of managed pointer, if needed the pointer is freed. Managed pointer stored in this instance is set to null.
-	 */
-	void detach ( ) {
-		if ( m_Data && ( --( m_Data->m_UseCount ) <= 0 ) ) delete m_Data;
-
-		m_Data = NULL;
-	}
-
-	/**
-	 * \brief
-	 * Ensures the managed pointer is unique by copy constructing the managed instance if needed.
-	 */
-	void make_unique ( ) {
-		if ( unique ( ) ) return;
-
-		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.
-	 */
-	cow_shared_ptr_data * m_Data;
-
 	/**
 	 * \brief
 	 * Specialisation of swap method to copy on write shared pointers.
@@ -582,9 +215,7 @@ private:
 	 * \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;
-		first.m_Data = second.m_Data;
-		second.m_Data = tmp;
+		std::swap ( static_cast < std::shared_ptr < T > & > ( first ), static_cast < std::shared_ptr < T > & > ( second ) );
 	}
 
 };
diff --git a/alib2std/test-src/extensions/SharedPtrTest.h b/alib2std/test-src/extensions/SharedPtrTest.h
index 63ed1d2a3f..2ed9aa6f7f 100644
--- a/alib2std/test-src/extensions/SharedPtrTest.h
+++ b/alib2std/test-src/extensions/SharedPtrTest.h
@@ -36,7 +36,7 @@ public:
 	}
 };
 
-class Moveable2 : public ext::cow_shared_ptr_base {
+class Moveable2 {
 	int& m_moves;
 	int& m_copies;
 
-- 
GitLab