#ifndef _DEUNIQUEPTR_HPP #define _DEUNIQUEPTR_HPP /*------------------------------------------------------------------------- * drawElements C++ Base Library * ----------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Unique pointer. *//*--------------------------------------------------------------------*/ #include "deDefs.hpp" namespace de { //! Unique pointer self-test. void UniquePtr_selfTest (void); // Hide implementation-private types in a details namespace. namespace details { //! Auxiliary struct used to pass references between unique pointers. To //! ensure that managed pointers are deleted exactly once, this type should //! not appear in user code. template<typename T, class D> struct PtrData { PtrData (T* p, D d) : ptr(p), deleter(d) {} template <typename T2, class D2> PtrData (const PtrData<T2, D2>& d) : ptr(d.ptr), deleter(d.deleter) {} T* ptr; D deleter; }; template<typename T, class D> class UniqueBase { public: typedef T element_type; typedef D deleter_type; T* get (void) const throw() { return m_data.ptr; } //!< Get stored pointer. D getDeleter (void) const throw() { return m_data.deleter; } T* operator-> (void) const throw() { return get(); } //!< Get stored pointer. T& operator* (void) const throw() { return *get(); } //!< De-reference stored pointer. operator bool (void) const throw() { return !!get(); } protected: UniqueBase (T* ptr, D deleter) : m_data(ptr, deleter) {} UniqueBase (PtrData<T, D> data) : m_data(data) {} ~UniqueBase (void); void reset (void); //!< Delete previous pointer, set to null. PtrData<T, D> releaseData (void) throw(); //!< Relinquish ownership, return pointer data. void assignData (PtrData<T, D> data); //!< Set new pointer, delete previous pointer. private: PtrData<T, D> m_data; }; template <typename T, class D> UniqueBase<T, D>::~UniqueBase (void) { reset(); } template <typename T, class D> void UniqueBase<T, D>::reset (void) { if (m_data.ptr != DE_NULL) { m_data.deleter(m_data.ptr); m_data.ptr = DE_NULL; } } template <typename T, class D> PtrData<T, D> UniqueBase<T, D>::releaseData (void) throw() { PtrData<T, D> data = m_data; m_data.ptr = DE_NULL; return data; } template <typename T, class D> void UniqueBase<T, D>::assignData (PtrData<T, D> data) { if (data.ptr != m_data.ptr) { reset(); m_data = data; } } /*--------------------------------------------------------------------*//*! * \brief Movable unique pointer * * A MovePtr is smart pointer that retains sole ownership of a pointer and * destroys it when it is destroyed (for example when it goes out of scope). * * A MovePtr can be copied and assigned to. The pointer ownership is moved to * the newly constructer or assigned-to MovePtr. Upon assignment to a * MovePtr, the previously managed pointer is deleted. * *//*--------------------------------------------------------------------*/ template<typename T, class Deleter = DefaultDeleter<T> > class MovePtr : public UniqueBase<T, Deleter> { public: MovePtr (void) : UniqueBase<T, Deleter> (DE_NULL, Deleter()) {} explicit MovePtr (T* ptr, Deleter deleter = Deleter()) : UniqueBase<T, Deleter> (ptr, deleter) {} MovePtr (MovePtr<T, Deleter>& other) : UniqueBase<T, Deleter> (other.releaseData()) {} MovePtr& operator= (MovePtr<T, Deleter>& other); T* release (void) throw(); void clear (void) { this->reset(); } // These implicit by-value conversions to and from a PtrData are used to // allow copying a MovePtr by value when returning from a function. To // ensure that the managed pointer gets deleted exactly once, the PtrData // should only exist as a temporary conversion step between two MovePtrs. MovePtr (PtrData<T, Deleter> data) : UniqueBase<T, Deleter> (data) {} MovePtr& operator= (PtrData<T, Deleter> data); template<typename U, class Del2> operator PtrData<U, Del2> (void) { return this->releaseData(); } }; template<typename T, class D> MovePtr<T, D>& MovePtr<T,D>::operator= (PtrData<T, D> data) { this->assignData(data); return *this; } template<typename T, class D> MovePtr<T, D>& MovePtr<T,D>::operator= (MovePtr<T, D>& other) { return (*this = other.releaseData()); } //! Steal the managed pointer. The caller is responsible for explicitly //! deleting the returned pointer. template<typename T, class D> inline T* MovePtr<T,D>::release (void) throw() { return this->releaseData().ptr; } //! Construct a MovePtr from a pointer. template<typename T> inline MovePtr<T> movePtr (T* ptr) { return MovePtr<T>(ptr); } //! Allocate and construct an object and return its address as a MovePtr. template<typename T> inline MovePtr<T> newMovePtr (void) { return MovePtr<T>(new T()); } template<typename T, typename P0> inline MovePtr<T> newMovePtr (P0 p0) { return MovePtr<T>(new T(p0)); } template<typename T, typename P0, typename P1> inline MovePtr<T> newMovePtr (P0 p0, P1 p1) { return MovePtr<T>(new T(p0, p1)); } template<typename T, typename P0, typename P1, typename P2> inline MovePtr<T> newMovePtr (P0 p0, P1 p1, P2 p2) { return MovePtr<T>(new T(p0, p1, p2)); } /*--------------------------------------------------------------------*//*! * \brief Unique pointer * * UniquePtr is smart pointer that retains sole ownership of a pointer * and destroys it when UniquePtr is destroyed (for example when UniquePtr * goes out of scope). * * UniquePtr is not copyable or assignable. Pointer ownership can be transferred * from a UniquePtr only explicitly with the move() member function. * * A UniquePtr can be constructed from a MovePtr. In this case it assumes * ownership of the pointer from the MovePtr. Because a UniquePtr cannot be * copied, direct initialization syntax must be used, i.e.: * * MovePtr<Foo> createFoo (void); * UniquePtr<Foo> fooPtr(createFoo()); // NOT fooPtr = createFoo(); * *//*--------------------------------------------------------------------*/ template<typename T, class Deleter = DefaultDeleter<T> > class UniquePtr : public UniqueBase<T, Deleter> { public: explicit UniquePtr (T* ptr, Deleter deleter = Deleter()); UniquePtr (PtrData<T, Deleter> data); MovePtr<T, Deleter> move (void); private: UniquePtr (const UniquePtr<T>& other); // Not allowed! UniquePtr operator= (const UniquePtr<T>& other); // Not allowed! }; /*--------------------------------------------------------------------*//*! * \brief Construct unique pointer. * \param ptr Pointer to be managed. * * Pointer ownership is transferred to the UniquePtr. *//*--------------------------------------------------------------------*/ template<typename T, class Deleter> inline UniquePtr<T, Deleter>::UniquePtr (T* ptr, Deleter deleter) : UniqueBase<T, Deleter> (ptr, deleter) { } template<typename T, class Deleter> inline UniquePtr<T, Deleter>::UniquePtr (PtrData<T, Deleter> data) : UniqueBase<T, Deleter> (data) { } /*--------------------------------------------------------------------*//*! * \brief Relinquish ownership of pointer. * * This method returns a MovePtr that now owns the pointer. The pointer in * the UniquePtr is set to null. *//*--------------------------------------------------------------------*/ template<typename T, class Deleter> inline MovePtr<T, Deleter> UniquePtr<T, Deleter>::move (void) { return MovePtr<T, Deleter>(this->releaseData()); } } // details using details::UniquePtr; using details::MovePtr; using details::newMovePtr; } // de #endif // _DEUNIQUEPTR_HPP