diff options
author | Sergey Sharybin <sergey@blender.org> | 2022-03-23 14:05:47 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey@blender.org> | 2022-03-25 12:37:56 +0300 |
commit | 8c44793228750537c08ea7b19fc18df0138f9501 (patch) | |
tree | 74d2104cccc457e477d653faf8841053e22d203a /source/blender/makesdna/DNA_defs.h | |
parent | 315210c22baea5e0da06cac7fee4c24a4b7d887f (diff) |
Implement C++ methods for DNA structures
This change makes it possible to add implementation of common
C++ methods for DNA structures which helps ensuring unsafe
operations like shallow copy are done explicitly.
For example, creating a shallow copy used to be:
Object temp_object = *input_object;
In the C++ context it was seen like the temp_object is
properly decoupled from the input object, while in the
reality is it not. Now this code becomes:
Object temp_object = blender::dna::shallow_copy(*input_object);
The copy and move constructor and assignment operators are
now explicitly disabled.
Other than a more explicit resource management this change
also solves a lot of warnings generated by the implicitly
defined copy constructors w.r.t dealing with deprecated fields.
These warnings were generated by Apple Clang when a shallow
object copy was created via implicitly defined copy constructor.
In order to enable C++ methods for DNA structures a newly added
macro `DNA_DEFINE_CXX_METHODS()` is to be used:
tpyedef struct Object {
DNA_DEFINE_CXX_METHODS(Object)
...
} Object;
For the shallow copy use `blender::dna::shallow_copy()`.
The implementation of the memcpy is hidden via an internal DNA
function to avoid pulling `string.h` into every DNA header.
This means that the solution does not affect on the headers
dependencies.
---
Ideally `DNA_shallow_copy` would be defined in a more explicit
header, but don;t think we have a suitable one already. Maybe
we can introduce `DNA_access.h` ?
Differential Revision: https://developer.blender.org/D14427
Diffstat (limited to 'source/blender/makesdna/DNA_defs.h')
-rw-r--r-- | source/blender/makesdna/DNA_defs.h | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/source/blender/makesdna/DNA_defs.h b/source/blender/makesdna/DNA_defs.h index b4230209dd5..283eacf1a16 100644 --- a/source/blender/makesdna/DNA_defs.h +++ b/source/blender/makesdna/DNA_defs.h @@ -46,3 +46,84 @@ /* non-id name variables should use this length */ #define MAX_NAME 64 + +/* #DNA_DEFINE_CXX_METHODS is used to define C++ methods which are needed for proper/safe resource + * management, making unsafe (from an ownership perspective: i.e. pointers which sometimes needs to + * be set to nullptr on copy, sometimes needs to be dupalloc-ed) operations explicit, and taking + * care of compiler specific warnings when dealing with members marked with DNA_DEPRECATED. + * + * The `class_name` argument is to match the structure name the macro is used from. + * + * Typical usage example: + * + * typedef struct Object { + * DNA_DEFINE_CXX_METHODS(Object) + * } Object; + */ +#ifndef __cplusplus +# define DNA_DEFINE_CXX_METHODS(class_name) +#else + +/* Forward-declared here since there is no simple header file to be pulled for this functionality. + * Avoids pulling `string.h` from this header to get access to #memcpy. */ +extern "C" void _DNA_internal_memcpy(void *dst, const void *src, size_t size); + +namespace blender::dna::internal { + +template<class T> class ShallowDataConstRef { + public: + constexpr explicit ShallowDataConstRef(const T &ref) : ref_(ref) + { + } + + inline const T *get_pointer() const + { + return &ref_; + } + + private: + const T &ref_; +}; + +} // namespace blender::dna::internal + +# define DNA_DEFINE_CXX_METHODS(class_name) \ + class_name() = default; \ + ~class_name() = default; \ + /* Delete copy and assignment, which are not safe for resource ownership. */ \ + class_name(const class_name &other) = delete; \ + class_name(class_name &&other) noexcept = delete; \ + class_name &operator=(const class_name &other) = delete; \ + class_name &operator=(class_name &&other) = delete; \ + /* Support for shallow copy. */ \ + class_name(const blender::dna::internal::ShallowDataConstRef<class_name> ref) \ + { \ + _DNA_internal_memcpy(this, ref.get_pointer(), sizeof(class_name)); \ + } \ + class_name &operator=(const blender::dna::internal::ShallowDataConstRef<class_name> ref) \ + { \ + if (this != ref.get_pointer()) { \ + _DNA_internal_memcpy(this, ref.get_pointer(), sizeof(class_name)); \ + } \ + return *this; \ + } + +namespace blender::dna { + +/* Creates shallow copy of the given object. + * The entire object is copied as-is using memory copy. + * + * Typical usage: + * Object temp_object = blender::dna::shallow_copy(*input_object); + * + * From the implementation detail go via copy constructor/assign operator defined in the structure. + */ +template<class T> +[[nodiscard]] inline internal::ShallowDataConstRef<T> shallow_copy(const T &other) +{ + return internal::ShallowDataConstRef(other); +} + +} // namespace blender::dna + +#endif |