diff --git a/modules/core/include/opencv2/core/cvdef.h b/modules/core/include/opencv2/core/cvdef.h index 9f4a004f9..9947bdfdb 100644 --- a/modules/core/include/opencv2/core/cvdef.h +++ b/modules/core/include/opencv2/core/cvdef.h @@ -230,4 +230,23 @@ # endif #endif + +/****************************************************************************************\ +* C++ Move semantics * +\****************************************************************************************/ + +#ifndef CV_CXX_MOVE_SEMANTICS +# if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(_MSC_VER) && _MSC_VER >= 1600 +# define CV_CXX_MOVE_SEMANTICS 1 +# elif defined(__clang) +# if __has_feature(cxx_rvalue_references) +# define CV_CXX_MOVE_SEMANTICS 1 +# endif +# endif +#else +# if CV_CXX_MOVE_SEMANTICS == 0 +# undef CV_CXX_MOVE_SEMANTICS +# endif +#endif + #endif // __OPENCV_CORE_CVDEF_H__ diff --git a/modules/core/include/opencv2/core/cvstd.hpp b/modules/core/include/opencv2/core/cvstd.hpp index 3977d513f..dff0b20cf 100644 --- a/modules/core/include/opencv2/core/cvstd.hpp +++ b/modules/core/include/opencv2/core/cvstd.hpp @@ -411,6 +411,11 @@ struct Ptr template Ptr dynamicCast() const; +#ifdef CV_CXX_MOVE_SEMANTICS + Ptr(Ptr&& o); + Ptr& operator = (Ptr&& o); +#endif + private: detail::PtrOwner* owner; T* stored; diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index 7f609dbb1..e85bf6fa5 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -1854,6 +1854,11 @@ public: /** @overload */ template void forEach(const Functor& operation) const; +#ifdef CV_CXX_MOVE_SEMANTICS + Mat(Mat&& m); + Mat& operator = (Mat&& m); +#endif + enum { MAGIC_VAL = 0x42FF0000, AUTO_STEP = 0, CONTINUOUS_FLAG = CV_MAT_CONT_FLAG, SUBMATRIX_FLAG = CV_SUBMAT_FLAG }; enum { MAGIC_MASK = 0xFFFF0000, TYPE_MASK = 0x00000FFF, DEPTH_MASK = 7 }; @@ -2084,6 +2089,16 @@ public: template operator Vec::channel_type, n>() const; //! conversion to Matx template operator Matx::channel_type, m, n>() const; + +#ifdef CV_CXX_MOVE_SEMANTICS + Mat_(Mat_&& m); + Mat_& operator = (Mat_&& m); + + Mat_(Mat&& m); + Mat_& operator = (Mat&& m); + + Mat_(MatExpr&& e); +#endif }; typedef Mat_ Mat1b; @@ -2276,6 +2291,11 @@ public: //! returns N if the matrix is 1-channel (N x ptdim) or ptdim-channel (1 x N) or (N x 1); negative number otherwise int checkVector(int elemChannels, int depth=-1, bool requireContinuous=true) const; +#ifdef CV_CXX_MOVE_SEMANTICS + UMat(UMat&& m); + UMat& operator = (UMat&& m); +#endif + void* handle(int accessFlags) const; void ndoffset(size_t* ofs) const; diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index ba52efde1..b7f46d6a9 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -1107,6 +1107,69 @@ void Mat::push_back(const MatExpr& expr) push_back(static_cast(expr)); } +#ifdef CV_CXX_MOVE_SEMANTICS + +inline +Mat::Mat(Mat&& m) + : flags(m.flags), dims(m.dims), rows(m.rows), cols(m.cols), data(m.data), + datastart(m.datastart), dataend(m.dataend), datalimit(m.datalimit), allocator(m.allocator), + u(m.u), size(&rows) +{ + if (m.dims <= 2) // move new step/size info + { + step[0] = m.step[0]; + step[1] = m.step[1]; + } + else + { + CV_DbgAssert(m.step.p != m.step.buf); + step.p = m.step.p; + size.p = m.size.p; + m.step.p = m.step.buf; + m.size.p = &m.rows; + } + m.flags = MAGIC_VAL; m.dims = m.rows = m.cols = 0; + m.data = NULL; m.datastart = NULL; m.dataend = NULL; m.datalimit = NULL; + m.allocator = NULL; + m.u = NULL; +} + +inline +Mat& Mat::operator = (Mat&& m) +{ + release(); + flags = m.flags; dims = m.dims; rows = m.rows; cols = m.cols; data = m.data; + datastart = m.datastart; dataend = m.dataend; datalimit = m.datalimit; allocator = m.allocator; + u = m.u; + if (step.p != step.buf) // release self step/size + { + fastFree(step.p); + step.p = step.buf; + size.p = &rows; + } + if (m.dims <= 2) // move new step/size info + { + step[0] = m.step[0]; + step[1] = m.step[1]; + } + else + { + CV_DbgAssert(m.step.p != m.step.buf); + step.p = m.step.p; + size.p = m.size.p; + m.step.p = m.step.buf; + m.size.p = &m.rows; + } + m.flags = MAGIC_VAL; m.dims = m.rows = m.cols = 0; + m.data = NULL; m.datastart = NULL; m.dataend = NULL; m.datalimit = NULL; + m.allocator = NULL; + m.u = NULL; + return *this; +} + +#endif + + ///////////////////////////// MatSize //////////////////////////// inline @@ -1655,6 +1718,57 @@ void Mat_<_Tp>::forEach(const Functor& operation) const { Mat::forEach<_Tp, Functor>(operation); } +#ifdef CV_CXX_MOVE_SEMANTICS + +template inline +Mat_<_Tp>::Mat_(Mat_&& m) + : Mat(m) +{ +} + +template inline +Mat_<_Tp>& Mat_<_Tp>::operator = (Mat_&& m) +{ + Mat::operator = (m); + return *this; +} + +template inline +Mat_<_Tp>::Mat_(Mat&& m) + : Mat() +{ + flags = (flags & ~CV_MAT_TYPE_MASK) | DataType<_Tp>::type; + *this = m; +} + +template inline +Mat_<_Tp>& Mat_<_Tp>::operator = (Mat&& m) +{ + if( DataType<_Tp>::type == m.type() ) + { + Mat::operator = ((Mat&&)m); + return *this; + } + if( DataType<_Tp>::depth == m.depth() ) + { + Mat::operator = ((Mat&&)m.reshape(DataType<_Tp>::channels, m.dims, 0)); + return *this; + } + CV_DbgAssert(DataType<_Tp>::channels == m.channels()); + m.convertTo(*this, type()); + return *this; +} + +template inline +Mat_<_Tp>::Mat_(MatExpr&& e) + : Mat() +{ + flags = (flags & ~CV_MAT_TYPE_MASK) | DataType<_Tp>::type; + *this = Mat(e); +} + +#endif + ///////////////////////////// SparseMat ///////////////////////////// inline @@ -3419,6 +3533,69 @@ size_t UMat::total() const return p; } +#ifdef CV_CXX_MOVE_SEMANTICS + +inline +UMat::UMat(UMat&& m) +: flags(m.flags), dims(m.dims), rows(m.rows), cols(m.cols), allocator(m.allocator), + usageFlags(m.usageFlags), u(m.u), offset(m.offset), size(&rows) +{ + if (m.dims <= 2) // move new step/size info + { + step[0] = m.step[0]; + step[1] = m.step[1]; + } + else + { + CV_DbgAssert(m.step.p != m.step.buf); + step.p = m.step.p; + size.p = m.size.p; + m.step.p = m.step.buf; + m.size.p = &m.rows; + } + m.flags = MAGIC_VAL; m.dims = m.rows = m.cols = 0; + m.allocator = NULL; + m.u = NULL; + m.offset = 0; +} + +inline +UMat& UMat::operator = (UMat&& m) +{ + release(); + flags = m.flags; dims = m.dims; rows = m.rows; cols = m.cols; + allocator = m.allocator; usageFlags = m.usageFlags; + u = m.u; + offset = m.offset; + if (step.p != step.buf) // release self step/size + { + fastFree(step.p); + step.p = step.buf; + size.p = &rows; + } + if (m.dims <= 2) // move new step/size info + { + step[0] = m.step[0]; + step[1] = m.step[1]; + } + else + { + CV_DbgAssert(m.step.p != m.step.buf); + step.p = m.step.p; + size.p = m.size.p; + m.step.p = m.step.buf; + m.size.p = &m.rows; + } + m.flags = MAGIC_VAL; m.dims = m.rows = m.cols = 0; + m.allocator = NULL; + m.u = NULL; + m.offset = 0; + return *this; +} + +#endif + + inline bool UMatData::hostCopyObsolete() const { return (flags & HOST_COPY_OBSOLETE) != 0; } inline bool UMatData::deviceCopyObsolete() const { return (flags & DEVICE_COPY_OBSOLETE) != 0; } inline bool UMatData::deviceMemMapped() const { return (flags & DEVICE_MEM_MAPPED) != 0; } diff --git a/modules/core/include/opencv2/core/ptr.inl.hpp b/modules/core/include/opencv2/core/ptr.inl.hpp index 65c09d1cb..3f6f214a8 100644 --- a/modules/core/include/opencv2/core/ptr.inl.hpp +++ b/modules/core/include/opencv2/core/ptr.inl.hpp @@ -252,6 +252,29 @@ Ptr Ptr::dynamicCast() const return Ptr(*this, dynamic_cast(stored)); } +#ifdef CV_CXX_MOVE_SEMANTICS + +template +Ptr::Ptr(Ptr&& o) : owner(o.owner), stored(o.stored) +{ + o.owner = NULL; + o.stored = NULL; +} + +template +Ptr& Ptr::operator = (Ptr&& o) +{ + release(); + owner = o.owner; + stored = o.stored; + o.owner = NULL; + o.stored = NULL; + return *this; +} + +#endif + + template void swap(Ptr& ptr1, Ptr& ptr2){ ptr1.swap(ptr2);