Zrythm v2.0.0-DEV
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
icloneable.h
1// SPDX-FileCopyrightText: © 2024-2025 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#pragma once
5
6#include <memory>
7#include <type_traits>
8#include <variant>
9#include <vector>
10
11#include "utils/initializable_object.h"
12#include "utils/qt.h"
13#include "utils/traits.h"
14#include "utils/variant_helpers.h"
15
16namespace zrythm::utils
17{
18
33
38template <typename T>
40 requires (T &obj, const T &other, ObjectCloneType clone_type) {
41 { init_from (obj, other, clone_type) } -> std::same_as<void>;
42 };
43
44template <CloneableObject Derived, typename... Args>
45std::unique_ptr<Derived>
46clone_unique (
47 const Derived &obj,
49 Args &&... args)
50{
51 std::unique_ptr<Derived> cloned;
53 {
54 auto result = Derived::create_unique (std::forward<Args> (args)...);
55 if (!result)
56 return nullptr;
57 cloned = std::move (result);
58 }
59 else
60 {
61 cloned = std::make_unique<Derived> (std::forward<Args> (args)...);
62 }
63 init_from (*cloned, obj, clone_type);
64 return cloned;
65}
66
67template <CloneableObject Derived, typename... Args>
68std::shared_ptr<Derived>
69clone_shared (
70 const Derived &obj,
72 Args &&... args)
73{
74 std::shared_ptr<Derived> cloned;
75 if constexpr (utils::Initializable<Derived>)
76 {
77 auto result =
78 Derived::template create_shared<Derived> (std::forward<Args> (args)...);
79 if (!result)
80 return nullptr;
81 cloned = std::move (result);
82 }
83 else
84 {
85 cloned = std::make_shared<Derived> (std::forward<Args> (args)...);
86 }
87 init_from (*cloned, obj, clone_type);
88 return cloned;
89}
90
91template <CloneableObject Derived, typename... Args>
92Derived *
93clone_raw_ptr (
94 const Derived &obj,
96 Args &&... args)
97{
98 auto unique_ptr = clone_unique (obj, clone_type, std::forward<Args> (args)...);
99 return unique_ptr.release ();
100}
101
102template <CloneableObject Derived, typename... Args>
103Derived *
104clone_qobject (
105 const Derived &obj,
106 QObject * parent,
108 Args &&... args)
109 requires utils::QObjectDerived<Derived>
110{
111 auto * cloned = clone_raw_ptr (obj, clone_type, std::forward<Args> (args)...);
112 if (cloned)
113 {
114 cloned->setParent (parent);
115 }
116 return cloned;
117}
118
119template <CloneableObject Derived, typename... Args>
120utils::QObjectUniquePtr<Derived>
121clone_unique_qobject (
122 const Derived &obj,
123 QObject * parent,
125 Args &&... args)
126 requires utils::QObjectDerived<Derived>
127{
128 return utils::QObjectUniquePtr<Derived> (
129 clone_qobject (obj, parent, clone_type, std::forward<Args> (args)...));
130}
131
136template <typename T>
138 CloneableObject<T> && std::default_initializable<T>;
139
141template <typename T, typename Base>
142concept InheritsFromBase = std::is_base_of_v<Base, std::remove_pointer_t<T>>;
143
145template <typename Variant, typename Base>
146concept AllInheritFromBase = requires {
147 []<typename... Ts> (std::variant<Ts...> *) {
148 static_assert (
150 "All types in Variant must inherit from Base");
151 }(static_cast<Variant *> (nullptr));
152};
153
162template <typename T, std::size_t N>
163void
165 std::array<std::unique_ptr<T>, N> &dest,
166 const std::array<std::unique_ptr<T>, N> &src,
168{
169 for (size_t i = 0; i < N; ++i)
170 {
171 if (src[i])
172 {
174 {
175 dest[i] =
176 clone_unique (*src[i], clone_type = ObjectCloneType::Snapshot);
177 }
178 else
179 {
180 dest[i] = std::make_unique<T> (*src[i]);
181 }
182 }
183 else
184 {
185 dest[i] = nullptr;
186 }
187 }
188}
189
198template <typename T, template <typename...> class Ptr>
199void
201 std::vector<Ptr<T>> &dest,
202 const std::vector<Ptr<T>> &src,
204{
205 dest.clear ();
206 dest.reserve (src.size ());
207
208 for (const auto &ptr : src)
209 {
210 if (ptr)
211 {
213 {
214 if constexpr (std::is_same_v<Ptr<T>, std::unique_ptr<T>>)
215 {
216 dest.push_back (clone_unique (
217 *ptr, clone_type = ObjectCloneType::Snapshot));
218 }
219 else if constexpr (std::is_same_v<Ptr<T>, std::shared_ptr<T>>)
220 {
221 dest.push_back (clone_shared (
222 *ptr, clone_type = ObjectCloneType::Snapshot));
223 }
224 }
225 else
226 {
227 if constexpr (std::is_same_v<Ptr<T>, std::unique_ptr<T>>)
228 {
229 dest.push_back (std::make_unique<T> (*ptr));
230 }
231 else if constexpr (std::is_same_v<Ptr<T>, std::shared_ptr<T>>)
232 {
233 dest.push_back (std::make_shared<T> (*ptr));
234 }
235 }
236 }
237 else
238 {
239 dest.push_back (nullptr);
240 }
241 }
242}
243
251template <typename Container>
252void
254 Container &dest,
255 const Container &src,
257{
258 if constexpr (StdArray<Container>)
259 {
260 clone_unique_ptr_array (dest, src, clone_type = ObjectCloneType::Snapshot);
261 }
262 else
263 {
264 clone_ptr_vector (dest, src, clone_type = ObjectCloneType::Snapshot);
265 }
266}
267
268template <typename Container, typename Variant, typename Base>
269 requires AllInheritFromBase<Variant, Base>
270void
271clone_variant_container (
272 Container &dest,
273 const Container &src,
275{
276 if constexpr (StdArray<Container>)
277 {
278 for (size_t i = 0; i < src.size (); ++i)
279 {
280 if (src[i])
281 {
282 dest[i] = clone_unique_with_variant<Variant, Base> (
283 src[i].get (), clone_type = ObjectCloneType::Snapshot);
284 }
285 else
286 {
287 dest[i] = nullptr;
288 }
289 }
290 }
291 else
292 {
293 dest.clear ();
294 dest.reserve (src.size ());
295
296 for (const auto &ptr : src)
297 {
298 if (ptr)
299 {
300 dest.push_back (
301 clone_unique_with_variant<Variant, Base> (
302 ptr.get (), clone_type = ObjectCloneType::Snapshot));
303 }
304 else
305 {
306 dest.push_back (nullptr);
307 }
308 }
309 }
310}
311
317template <typename Variant, typename Container>
319void
320clone_variant_container (
321 Container &dest,
322 const Container &src,
324{
325 using Base = typename Container::value_type::element_type;
326
327 if constexpr (StdArray<Container>)
328 {
329 // Handle std::array
330 for (size_t i = 0; i < src.size (); ++i)
331 {
332 if (src[i])
333 {
334 dest[i] = clone_unique_with_variant<Variant, Base> (
335 src[i].get (), clone_type = ObjectCloneType::Snapshot);
336 }
337 else
338 {
339 dest[i] = nullptr;
340 }
341 }
342 }
343 else
344 {
345 // Handle std::vector or similar containers
346 dest.clear ();
347 dest.reserve (src.size ());
348
349 for (const auto &ptr : src)
350 {
351 if (ptr)
352 {
353 dest.push_back (
354 clone_unique_with_variant<Variant, Base> (
355 ptr.get (), clone_type = ObjectCloneType::Snapshot));
356 }
357 else
358 {
359 dest.push_back (nullptr);
360 }
361 }
362 }
363}
364
365} // namespace zrythm::utils
Concept to ensure all types in a variant inherit from a base class.
Definition icloneable.h:146
Concept that checks if a type is cloneable.
Definition icloneable.h:137
Concept that checks if a type is cloneable.
Definition icloneable.h:39
Concept to check if a type inherits from a base class.
Definition icloneable.h:142
String utilities.
Definition algorithms.h:12
void clone_unique_ptr_container(Container &dest, const Container &src, ObjectCloneType clone_type=ObjectCloneType::Snapshot)
Clones the elements of a container of std::unique_ptr into the destination container.
Definition icloneable.h:253
void clone_unique_ptr_array(std::array< std::unique_ptr< T >, N > &dest, const std::array< std::unique_ptr< T >, N > &src, ObjectCloneType clone_type=ObjectCloneType::Snapshot)
Clones the elements of a std::array of std::unique_ptr into the destination array.
Definition icloneable.h:164
@ NewIdentity
Creates a separately identified object.
Definition icloneable.h:31
@ Snapshot
Creates a snapshot of the object with the same identity.
Definition icloneable.h:24
void clone_ptr_vector(std::vector< Ptr< T > > &dest, const std::vector< Ptr< T > > &src, ObjectCloneType clone_type=ObjectCloneType::Snapshot)
Clones the elements of a std::vector of std::unique_ptr or std::shared_ptr into the destination vecto...
Definition icloneable.h:200