[DEV] add refPtr and RefCounter object to manage refconted element (somtimes better than sharedPtr: smaller, faster, less segmentation)
This commit is contained in:
parent
4bc9a2f27b
commit
2a211653e0
37
ememory/RefCounter.cpp
Normal file
37
ememory/RefCounter.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2016, Edouard DUPIN, all right reserved
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ememory/RefCounter.hpp>
|
||||
#include <ememory/debug.hpp>
|
||||
|
||||
ememory::RefCounter::~RefCounter() {
|
||||
if (m_refCount != 0) {
|
||||
EMEMORY_ERROR("delete a RefCounted element that is keep by somewhere !! " << m_refCount);
|
||||
}
|
||||
}
|
||||
|
||||
void ememory::RefCounter::refKeep() {
|
||||
m_refCount++;
|
||||
}
|
||||
|
||||
void ememory::RefCounter::refRelease() {
|
||||
int refCount = --m_refCount;
|
||||
if (refCount == 0) {
|
||||
// No more element ==> remove it.
|
||||
this->~RefCounter();
|
||||
ETK_DELETE(ememory::RefCounter, this);
|
||||
// NOTE: Do nothing more than this ==> it will not work
|
||||
return;
|
||||
}
|
||||
if (refCount < 0) {
|
||||
EMEMORY_ERROR("request release a refcounted One more time than needed !! " << m_refCount);
|
||||
m_refCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ememory::RefCounter::getRefCount() const {
|
||||
return m_refCount;
|
||||
}
|
49
ememory/RefCounter.hpp
Normal file
49
ememory/RefCounter.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2016, Edouard DUPIN, all right reserved
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <etk/types.hpp>
|
||||
#include <ememory/RefPtr.hpp>
|
||||
|
||||
|
||||
namespace ememory {
|
||||
/**
|
||||
* @brief Use the element as a refcounted element
|
||||
*/
|
||||
class RefCounter {
|
||||
protected:
|
||||
// Virtualize destructor in private to prevent user ot remove it without permition
|
||||
virtual ~RefCounter();
|
||||
private:
|
||||
int32_t m_refCount = 1;
|
||||
public:
|
||||
/**
|
||||
* @brief Keep a copy of this reference-counted element.
|
||||
*/
|
||||
void refKeep();
|
||||
/**
|
||||
* @brief Relese a copy of this reference-counted element.
|
||||
*/
|
||||
void refRelease();
|
||||
/**
|
||||
* @brief Get the number of time the object is required.
|
||||
*/
|
||||
int32_t getRefCount() const;
|
||||
/**
|
||||
* @brief Get the currect class SharedPtr
|
||||
* @return Request SharedPtr
|
||||
*/
|
||||
//ememory::RefPtr<EMEMORY_TYPE> refFromThis();
|
||||
/**
|
||||
* @brief Get the currect class SharedPtr
|
||||
* @return Request const SharedPtr
|
||||
*/
|
||||
//const ememory::RefPtr<EMEMORY_TYPE> refFromThis() const;
|
||||
};
|
||||
}
|
||||
|
||||
#include <ememory/details/EnableSharedFromThis.hxx>
|
||||
|
167
ememory/RefPtr.hpp
Normal file
167
ememory/RefPtr.hpp
Normal file
@ -0,0 +1,167 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2016, Edouard DUPIN, all right reserved
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ememory/debug.hpp>
|
||||
#include <ememory/RefCounter.hpp>
|
||||
|
||||
namespace ememory {
|
||||
class RefCounter;
|
||||
/**
|
||||
* @brief ememory::Ref is a smart pointer on RefCounted element.
|
||||
* this is the good way to use a RefCounter object to not missed to remove one of them.
|
||||
*
|
||||
* @note this is smaller than SharedPtr in memory impact and code done, then it is faster.
|
||||
*/
|
||||
template<typename EMEMORY_TYPE>
|
||||
class RefPtr {
|
||||
private:
|
||||
EMEMORY_TYPE* m_element = null; //!< Pointer on the Data
|
||||
public:
|
||||
#ifndef PARSE_DOXYGEN
|
||||
template<class EMEMORY_TYPE2,
|
||||
typename etk::EnableIf< etk::IsSame<EMEMORY_TYPE2, EMEMORY_TYPE>::value
|
||||
&& etk::IsBaseOf<ememory::RefCounter, EMEMORY_TYPE2>::value
|
||||
, int>::type = 0>
|
||||
RefPtr(EMEMORY_TYPE2* _element);
|
||||
#else
|
||||
/**
|
||||
* @brief Contructor whith the pointer of data
|
||||
* @param[in] _element allocated data (RefPtr will remove it)
|
||||
*/
|
||||
RefPtr(EMEMORY_TYPE2* _element);
|
||||
#endif
|
||||
public:
|
||||
/**
|
||||
* @brief Contructor on null
|
||||
*/
|
||||
RefPtr(etk::NullPtr);
|
||||
/**
|
||||
* @brief Contructor empty
|
||||
*/
|
||||
RefPtr();
|
||||
/**
|
||||
* @brief creator (to use wher create a new object (using nuw or ...)
|
||||
* @param[in] _obj Pointer on the Data
|
||||
*/
|
||||
static inline RefPtr create(EMEMORY_TYPE* _obj);
|
||||
/**
|
||||
* @brief Contructor (API for casting)
|
||||
* @param[in] _obj Pointer on the Data
|
||||
*/
|
||||
RefPtr(EMEMORY_TYPE* _obj);
|
||||
/**
|
||||
* @brief copy Contructor
|
||||
* @param[in] _obj RefPtr to copy
|
||||
*/
|
||||
RefPtr(const RefPtr<EMEMORY_TYPE>& _obj);
|
||||
/**
|
||||
* @brief copy Contructor
|
||||
* @param[in] _obj RefPtr to copy
|
||||
*/
|
||||
RefPtr(RefPtr<EMEMORY_TYPE>&& _obj);
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~RefPtr();
|
||||
/**
|
||||
* @brief Asignement operator
|
||||
* @param[in] _obj RefPtr to copy
|
||||
* @return Reference on this
|
||||
*/
|
||||
RefPtr& operator= (const RefPtr<EMEMORY_TYPE>& _obj);
|
||||
/**
|
||||
* @brief Asignement operator (asign null)
|
||||
* @return Reference on this
|
||||
*/
|
||||
RefPtr& operator= (etk::NullPtr);
|
||||
public:
|
||||
#ifndef PARSE_DOXYGEN
|
||||
template<class EMEMORY_TYPE2,
|
||||
typename etk::EnableIf< etk::IsBaseOf<EMEMORY_TYPE, EMEMORY_TYPE2>::value
|
||||
, int>::type = 0>
|
||||
RefPtr(const RefPtr<EMEMORY_TYPE2>& _obj);
|
||||
template<class EMEMORY_TYPE2,
|
||||
typename etk::EnableIf< etk::IsBaseOf<EMEMORY_TYPE, EMEMORY_TYPE2>::value
|
||||
, int>::type = 0>
|
||||
RefPtr& operator= (const RefPtr<EMEMORY_TYPE2>& _obj);
|
||||
#endif
|
||||
public:
|
||||
/**
|
||||
* @brief Reset the RefPtr ==> Remove data if needed
|
||||
*/
|
||||
void reset();
|
||||
/**
|
||||
* @brief Get the number of conencted RefPtr
|
||||
* @return Number of RefPtr on this data
|
||||
*/
|
||||
int useCount() const;
|
||||
/**
|
||||
* @brief Check if the RefPtr have an internal data (not null)
|
||||
* @return true The pointer is not asigned, false otherwise
|
||||
*/
|
||||
bool operator==(etk::NullPtr) const;
|
||||
/**
|
||||
* @brief Check if two RefPtr are the same data (maybe not the same cast)
|
||||
* @param[in] _obj Object to compare
|
||||
* @return true The Object have the same pointer reference, false otherwise
|
||||
*/
|
||||
template<class EMEMORY_TYPE2>
|
||||
bool operator==(const RefPtr<EMEMORY_TYPE2>& _obj) const;
|
||||
/**
|
||||
* @brief Check if the RefPtr have NOT an internal data (null)
|
||||
* @return true The pointer is asigned, false otherwise
|
||||
*/
|
||||
bool operator!=(etk::NullPtr) const;
|
||||
/**
|
||||
* @brief Check if two RefPtr are NOT the same data (maybe not the same cast)
|
||||
* @param[in] _obj Object to compare
|
||||
* @return true The Object have NOT the same pointer reference, false otherwise
|
||||
*/
|
||||
template<class EMEMORY_TYPE2>
|
||||
bool operator!=(const RefPtr<EMEMORY_TYPE2>& _obj) const;
|
||||
/**
|
||||
* @brief Get a const pointer on the data
|
||||
* @return Data const pointer
|
||||
*/
|
||||
const EMEMORY_TYPE* get() const;
|
||||
/**
|
||||
* @brief Get a pointer on the data
|
||||
* @return Data pointer
|
||||
*/
|
||||
EMEMORY_TYPE* get();
|
||||
/**
|
||||
* @brief Const dereferences the stored pointer.
|
||||
* @return Const pointer on the Data
|
||||
*/
|
||||
const EMEMORY_TYPE* operator->() const;
|
||||
/**
|
||||
* @brief Dereferences the stored pointer.
|
||||
* @return Pointer on the Data
|
||||
*/
|
||||
EMEMORY_TYPE* operator->();
|
||||
/**
|
||||
* @brief Get a const reference on the data
|
||||
* @return Data const reference
|
||||
*/
|
||||
const EMEMORY_TYPE& operator*() const;
|
||||
/**
|
||||
* @brief Get a reference on the data
|
||||
* @return Data reference
|
||||
*/
|
||||
EMEMORY_TYPE& operator*();
|
||||
/**
|
||||
* @brief Swap 2 Object inside the RefPtr
|
||||
* @param[in] _obj Object to swap with
|
||||
*/
|
||||
void swap(RefPtr<EMEMORY_TYPE>& _obj);
|
||||
// TODO: unique
|
||||
// TODO: bool
|
||||
};
|
||||
}
|
||||
|
||||
#include <ememory/details/RefPtr.hxx>
|
||||
|
@ -1,4 +1,8 @@
|
||||
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2016, Edouard DUPIN, all right reserved
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <etk/types.hpp>
|
||||
|
200
ememory/details/RefPtr.hxx
Normal file
200
ememory/details/RefPtr.hxx
Normal file
@ -0,0 +1,200 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2016, Edouard DUPIN, all right reserved
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ememory/debug.hpp>
|
||||
#include <ememory/RefPtr.hpp>
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
template<class EMEMORY_TYPE2,
|
||||
typename etk::EnableIf< etk::IsSame<EMEMORY_TYPE2, EMEMORY_TYPE>::value
|
||||
&& etk::IsBaseOf<ememory::RefCounter, EMEMORY_TYPE2>::value
|
||||
, int>::type>
|
||||
ememory::RefPtr<EMEMORY_TYPE>::RefPtr(EMEMORY_TYPE2* _element):
|
||||
m_element(_element) {
|
||||
EMEMORY_DBG("Create shared");
|
||||
if (m_element == null) {
|
||||
return;
|
||||
}
|
||||
EMEMORY_DBG("Check if the user use the memory allocator or personal system...");
|
||||
ETK_MEM_CHECK_POINTER(_element);
|
||||
EMEMORY_DBG(" ==> get previous pointer");
|
||||
m_element->refKeep();
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
ememory::RefPtr<EMEMORY_TYPE> ememory::RefPtr<EMEMORY_TYPE>::create(EMEMORY_TYPE* _obj) {
|
||||
EMEMORY_DBG("Create shared");
|
||||
ememory::RefPtr<EMEMORY_TYPE> tmp{_obj};
|
||||
_obj->refRelease();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
ememory::RefPtr<EMEMORY_TYPE>::RefPtr():
|
||||
m_element(null) {
|
||||
EMEMORY_DBG("Create shared");
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
ememory::RefPtr<EMEMORY_TYPE>::RefPtr(etk::NullPtr):
|
||||
m_element(null) {
|
||||
EMEMORY_DBG("Create shared");
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
ememory::RefPtr<EMEMORY_TYPE>::RefPtr(EMEMORY_TYPE* _obj):
|
||||
m_element(_obj) {
|
||||
EMEMORY_DBG("Create shared (from a cast)");
|
||||
if (m_element == null) {
|
||||
return;
|
||||
}
|
||||
m_element->refKeep();
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
ememory::RefPtr<EMEMORY_TYPE>::~RefPtr() {
|
||||
EMEMORY_DBG("delete shared");
|
||||
reset();
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
ememory::RefPtr<EMEMORY_TYPE>::RefPtr(const ememory::RefPtr<EMEMORY_TYPE>& _obj):
|
||||
m_element(_obj.m_element) {
|
||||
if (m_element == null) {
|
||||
return;
|
||||
}
|
||||
m_element->refKeep();
|
||||
};
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
ememory::RefPtr<EMEMORY_TYPE>& ememory::RefPtr<EMEMORY_TYPE>::operator= (const ememory::RefPtr<EMEMORY_TYPE>& _obj) {
|
||||
reset();
|
||||
m_element = _obj.m_element;
|
||||
if (m_element == null) {
|
||||
return *this;
|
||||
}
|
||||
m_element->refKeep();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
ememory::RefPtr<EMEMORY_TYPE>& ememory::RefPtr<EMEMORY_TYPE>::operator= (etk::NullPtr) {
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
ememory::RefPtr<EMEMORY_TYPE>::RefPtr(ememory::RefPtr<EMEMORY_TYPE>&& _obj) {
|
||||
m_element = _obj.m_element;
|
||||
_obj.m_element = null;
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
template<class EMEMORY_TYPE2,
|
||||
typename etk::EnableIf< etk::IsBaseOf<EMEMORY_TYPE, EMEMORY_TYPE2>::value
|
||||
, int>::type>
|
||||
ememory::RefPtr<EMEMORY_TYPE>::RefPtr(const ememory::RefPtr<EMEMORY_TYPE2>& _obj):
|
||||
m_element(const_cast<EMEMORY_TYPE2*>(_obj.get())) {
|
||||
if (m_element == null) {
|
||||
return;
|
||||
}
|
||||
m_element->refKeep();
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
template<class EMEMORY_TYPE2,
|
||||
typename etk::EnableIf< etk::IsBaseOf<EMEMORY_TYPE, EMEMORY_TYPE2>::value
|
||||
, int>::type>
|
||||
ememory::RefPtr<EMEMORY_TYPE>& ememory::RefPtr<EMEMORY_TYPE>::operator= (const RefPtr<EMEMORY_TYPE2>& _obj) {
|
||||
reset();
|
||||
m_element = const_cast<EMEMORY_TYPE2*>(_obj.get());
|
||||
if (m_element == null) {
|
||||
return *this;
|
||||
}
|
||||
m_element->refKeep();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
void ememory::RefPtr<EMEMORY_TYPE>::reset() {
|
||||
if(m_element == null) {
|
||||
return;
|
||||
}
|
||||
EMEMORY_DBG("reset RefPtr (start)");
|
||||
m_element->refRelease();
|
||||
m_element = null;
|
||||
EMEMORY_DBG("reset RefPtr (stop)");
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
int ememory::RefPtr<EMEMORY_TYPE>::useCount() const {
|
||||
if (m_element == null) {
|
||||
return 0;
|
||||
}
|
||||
return m_element->getRefCount();
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
bool ememory::RefPtr<EMEMORY_TYPE>::operator==(etk::NullPtr) const {
|
||||
return m_element == null;
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
template<class EMEMORY_TYPE2>
|
||||
bool ememory::RefPtr<EMEMORY_TYPE>::operator==(const RefPtr<EMEMORY_TYPE2>& _obj) const {
|
||||
return m_element == _obj.get();
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
bool ememory::RefPtr<EMEMORY_TYPE>::operator!=(etk::NullPtr) const {
|
||||
return m_element != null;
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
template<typename EMEMORY_TYPE2>
|
||||
bool ememory::RefPtr<EMEMORY_TYPE>::operator!=(const RefPtr<EMEMORY_TYPE2>& _obj) const {
|
||||
return m_element != _obj.get();
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
const EMEMORY_TYPE* ememory::RefPtr<EMEMORY_TYPE>::get() const {
|
||||
return m_element;
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
EMEMORY_TYPE* ememory::RefPtr<EMEMORY_TYPE>::get() {
|
||||
return m_element;
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
const EMEMORY_TYPE* ememory::RefPtr<EMEMORY_TYPE>::operator->() const {
|
||||
return m_element;
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
EMEMORY_TYPE* ememory::RefPtr<EMEMORY_TYPE>::operator->() {
|
||||
return m_element;
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
const EMEMORY_TYPE& ememory::RefPtr<EMEMORY_TYPE>::operator*() const {
|
||||
return *m_element;
|
||||
}
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
EMEMORY_TYPE& ememory::RefPtr<EMEMORY_TYPE>::operator*() {
|
||||
return *m_element;
|
||||
}
|
||||
|
||||
|
||||
template<typename EMEMORY_TYPE>
|
||||
void ememory::RefPtr<EMEMORY_TYPE>::swap(RefPtr& _obj) {
|
||||
etk::swap(_obj.m_element, m_element);
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <etk/Vector.hpp>
|
||||
#include <ethread/Mutex.hpp>
|
||||
#include <ememory/SharedPtr.hpp>
|
||||
#include <ememory/RefPtr.hpp>
|
||||
#include <ememory/WeakPtr.hpp>
|
||||
#include <ememory/EnableSharedFromThis.hpp>
|
||||
#include <etk/Allocator.hpp>
|
||||
@ -88,4 +89,81 @@ namespace ememory {
|
||||
inline ememory::SharedPtr<EMEMORY_TYPE_CAST> constPointerCast(const ememory::SharedPtr<EMEMORY_TYPE>& _obj) {
|
||||
return ememory::SharedPtr<EMEMORY_TYPE_CAST>(const_cast<EMEMORY_TYPE*>(_obj.get()), _obj.getCounter());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a RefPtr with specific arguments
|
||||
* @param[in] _args Multiples argument to add in the EMEMORY_TYPE public constructor.
|
||||
* @return the requested created RefPtr
|
||||
*/
|
||||
template<class EMEMORY_TYPE,
|
||||
typename etk::EnableIf< etk::IsBaseOf<ememory::RefCounter, EMEMORY_TYPE>::value
|
||||
, int>::type = 0,
|
||||
typename... EMEMORY_ARGS>
|
||||
static ememory::RefPtr<EMEMORY_TYPE> makeRef(EMEMORY_ARGS && ..._args) {
|
||||
return ememory::RefPtr<EMEMORY_TYPE>::create(ETK_NEW(EMEMORY_TYPE, etk::forward<EMEMORY_ARGS>(_args)...));
|
||||
}
|
||||
/**
|
||||
* @brief Cast in Dynamic the input RefPtr into an other type like dynamic_cast on pointer
|
||||
* @param[in] _obj Object To cast
|
||||
* @return Casted Object
|
||||
*/
|
||||
template<class EMEMORY_TYPE_CAST, class EMEMORY_TYPE>
|
||||
inline ememory::RefPtr<EMEMORY_TYPE_CAST> dynamicRefCast(ememory::RefPtr<EMEMORY_TYPE>& _obj) {
|
||||
return ememory::RefPtr<EMEMORY_TYPE_CAST>(dynamic_cast<EMEMORY_TYPE_CAST*>(_obj.get()));
|
||||
}
|
||||
/**
|
||||
* @brief CONST Cast in Dynamic the input RefPtr into an other type like dynamic_cast on pointer
|
||||
* @param[in] _obj Object To cast
|
||||
* @return Casted Object
|
||||
*/
|
||||
template<class EMEMORY_TYPE_CAST, class EMEMORY_TYPE>
|
||||
inline const ememory::RefPtr<EMEMORY_TYPE_CAST> dynamicRefCast(const ememory::RefPtr<EMEMORY_TYPE>& _obj) {
|
||||
return ememory::RefPtr<EMEMORY_TYPE_CAST>(dynamic_cast<EMEMORY_TYPE_CAST*>(const_cast<EMEMORY_TYPE*>(_obj.get())));
|
||||
}
|
||||
/**
|
||||
* @brief Cast in static the input RefPtr into an other type like static_cast on pointer
|
||||
* @param[in] _obj Object To cast
|
||||
* @return Casted Object
|
||||
*/
|
||||
template<class EMEMORY_TYPE_CAST, class EMEMORY_TYPE>
|
||||
inline ememory::RefPtr<EMEMORY_TYPE_CAST> staticRefCast(ememory::RefPtr<EMEMORY_TYPE>& _obj) {
|
||||
return ememory::RefPtr<EMEMORY_TYPE_CAST>(static_cast<EMEMORY_TYPE_CAST*>(_obj.get()));
|
||||
}
|
||||
/**
|
||||
* @brief CONST Cast in static the input RefPtr into an other type like static_cast on pointer
|
||||
* @param[in] _obj Object To cast
|
||||
* @return Casted Object
|
||||
*/
|
||||
template<class EMEMORY_TYPE_CAST, class EMEMORY_TYPE>
|
||||
inline const ememory::RefPtr<EMEMORY_TYPE_CAST> staticRefCast(const ememory::RefPtr<EMEMORY_TYPE>& _obj) {
|
||||
return ememory::RefPtr<EMEMORY_TYPE_CAST>(static_cast<EMEMORY_TYPE_CAST*>(const_cast<EMEMORY_TYPE*>(_obj.get())));
|
||||
}
|
||||
/**
|
||||
* @brief Cast in reinterpret the input RefPtr into an other type like reinterpret_cast on pointer
|
||||
* @param[in] _obj Object To cast
|
||||
* @return Casted Object
|
||||
*/
|
||||
template<class EMEMORY_TYPE_CAST, class EMEMORY_TYPE>
|
||||
inline ememory::RefPtr<EMEMORY_TYPE_CAST> reinterpretRefCast(ememory::RefPtr<EMEMORY_TYPE>& _obj) {
|
||||
return ememory::RefPtr<EMEMORY_TYPE_CAST>(reinterpret_cast<EMEMORY_TYPE_CAST*>(_obj.get()));
|
||||
}
|
||||
/**
|
||||
* @brief CONST Cast in reinterpret the input RefPtr into an other type like reinterpret_cast on pointer
|
||||
* @param[in] _obj Object To cast
|
||||
* @return Casted Object
|
||||
*/
|
||||
template<class EMEMORY_TYPE_CAST, class EMEMORY_TYPE>
|
||||
inline const ememory::RefPtr<EMEMORY_TYPE_CAST> reinterpretRefCast(const ememory::RefPtr<EMEMORY_TYPE>& _obj) {
|
||||
return ememory::RefPtr<EMEMORY_TYPE_CAST>(reinterpret_cast<EMEMORY_TYPE_CAST*>(const_cast<EMEMORY_TYPE*>(_obj.get())));
|
||||
}
|
||||
/**
|
||||
* @brief Cast in const the input RefPtr into an other type like const_cast on pointer (remove constness)
|
||||
* @param[in] _obj Object To cast
|
||||
* @return Casted Object
|
||||
*/
|
||||
template<class EMEMORY_TYPE_CAST, class EMEMORY_TYPE>
|
||||
inline ememory::RefPtr<EMEMORY_TYPE_CAST> constRefCast(const ememory::RefPtr<EMEMORY_TYPE>& _obj) {
|
||||
return ememory::RefPtr<EMEMORY_TYPE_CAST>(const_cast<EMEMORY_TYPE*>(_obj.get()));
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ def configure(target, my_module):
|
||||
my_module.add_src_file([
|
||||
'test/main.cpp',
|
||||
'test/testUnique.cpp',
|
||||
'test/testRef.cpp',
|
||||
'test/testShared.cpp',
|
||||
'test/testWeak.cpp',
|
||||
'test/testEnableSharedFromThis.cpp',
|
||||
|
@ -29,21 +29,25 @@ def configure(target, my_module):
|
||||
# add the file to compile:
|
||||
my_module.add_src_file([
|
||||
'ememory/debug.cpp',
|
||||
'ememory/Counter.cpp'
|
||||
'ememory/Counter.cpp',
|
||||
'ememory/RefCounter.cpp',
|
||||
])
|
||||
|
||||
my_module.add_header_file([
|
||||
'ememory/debug.hpp',
|
||||
'ememory/memory.hpp',
|
||||
'ememory/Counter.hpp',
|
||||
'ememory/RefCounter.hpp',
|
||||
'ememory/RefPtr.hpp',
|
||||
'ememory/SharedPtr.hpp',
|
||||
'ememory/UniquePtr.hpp',
|
||||
'ememory/WeakPtr.hpp',
|
||||
'ememory/EnableSharedFromThis.hpp',
|
||||
'ememory/details/memory.hxx',
|
||||
'ememory/details/SharedPtr.hxx',
|
||||
'ememory/details/RefPtr.hxx',
|
||||
'ememory/details/WeakPtr.hxx',
|
||||
'ememory/details/EnableSharedFromThis.hxx'
|
||||
'ememory/details/EnableSharedFromThis.hxx',
|
||||
])
|
||||
|
||||
# build in C++ mode
|
||||
|
208
test/testRef.cpp
Normal file
208
test/testRef.cpp
Normal file
@ -0,0 +1,208 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2016, Edouard DUPIN, all right reserved
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <etest/etest.hpp>
|
||||
#include <ememory/memory.hpp>
|
||||
#include <test-debug/debug.hpp>
|
||||
|
||||
#include "main.hpp"
|
||||
|
||||
namespace {
|
||||
class MyTestString:
|
||||
public ememory::RefCounter,
|
||||
public etk::String {
|
||||
public:
|
||||
MyTestString() = default;
|
||||
MyTestString(const etk::String& _value):
|
||||
etk::String(_value) {
|
||||
|
||||
}
|
||||
MyTestString& operator = (const etk::String& _value) {
|
||||
etk::String::operator=(_value);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST(TestRef, createAndDestroy) {
|
||||
ememory::RefPtr<MyTestString> data = ememory::makeRef<MyTestString>("coucou");
|
||||
EXPECT_EQ(data.useCount(), 1);
|
||||
EXPECT_EQ(*data, "coucou");
|
||||
EXPECT_EQ(data == null, false);
|
||||
EXPECT_EQ(data != null, true);
|
||||
data.reset();
|
||||
EXPECT_EQ(data.useCount(), 0);
|
||||
EXPECT_EQ(data == null, true);
|
||||
EXPECT_EQ(data != null, false);
|
||||
}
|
||||
|
||||
TEST(TestRef, createAndDestroy_2) {
|
||||
ememory::RefPtr<MyTestString> data = ememory::RefPtr<MyTestString>::create(ETK_NEW(MyTestString, "coucou"));
|
||||
EXPECT_EQ(data.useCount(), 1);
|
||||
EXPECT_EQ(*data, "coucou");
|
||||
EXPECT_EQ(data == null, false);
|
||||
EXPECT_EQ(data != null, true);
|
||||
data.reset();
|
||||
EXPECT_EQ(data.useCount(), 0);
|
||||
EXPECT_EQ(data == null, true);
|
||||
EXPECT_EQ(data != null, false);
|
||||
}
|
||||
|
||||
TEST(TestRef, createAndDestroy_3) {
|
||||
ememory::RefPtr<MyTestString> data = ememory::RefPtr<MyTestString>::create(new MyTestString("coucou"));
|
||||
EXPECT_EQ(data.useCount(), 1);
|
||||
EXPECT_EQ(*data, "coucou");
|
||||
EXPECT_EQ(data == null, false);
|
||||
EXPECT_EQ(data != null, true);
|
||||
data.reset();
|
||||
EXPECT_EQ(data.useCount(), 0);
|
||||
EXPECT_EQ(data == null, true);
|
||||
EXPECT_EQ(data != null, false);
|
||||
}
|
||||
|
||||
TEST(TestRef, copy) {
|
||||
ememory::RefPtr<MyTestString> data = ememory::makeRef<MyTestString>("coucou");
|
||||
EXPECT_EQ(data.useCount(), 1);
|
||||
EXPECT_EQ(*data, "coucou");
|
||||
ememory::RefPtr<MyTestString> dataCopy = data;
|
||||
EXPECT_EQ(data.useCount(), 2);
|
||||
EXPECT_EQ(data == dataCopy, true);
|
||||
EXPECT_EQ(data != dataCopy, false);
|
||||
data.reset();
|
||||
EXPECT_EQ(data == dataCopy, false);
|
||||
EXPECT_EQ(data != dataCopy, true);
|
||||
EXPECT_EQ(data.useCount(), 0);
|
||||
EXPECT_EQ(dataCopy.useCount(), 1);
|
||||
EXPECT_EQ(*dataCopy, "coucou");
|
||||
dataCopy.reset();
|
||||
EXPECT_EQ(dataCopy.useCount(), 0);
|
||||
dataCopy.reset();
|
||||
EXPECT_EQ(dataCopy.useCount(), 0);
|
||||
}
|
||||
|
||||
TEST(TestRef, swap) {
|
||||
ememory::RefPtr<MyTestString> data = ememory::makeRef<MyTestString>("coucou");
|
||||
EXPECT_EQ(data.useCount(), 1);
|
||||
EXPECT_EQ(*data, "coucou");
|
||||
ememory::RefPtr<MyTestString> dataCopy;
|
||||
EXPECT_EQ(dataCopy.useCount(), 0);
|
||||
dataCopy.swap(data);
|
||||
EXPECT_EQ(data.useCount(), 0);
|
||||
EXPECT_EQ(dataCopy.useCount(), 1);
|
||||
EXPECT_EQ(*dataCopy, "coucou");
|
||||
}
|
||||
|
||||
TEST(TestRef, callOperator) {
|
||||
ememory::RefPtr<MyTestString> data = ememory::makeRef<MyTestString>("coucou");
|
||||
EXPECT_EQ(data->size(), 6);
|
||||
}
|
||||
|
||||
static void functionCallRef(etk::String& _data) {
|
||||
_data = "plop";
|
||||
}
|
||||
|
||||
TEST(TestRef, callOperatorStar) {
|
||||
ememory::RefPtr<MyTestString> data = ememory::makeRef<MyTestString>("coucou");
|
||||
EXPECT_EQ(data->size(), 6);
|
||||
EXPECT_EQ(*data, "coucou");
|
||||
*data = "ragout";
|
||||
EXPECT_EQ(data->size(), 6);
|
||||
EXPECT_EQ(*data, "ragout");
|
||||
functionCallRef(*data);
|
||||
EXPECT_EQ(data->size(), 4);
|
||||
EXPECT_EQ(*data, "plop");
|
||||
}
|
||||
|
||||
namespace {
|
||||
class basicClass : public ememory::RefCounter {
|
||||
|
||||
};
|
||||
|
||||
class heritedClass : public basicClass {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
TEST(TestRef, heritage) {
|
||||
ememory::RefPtr<heritedClass> data = ememory::makeRef<heritedClass>();
|
||||
ememory::RefPtr<basicClass> data2 = data;
|
||||
ememory::RefPtr<basicClass> data3(data);
|
||||
EXPECT_NE(data, null);
|
||||
EXPECT_NE(data2, null);
|
||||
EXPECT_NE(data3, null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static uint32_t isDestroy = 0;
|
||||
namespace {
|
||||
class testContructDestruct : public ememory::RefCounter {
|
||||
private:
|
||||
uint32_t m_addValue;
|
||||
public:
|
||||
testContructDestruct(uint32_t _addValue):
|
||||
m_addValue(_addValue) {
|
||||
isDestroy += m_addValue;
|
||||
TEST_DEBUG("Create class " << m_addValue);
|
||||
}
|
||||
testContructDestruct(testContructDestruct&& _obj):
|
||||
m_addValue(_obj.m_addValue) {
|
||||
_obj.m_addValue = 0;
|
||||
TEST_DEBUG("move contruction " << m_addValue);
|
||||
}
|
||||
virtual ~testContructDestruct() {
|
||||
if (m_addValue == 0) {
|
||||
TEST_DEBUG("Remove class (after move)");
|
||||
return;
|
||||
}
|
||||
TEST_DEBUG("Remove Class " << m_addValue);
|
||||
isDestroy -= m_addValue;
|
||||
}
|
||||
testContructDestruct& operator= (testContructDestruct&& _obj) {
|
||||
TEST_DEBUG("move operator " << m_addValue);
|
||||
if (this != &_obj) {
|
||||
etk::swap(m_addValue, _obj.m_addValue);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST(TestRef, destroyElementAtTheCorectMoment) {
|
||||
isDestroy = 0;
|
||||
{
|
||||
etk::Vector<ememory::RefPtr<testContructDestruct>> list;
|
||||
list.pushBack(ememory::makeRef<testContructDestruct>(55));
|
||||
EXPECT_EQ(list.size(), 1);
|
||||
EXPECT_EQ(isDestroy, 55);
|
||||
auto it = list.erase(list.begin());
|
||||
EXPECT_EQ(isDestroy, 0);
|
||||
EXPECT_EQ(list.size(), 0);
|
||||
EXPECT_EQ(it, list.end());
|
||||
}
|
||||
EXPECT_EQ(isDestroy, 0);
|
||||
}
|
||||
|
||||
TEST(TestRef, destroyElementAtTheCorectMoment_2) {
|
||||
isDestroy = 0;
|
||||
{
|
||||
etk::Vector<ememory::RefPtr<testContructDestruct>> list;
|
||||
list.pushBack(ememory::makeRef<testContructDestruct>(4));
|
||||
list.pushBack(ememory::makeRef<testContructDestruct>(30));
|
||||
list.pushBack(ememory::makeRef<testContructDestruct>(1000));
|
||||
list.pushBack(ememory::makeRef<testContructDestruct>(200));
|
||||
EXPECT_EQ(list.size(), 4);
|
||||
EXPECT_EQ(isDestroy, 1234);
|
||||
auto it = list.erase(list.begin());
|
||||
EXPECT_EQ(list.size(), 3);
|
||||
EXPECT_EQ(isDestroy, 1230);
|
||||
it = list.erase(list.begin()+1);
|
||||
EXPECT_EQ(isDestroy, 230);
|
||||
EXPECT_EQ(list.size(), 2);
|
||||
}
|
||||
EXPECT_EQ(isDestroy, 0);
|
||||
}
|
@ -128,68 +128,69 @@ TEST(TestShared, heritage) {
|
||||
|
||||
|
||||
static uint32_t isDestroy = 0;
|
||||
|
||||
class testContructDestruct {
|
||||
private:
|
||||
uint32_t m_addValue;
|
||||
public:
|
||||
testContructDestruct(uint32_t _addValue):
|
||||
m_addValue(_addValue) {
|
||||
isDestroy += m_addValue;
|
||||
TEST_DEBUG("Create class " << m_addValue);
|
||||
}
|
||||
testContructDestruct(testContructDestruct&& _obj):
|
||||
m_addValue(_obj.m_addValue) {
|
||||
_obj.m_addValue = 0;
|
||||
TEST_DEBUG("move contruction " << m_addValue);
|
||||
}
|
||||
virtual ~testContructDestruct() {
|
||||
if (m_addValue == 0) {
|
||||
TEST_DEBUG("Remove class (after move)");
|
||||
return;
|
||||
namespace {
|
||||
class testContructDestruct {
|
||||
private:
|
||||
uint32_t m_addValue;
|
||||
public:
|
||||
testContructDestruct(uint32_t _addValue):
|
||||
m_addValue(_addValue) {
|
||||
isDestroy += m_addValue;
|
||||
TEST_DEBUG("Create class " << m_addValue);
|
||||
}
|
||||
TEST_DEBUG("Remove Class " << m_addValue);
|
||||
isDestroy -= m_addValue;
|
||||
}
|
||||
testContructDestruct& operator= (testContructDestruct&& _obj) {
|
||||
TEST_DEBUG("move operator " << m_addValue);
|
||||
if (this != &_obj) {
|
||||
etk::swap(m_addValue, _obj.m_addValue);
|
||||
testContructDestruct(testContructDestruct&& _obj):
|
||||
m_addValue(_obj.m_addValue) {
|
||||
_obj.m_addValue = 0;
|
||||
TEST_DEBUG("move contruction " << m_addValue);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class testContructDestruct2 : public ememory::EnableSharedFromThis<testContructDestruct2> {
|
||||
private:
|
||||
uint32_t m_addValue;
|
||||
public:
|
||||
testContructDestruct2(uint32_t _addValue):
|
||||
m_addValue(_addValue) {
|
||||
isDestroy += m_addValue;
|
||||
TEST_DEBUG("Create class " << m_addValue);
|
||||
}
|
||||
testContructDestruct2(testContructDestruct2&& _obj):
|
||||
m_addValue(_obj.m_addValue) {
|
||||
_obj.m_addValue = 0;
|
||||
TEST_DEBUG("move contruction " << m_addValue);
|
||||
}
|
||||
virtual ~testContructDestruct2() {
|
||||
if (m_addValue == 0) {
|
||||
TEST_DEBUG("Remove class (after move)");
|
||||
return;
|
||||
virtual ~testContructDestruct() {
|
||||
if (m_addValue == 0) {
|
||||
TEST_DEBUG("Remove class (after move)");
|
||||
return;
|
||||
}
|
||||
TEST_DEBUG("Remove Class " << m_addValue);
|
||||
isDestroy -= m_addValue;
|
||||
}
|
||||
TEST_DEBUG("Remove Class " << m_addValue);
|
||||
isDestroy -= m_addValue;
|
||||
}
|
||||
testContructDestruct2& operator= (testContructDestruct2&& _obj) {
|
||||
TEST_DEBUG("move operator " << m_addValue);
|
||||
if (this != &_obj) {
|
||||
etk::swap(m_addValue, _obj.m_addValue);
|
||||
testContructDestruct& operator= (testContructDestruct&& _obj) {
|
||||
TEST_DEBUG("move operator " << m_addValue);
|
||||
if (this != &_obj) {
|
||||
etk::swap(m_addValue, _obj.m_addValue);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class testContructDestruct2 : public ememory::EnableSharedFromThis<testContructDestruct2> {
|
||||
private:
|
||||
uint32_t m_addValue;
|
||||
public:
|
||||
testContructDestruct2(uint32_t _addValue):
|
||||
m_addValue(_addValue) {
|
||||
isDestroy += m_addValue;
|
||||
TEST_DEBUG("Create class " << m_addValue);
|
||||
}
|
||||
testContructDestruct2(testContructDestruct2&& _obj):
|
||||
m_addValue(_obj.m_addValue) {
|
||||
_obj.m_addValue = 0;
|
||||
TEST_DEBUG("move contruction " << m_addValue);
|
||||
}
|
||||
virtual ~testContructDestruct2() {
|
||||
if (m_addValue == 0) {
|
||||
TEST_DEBUG("Remove class (after move)");
|
||||
return;
|
||||
}
|
||||
TEST_DEBUG("Remove Class " << m_addValue);
|
||||
isDestroy -= m_addValue;
|
||||
}
|
||||
testContructDestruct2& operator= (testContructDestruct2&& _obj) {
|
||||
TEST_DEBUG("move operator " << m_addValue);
|
||||
if (this != &_obj) {
|
||||
etk::swap(m_addValue, _obj.m_addValue);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST(TestShared, destroyElementAtTheCorectMoment) {
|
||||
isDestroy = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user