From e67cd74725700b236bb1d2346fc329ac4d04a07a Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 19 Dec 2022 16:19:46 +0100 Subject: [PATCH] express: Implement `copy.deepcopy()` for PointerToArray It actually makes a unique copy of the underlying array. --- doc/ReleaseNotes | 1 + panda/src/express/pointerToArray.h | 4 ++ panda/src/express/pointerToArray_ext.I | 28 ++++++++++++ panda/src/express/pointerToArray_ext.h | 4 ++ tests/express/test_pointertoarray.py | 60 ++++++++++++++++++++++++++ 5 files changed, 97 insertions(+) diff --git a/doc/ReleaseNotes b/doc/ReleaseNotes index 2b8d78a58b..946879c85a 100644 --- a/doc/ReleaseNotes +++ b/doc/ReleaseNotes @@ -71,6 +71,7 @@ Miscellaneous * Fix texture transforms sometimes not being flattened (#1392) * Fix support for `#pragma include ` in GLSL shaders * Fix `ShaderBuffer.prepare()` not doing anything +* Implement deepcopy for PointerToArray * Fix bf-cbc encryption no longer working when building with OpenSSL 3.0 * PandaNode bounds_type property was erroneously marked read-only * Fix warnings when copying OdeTriMeshGeom objects diff --git a/panda/src/express/pointerToArray.h b/panda/src/express/pointerToArray.h index 24a5322bc7..65974c28bc 100644 --- a/panda/src/express/pointerToArray.h +++ b/panda/src/express/pointerToArray.h @@ -121,6 +121,8 @@ PUBLISHED: EXTENSION(int __getbuffer__(PyObject *self, Py_buffer *view, int flags)); EXTENSION(void __releasebuffer__(PyObject *self, Py_buffer *view) const); + + EXTENSION(PointerToArray __deepcopy__(PyObject *memo) const); #endif #else // CPPPARSER @@ -279,6 +281,8 @@ PUBLISHED: EXTENSION(int __getbuffer__(PyObject *self, Py_buffer *view, int flags) const); EXTENSION(void __releasebuffer__(PyObject *self, Py_buffer *view) const); + + EXTENSION(ConstPointerToArray __deepcopy__(PyObject *memo) const); #endif #else // CPPPARSER diff --git a/panda/src/express/pointerToArray_ext.I b/panda/src/express/pointerToArray_ext.I index 425f4d87e3..a56368f36b 100644 --- a/panda/src/express/pointerToArray_ext.I +++ b/panda/src/express/pointerToArray_ext.I @@ -510,6 +510,20 @@ __releasebuffer__(PyObject *self, Py_buffer *view) const { #endif } +/** + * A special Python method that is invoked by copy.deepcopy(pta). This makes + * sure that there is truly a unique copy of the array. + */ +template +INLINE PointerToArray Extension >:: +__deepcopy__(PyObject *memo) const { + PointerToArray copy; + if (!_this->is_null()) { + copy.v() = _this->v(); + } + return copy; +} + /** * This is used to implement the buffer protocol, in order to allow efficient * access to the array data through a Python multiview object. @@ -702,3 +716,17 @@ __releasebuffer__(PyObject *self, Py_buffer *view) const { } #endif } + +/** + * A special Python method that is invoked by copy.deepcopy(pta). This makes + * sure that there is truly a unique copy of the array. + */ +template +INLINE ConstPointerToArray Extension >:: +__deepcopy__(PyObject *memo) const { + PointerToArray copy; + if (!_this->is_null()) { + copy.v() = _this->v(); + } + return copy; +} diff --git a/panda/src/express/pointerToArray_ext.h b/panda/src/express/pointerToArray_ext.h index ce6104791b..6059aec062 100644 --- a/panda/src/express/pointerToArray_ext.h +++ b/panda/src/express/pointerToArray_ext.h @@ -44,6 +44,8 @@ public: INLINE int __getbuffer__(PyObject *self, Py_buffer *view, int flags); INLINE void __releasebuffer__(PyObject *self, Py_buffer *view) const; + + INLINE PointerToArray __deepcopy__(PyObject *memo) const; }; template<> @@ -81,6 +83,8 @@ public: INLINE int __getbuffer__(PyObject *self, Py_buffer *view, int flags) const; INLINE void __releasebuffer__(PyObject *self, Py_buffer *view) const; + + INLINE ConstPointerToArray __deepcopy__(PyObject *memo) const; }; template<> diff --git a/tests/express/test_pointertoarray.py b/tests/express/test_pointertoarray.py index e68fa2ca36..3c87373904 100644 --- a/tests/express/test_pointertoarray.py +++ b/tests/express/test_pointertoarray.py @@ -69,3 +69,63 @@ def test_cpta_float_pickle(): data_pta2 = loads(dumps(data_pta, proto)) assert tuple(data_pta2) == (1.0, 2.0, 3.0) assert data_pta2.get_data() == data_pta.get_data() + + +def test_pta_float_copy(): + from panda3d.core import PTA_float + from copy import copy + + null_pta = PTA_float() + assert copy(null_pta).is_null() + + empty_pta = PTA_float([]) + empty_pta_copy = copy(empty_pta) + assert not empty_pta_copy.is_null() + assert len(empty_pta_copy) == 0 + assert empty_pta_copy.get_ref_count() == 2 + + data_pta = PTA_float([1.0, 2.0, 3.0]) + data_pta_copy = copy(data_pta) + assert not data_pta_copy.is_null() + assert data_pta_copy.get_ref_count() == 2 + assert tuple(data_pta_copy) == (1.0, 2.0, 3.0) + + +def test_pta_float_deepcopy(): + from panda3d.core import PTA_float + from copy import deepcopy + + null_pta = PTA_float() + assert deepcopy(null_pta).is_null() + + empty_pta = PTA_float([]) + empty_pta_copy = deepcopy(empty_pta) + assert not empty_pta_copy.is_null() + assert len(empty_pta_copy) == 0 + assert empty_pta_copy.get_ref_count() == 1 + + data_pta = PTA_float([1.0, 2.0, 3.0]) + data_pta_copy = deepcopy(data_pta) + assert not data_pta_copy.is_null() + assert data_pta_copy.get_ref_count() == 1 + assert tuple(data_pta_copy) == (1.0, 2.0, 3.0) + + +def test_cpta_float_deepcopy(): + from panda3d.core import PTA_float, CPTA_float + from copy import deepcopy + + null_pta = CPTA_float(PTA_float()) + assert deepcopy(null_pta).is_null() + + empty_pta = CPTA_float([]) + empty_pta_copy = deepcopy(empty_pta) + assert not empty_pta_copy.is_null() + assert len(empty_pta_copy) == 0 + assert empty_pta_copy.get_ref_count() == 1 + + data_pta = CPTA_float([1.0, 2.0, 3.0]) + data_pta_copy = deepcopy(data_pta) + assert not data_pta_copy.is_null() + assert data_pta_copy.get_ref_count() == 1 + assert tuple(data_pta_copy) == (1.0, 2.0, 3.0)