diff --git a/modules/core/include/opencv2/core/cvstd.hpp b/modules/core/include/opencv2/core/cvstd.hpp index 5014dba0f783e8070681cff07bc1fc19abe7dfec..afdeb2549a4deaae0cc37d092aee24a379cbb82b 100644 --- a/modules/core/include/opencv2/core/cvstd.hpp +++ b/modules/core/include/opencv2/core/cvstd.hpp @@ -158,69 +158,176 @@ public: size_type max_size() const { return cv::max(static_cast<_Tp>(-1)/sizeof(_Tp), 1); } }; +namespace detail +{ +// Metafunction to avoid taking a reference to void. +template +struct RefOrVoid { typedef T& type; }; -//////////////////// generic_type ref-counting pointer class for C/C++ objects //////////////////////// +template<> +struct RefOrVoid{ typedef void type; }; -/*! - Smart pointer to dynamically allocated objects. +template<> +struct RefOrVoid{ typedef const void type; }; - This is template pointer-wrapping class that stores the associated reference counter along with the - object pointer. The class is similar to std::smart_ptr<> from the recent addons to the C++ standard, - but is shorter to write :) and self-contained (i.e. does add any dependency on the compiler or an external library). +template<> +struct RefOrVoid{ typedef volatile void type; }; - Basically, you can use "Ptr ptr" (or faster "const Ptr& ptr" for read-only access) - everywhere instead of "MyObjectType* ptr", where MyObjectType is some C structure or a C++ class. - To make it all work, you need to specialize Ptr<>::delete_obj(), like: +template<> +struct RefOrVoid{ typedef const volatile void type; }; - \code - template<> CV_EXPORTS void Ptr::delete_obj() { call_destructor_func(obj); } - \endcode +// This class would be private to Ptr, if it didn't have to be a non-template. +struct PtrOwner; + +} + +template +struct DefaultDeleter +{ + void operator () (Y* p) const; +}; - \note{if MyObjectType is a C++ class with a destructor, you do not need to specialize delete_obj(), - since the default implementation calls "delete obj;"} +/* + A smart shared pointer class with reference counting. - \note{Another good property of the class is that the operations on the reference counter are atomic, - i.e. it is safe to use the class in multi-threaded applications} + A Ptr stores a pointer and owns a (potentially different) pointer. + The stored pointer has type T and is the one returned by get() et al, + while the owned pointer can have any type and is the one deleted + when there are no more Ptrs that own it. You can't directly obtain the + owned pointer. + + The interface of this class is mostly a subset of that of C++11's + std::shared_ptr. */ -template class Ptr +template +struct Ptr { -public: - //! empty constructor + /* Generic programming support. */ + typedef T element_type; + + /* Ptr that owns NULL and stores NULL. */ Ptr(); - //! take ownership of the pointer. The associated reference counter is allocated and set to 1 - Ptr(_Tp* _obj); - //! calls release() + + /* Ptr that owns p and stores p. The owned pointer will be deleted with + DefaultDeleter. Y must be a complete type and Y* must be + convertible to T*. */ + template + explicit Ptr(Y* p); + + /* Ptr that owns p and stores p. The owned pointer will be deleted by + calling d(p). Y* must be convertible to T*. */ + template + Ptr(Y* p, D d); + + /* Same as the constructor below; it exists to suppress the generation + of the implicit copy constructor. */ + Ptr(const Ptr& o); + + /* Ptr that owns the same pointer as o and stores the same pointer as o, + converted to T*. Naturally, Y* must be convertible to T*. */ + template + Ptr(const Ptr& o); + + /* Ptr that owns same pointer as o, and stores p. Useful for casts and + creating non-owning Ptrs. */ + template + Ptr(const Ptr& o, T* p); + + /* Equivalent to release(). */ ~Ptr(); - //! copy constructor. Copies the members and calls addref() - Ptr(const Ptr& ptr); - template Ptr(const Ptr<_Tp2>& ptr); - //! copy operator. Calls ptr.addref() and release() before copying the members - Ptr& operator = (const Ptr& ptr); - //! increments the reference counter - void addref(); - //! decrements the reference counter. If it reaches 0, delete_obj() is called + + /* Same as assignment below; exists to suppress the generation of the + implicit assignment operator. */ + Ptr& operator = (const Ptr& o); + + template + Ptr& operator = (const Ptr& o); + + /* Resets both the owned and stored pointers to NULL. Deletes the owned + pointer with the associated deleter if it's not owned by any other + Ptr and is non-zero. It's called reset() in std::shared_ptr; here + it is release() for compatibility with old OpenCV versions. */ void release(); - //! deletes the object. Override if needed - void delete_obj(); - //! returns true iff obj==NULL + + /* Equivalent to assigning from Ptr(p). */ + template + void reset(Y* p); + + /* Equivalent to assigning from Ptr(p, d). */ + template + void reset(Y* p, D d); + + /* Swaps the stored and owned pointers of this and o. */ + void swap(Ptr& o); + + /* Returns the stored pointer. */ + T* get() const; + + /* Ordinary pointer emulation. */ + typename detail::RefOrVoid::type operator * () const; + T* operator -> () const; + + /* Equivalent to get(). */ + operator T* () const; + + /* Equivalent to !*this. */ bool empty() const; - //! cast pointer to another type - template Ptr<_Tp2> ptr(); - template const Ptr<_Tp2> ptr() const; + /* Returns a Ptr that owns the same pointer as this, and stores the same + pointer as this, except converted via static_cast to Y*. */ + template + Ptr staticCast() const; + + /* Ditto for const_cast. */ + template + Ptr constCast() const; - //! helper operators making "Ptr ptr" use very similar to "T* ptr". - _Tp* operator -> (); - const _Tp* operator -> () const; + /* Ditto for dynamic_cast. */ + template + Ptr dynamicCast() const; - operator _Tp* (); - operator const _Tp*() const; +private: + detail::PtrOwner* owner; + T* stored; - _Tp* obj; //< the object pointer. - int* refcount; //< the associated reference counter + template + friend struct Ptr; // have to do this for the cross-type copy constructor }; +/* Overload of the generic swap. */ +template +void swap(Ptr& ptr1, Ptr& ptr2); + +/* Obvious comparisons. */ +template +bool operator == (const Ptr& ptr1, const Ptr& ptr2); +template +bool operator != (const Ptr& ptr1, const Ptr& ptr2); + +/* Convenience creation functions. In the far future, there may be variadic templates here. */ +template +Ptr makePtr(); +template +Ptr makePtr(const A1& a1); +template +Ptr makePtr(const A1& a1, const A2& a2); +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3); +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4); +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5); +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6); +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7); +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8); +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9); +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10); //////////////////////////////// string class //////////////////////////////// @@ -324,176 +431,6 @@ private: }; - -/////////////////////////// cv::Ptr implementation /////////////////////////// - -template inline -Ptr<_Tp>::Ptr() - : obj(0), refcount(0) {} - -template inline -Ptr<_Tp>::Ptr(_Tp* _obj) - : obj(_obj) -{ - if(obj) - { - refcount = (int*)fastMalloc(sizeof(*refcount)); - *refcount = 1; - } - else - refcount = 0; -} - -template template -Ptr<_Tp>::Ptr(const Ptr<_Tp2>& p) - : obj(0), refcount(0) -{ - if (p.empty()) - return; - - _Tp* p_casted = dynamic_cast<_Tp*>(p.obj); - if (!p_casted) - return; - - obj = p_casted; - refcount = p.refcount; - addref(); -} - -template inline -Ptr<_Tp>::~Ptr() -{ - release(); -} - -template inline -void Ptr<_Tp>::addref() -{ - if( refcount ) - CV_XADD(refcount, 1); -} - -template inline -void Ptr<_Tp>::release() -{ - if( refcount && CV_XADD(refcount, -1) == 1 ) - { - delete_obj(); - fastFree(refcount); - } - refcount = 0; - obj = 0; -} - -template inline -void Ptr<_Tp>::delete_obj() -{ - if( obj ) - delete obj; -} - -template inline -Ptr<_Tp>::Ptr(const Ptr<_Tp>& _ptr) -{ - obj = _ptr.obj; - refcount = _ptr.refcount; - addref(); -} - -template inline -Ptr<_Tp>& Ptr<_Tp>::operator = (const Ptr<_Tp>& _ptr) -{ - int* _refcount = _ptr.refcount; - if( _refcount ) - CV_XADD(_refcount, 1); - release(); - obj = _ptr.obj; - refcount = _refcount; - return *this; -} - -template inline -_Tp* Ptr<_Tp>::operator -> () -{ - return obj; -} - -template inline -const _Tp* Ptr<_Tp>::operator -> () const -{ - return obj; -} - -template inline -Ptr<_Tp>::operator _Tp* () -{ - return obj; -} - -template inline -Ptr<_Tp>::operator const _Tp*() const -{ - return obj; -} - -template inline -bool Ptr<_Tp>::empty() const -{ - return obj == 0; -} - -template template inline -Ptr<_Tp2> Ptr<_Tp>::ptr() -{ - Ptr<_Tp2> p; - if( !obj ) - return p; - - _Tp2* obj_casted = dynamic_cast<_Tp2*>(obj); - if (!obj_casted) - return p; - - if( refcount ) - CV_XADD(refcount, 1); - - p.obj = obj_casted; - p.refcount = refcount; - return p; -} - -template template inline -const Ptr<_Tp2> Ptr<_Tp>::ptr() const -{ - Ptr<_Tp2> p; - if( !obj ) - return p; - - _Tp2* obj_casted = dynamic_cast<_Tp2*>(obj); - if (!obj_casted) - return p; - - if( refcount ) - CV_XADD(refcount, 1); - - p.obj = obj_casted; - p.refcount = refcount; - return p; -} - -template static inline -bool operator == (const Ptr<_Tp>& a, const Ptr<_Tp2>& b) -{ - return a.refcount == b.refcount; -} - -template static inline -bool operator != (const Ptr<_Tp>& a, const Ptr<_Tp2>& b) -{ - return a.refcount != b.refcount; -} - - - ////////////////////////// cv::String implementation ///////////////////////// inline @@ -940,4 +877,6 @@ namespace cv } } +#include "opencv2/core/ptr.inl.hpp" + #endif //__OPENCV_CORE_CVSTD_HPP__ diff --git a/modules/core/include/opencv2/core/ptr.inl.hpp b/modules/core/include/opencv2/core/ptr.inl.hpp new file mode 100644 index 0000000000000000000000000000000000000000..989724281f027b9f1efa8db3967830e928796aa1 --- /dev/null +++ b/modules/core/include/opencv2/core/ptr.inl.hpp @@ -0,0 +1,338 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, NVIDIA Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the copyright holders or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_CORE_PTR_INL_HPP__ +#define __OPENCV_CORE_PTR_INL_HPP__ + +#include + +namespace cv { + +template +void DefaultDeleter::operator () (Y* p) const +{ + delete p; +} + +namespace detail +{ + +struct PtrOwner +{ + PtrOwner() : refCount(1) + {} + + void incRef() + { + CV_XADD(&refCount, 1); + } + + void decRef() + { + if (CV_XADD(&refCount, -1) == 1) deleteSelf(); + } + +protected: + /* This doesn't really need to be virtual, since PtrOwner is never deleted + directly, but it doesn't hurt and it helps avoid warnings. */ + virtual ~PtrOwner() + {} + + virtual void deleteSelf() = 0; + +private: + unsigned int refCount; + + // noncopyable + PtrOwner(const PtrOwner&); + PtrOwner& operator = (const PtrOwner&); +}; + +template +struct PtrOwnerImpl : PtrOwner +{ + PtrOwnerImpl(Y* p, D d) : owned(p), deleter(d) + {} + + void deleteSelf() + { + deleter(owned); + delete this; + } + +private: + Y* owned; + D deleter; +}; + + +} + +template +Ptr::Ptr() : owner(NULL), stored(NULL) +{} + +template +template +Ptr::Ptr(Y* p) + : owner(p + ? new detail::PtrOwnerImpl >(p, DefaultDeleter()) + : NULL), + stored(p) +{} + +template +template +Ptr::Ptr(Y* p, D d) + : owner(p + ? new detail::PtrOwnerImpl(p, d) + : NULL), + stored(p) +{} + +template +Ptr::Ptr(const Ptr& o) : owner(o.owner), stored(o.stored) +{ + if (owner) owner->incRef(); +} + +template +template +Ptr::Ptr(const Ptr& o) : owner(o.owner), stored(o.stored) +{ + if (owner) owner->incRef(); +} + +template +template +Ptr::Ptr(const Ptr& o, T* p) : owner(o.owner), stored(p) +{ + if (owner) owner->incRef(); +} + +template +Ptr::~Ptr() +{ + release(); +} + +template +Ptr& Ptr::operator = (const Ptr& o) +{ + Ptr(o).swap(*this); + return *this; +} + +template +template +Ptr& Ptr::operator = (const Ptr& o) +{ + Ptr(o).swap(*this); + return *this; +} + +template +void Ptr::release() +{ + if (owner) owner->decRef(); + owner = NULL; + stored = NULL; +} + +template +template +void Ptr::reset(Y* p) +{ + Ptr(p).swap(*this); +} + +template +template +void Ptr::reset(Y* p, D d) +{ + Ptr(p, d).swap(*this); +} + +template +void Ptr::swap(Ptr& o) +{ + std::swap(owner, o.owner); + std::swap(stored, o.stored); +} + +template +T* Ptr::get() const +{ + return stored; +} + +template +typename detail::RefOrVoid::type Ptr::operator * () const +{ + return *stored; +} + +template +T* Ptr::operator -> () const +{ + return stored; +} + +template +Ptr::operator T* () const +{ + return stored; +} + + +template +bool Ptr::empty() const +{ + return !stored; +} + +template +template +Ptr Ptr::staticCast() const +{ + return Ptr(*this, static_cast(stored)); +} + +template +template +Ptr Ptr::constCast() const +{ + return Ptr(*this, const_cast(stored)); +} + +template +template +Ptr Ptr::dynamicCast() const +{ + return Ptr(*this, dynamic_cast(stored)); +} + +template +void swap(Ptr& ptr1, Ptr& ptr2){ + ptr1.swap(ptr2); +} + +template +bool operator == (const Ptr& ptr1, const Ptr& ptr2) +{ + return ptr1.get() == ptr2.get(); +} + +template +bool operator != (const Ptr& ptr1, const Ptr& ptr2) +{ + return ptr1.get() != ptr2.get(); +} + +template +Ptr makePtr() +{ + return Ptr(new T()); +} + +template +Ptr makePtr(const A1& a1) +{ + return Ptr(new T(a1)); +} + +template +Ptr makePtr(const A1& a1, const A2& a2) +{ + return Ptr(new T(a1, a2)); +} + +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3) +{ + return Ptr(new T(a1, a2, a3)); +} + +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4) +{ + return Ptr(new T(a1, a2, a3, a4)); +} + +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) +{ + return Ptr(new T(a1, a2, a3, a4, a5)); +} + +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) +{ + return Ptr(new T(a1, a2, a3, a4, a5, a6)); +} + +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) +{ + return Ptr(new T(a1, a2, a3, a4, a5, a6, a7)); +} + +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) +{ + return Ptr(new T(a1, a2, a3, a4, a5, a6, a7, a8)); +} + +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) +{ + return Ptr(new T(a1, a2, a3, a4, a5, a6, a7, a8, a9)); +} + +template +Ptr makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) +{ + return Ptr(new T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)); +} + +} // namespace cv + +#endif // __OPENCV_CORE_PTR_INL_HPP__