Sound Bakery  v0.1.0
Open-source audio middleware for games
Loading...
Searching...
No Matches
database_ptr.h
1#pragma once
2
3#include "sound_bakery/core/database/database_object.h"
4#include "sound_bakery/pch.h"
5
6namespace sbk::core
7{
8 class database_object;
9
10 std::weak_ptr<database_object> SB_API find_object(sbk_id id);
11 bool SB_API object_id_is_child_of_parent(sbk_id childToCheck, sbk_id parent);
12 sbk_id SB_API get_parent_id_from_id(sbk_id id);
13
21 template <typename TObject>
23 {
24 public:
26 using TIdentifierType = sbk_id;
27 using TObjectPtr = TObject*;
28 using TObjectRef = TObject&;
29 using TObjectWeak = std::weak_ptr<database_object>;
30 using TObjectShared = std::shared_ptr<TObject>;
31 using TPtrType = std::weak_ptr<database_object>;
32
33 static_assert(!std::is_pointer<TObject>::value);
34
35 public:
39 database_ptr() : m_objectID(), m_objectPtr(), m_null(true) {}
40
41 database_ptr(const TThisType& other) = default;
42 database_ptr(TThisType&& other) = default;
43
49 database_ptr(sbk_id id) : m_objectID(id), m_objectPtr(), m_null(true) {}
50
55 database_ptr(const TObjectShared& object)
56 : m_objectID(object ? static_cast<TIdentifierType>(*object) : 0),
57 m_objectPtr(object),
58 m_null(object.use_count() == 0)
59 {
60 }
61
66 database_ptr(const TObjectPtr& object)
67 : m_objectID(object ? static_cast<TIdentifierType>(*object) : 0),
68 m_objectPtr(find_object(id())),
69 m_null(object == nullptr)
70 {
71 }
72
77 database_ptr(std::nullptr_t) : m_objectID(), m_objectPtr(), m_null(true) {}
78
79 ~database_ptr() = default;
80
81 public:
85 auto id() const noexcept -> sbk_id { return m_objectID; }
86
87 auto shared() const noexcept -> TObjectShared
88 {
89 lookup();
90
91 if (m_objectPtr.expired())
92 {
93 return std::shared_ptr<TObject>();
94 }
95 else
96 {
97 return std::static_pointer_cast<TObject>(m_objectPtr.lock());
98 }
99 }
100
101 auto weak() const noexcept -> TObjectWeak { return m_objectPtr; }
102
106 auto raw() const noexcept -> TObjectPtr { return shared().get(); }
107
108 auto lookup_raw() const noexcept -> TObjectPtr
109 {
110 lookup();
111 return raw();
112 }
113
118 auto has_id() const noexcept -> bool { return m_objectID != TIdentifierType(); }
119
123 auto null() const noexcept -> bool { return m_null || m_objectPtr.expired(); }
124
129 auto pending() const noexcept -> bool { return has_id() && null(); }
130
135 auto stale() const noexcept -> bool { return !m_null && m_objectPtr.expired(); }
136
141 auto valid() const noexcept -> bool { return has_id() && !null(); }
142
147 auto lookup() const noexcept -> bool
148 {
149 if (pending())
150 {
151 m_objectPtr = find_object(id());
152 m_null = m_objectPtr.expired();
153 }
154 return valid();
155 }
156
160 auto reset(TObjectPtr object = nullptr) -> void
161 {
162 m_objectID = object ? static_cast<TIdentifierType>(*object) : TIdentifierType();
163 m_objectPtr.reset();
164 m_null = true;
165
166 lookup();
167 }
168
169 TThisType& operator=(TObjectShared object)
170 {
171 if (raw() != object.get())
172 {
173 reset(object.get());
174 }
175 return *this;
176 }
177
184 TThisType& operator=(TObjectPtr object)
185 {
186 if (raw() != object)
187 {
188 reset(object);
189 }
190 return *this;
191 }
192
193 TThisType& operator=(const TThisType& other)
194 {
195 if (id() != other.id())
196 {
197 m_objectID = other.id();
198 m_objectPtr = other.weak();
199 m_null = other.null();
200 }
201
202 return *this;
203 }
204
205 TThisType& operator=(const TThisType&& other)
206 {
207 if (id() != other.id())
208 {
209 m_objectID = other.id();
210 m_objectPtr = other.weak();
211 m_null = other.null();
212 }
213
214 return *this;
215 }
216
220 operator bool() const { return valid(); }
221
225 bool operator!() const { return !valid(); }
226
231 TObjectPtr operator->() const { return raw(); }
232
233 protected:
234 sbk_id m_objectID;
235 mutable TPtrType m_objectPtr = TPtrType();
236 mutable bool m_null;
237 };
238
245 template <typename T1, typename T2>
246 bool operator==(const database_ptr<T1>& lhs, const database_ptr<T2>& rhs)
247 {
248 return lhs.id() == rhs.id();
249 }
250
255 template <typename T>
256 bool operator==(const database_ptr<T>& lhs, const T* rhs)
257 {
258 return lhs.raw() == rhs;
259 }
260
264 template <typename T1, typename T2>
265 bool operator<(const database_ptr<T1>& lhs, const database_ptr<T2>& rhs)
266 {
267 return lhs.id() < rhs.id();
268 }
269
274 template <typename TObject>
275 class child_ptr final : public database_ptr<TObject>
276 {
277 public:
279
280 public:
287 child_ptr() = default;
288
289 child_ptr(const TThisType& other) : database_ptr<TObject>(other), m_ownerID(other.m_ownerID)
290 {
291 // If we don't have an owner, try finding it now
292 // We can't do any other checks because we were empty before this copy
293 // Because we can't do checks, we're just hoping the passed in object is valid
294 if (m_ownerID == 0)
295 {
296 m_ownerID = get_parent_id_from_id(other.m_objectID);
297 }
298 }
299
300 child_ptr(TThisType&& other) = default;
301 ~child_ptr() = default;
302
311 child_ptr(const database_object& owner) : database_ptr<TObject>(), m_ownerID(owner.get_database_id()) {}
312
318 child_ptr(sbk_id id) : database_ptr<TObject>(id), m_ownerID(get_parent_id_from_id(id)) {}
319
320 TThisType& operator=(typename database_ptr<TObject>::TIdentifierType id)
321 {
322 setID(id);
323
324 return *this;
325 }
326
327 TThisType& operator=(typename database_ptr<TObject>::TObjectPtr object)
328 {
329 reset(object);
330
331 return *this;
332 }
333
334 TThisType& operator=(const TThisType& other)
335 {
336 if (database_ptr<TObject>::id() != other.id())
337 {
338 if (m_ownerID == 0 && database_ptr<TObject>::m_objectID != 0)
339 {
340 m_ownerID = get_parent_id_from_id(database_ptr<TObject>::m_objectID);
341 }
342
343 // If we don't have an owner, we don't care about checking children
344 // We can completely copy other
345 if (m_ownerID == 0)
346 {
347 database_ptr<TObject>::m_objectID = other.id();
348 database_ptr<TObject>::m_objectPtr = other.weak();
349 database_ptr<TObject>::m_null = other.null();
350 m_ownerID = other.m_ownerID;
351 }
352 // If owner isn't trying to be changed, we can just check children and update the pointed to ID
353 else if (m_ownerID == other.m_ownerID || other.m_ownerID == 0)
354 {
355 // Do child check
356 if (object_id_is_child_of_parent(other.m_objectID, m_ownerID))
357 {
358 database_ptr<TObject>::m_objectID = other.id();
359 database_ptr<TObject>::m_objectPtr = other.weak();
360 database_ptr<TObject>::m_null = other.null();
361 }
362 }
363 // else: don't allow changing owner IDs once they're set
364 }
365
366 return *this;
367 }
368
369 void setID(typename database_ptr<TObject>::TIdentifierType id = 0)
370 {
371 // Fill our get_parent ID if we didn't have it already
372 if (m_ownerID == 0 && database_ptr<TObject>::m_objectID != 0)
373 {
374 m_ownerID = get_parent_id_from_id(database_ptr<TObject>::m_objectID);
375 }
376
377 if (id == 0)
378 {
379 database_ptr<TObject>::m_objectID = 0;
380 database_ptr<TObject>::m_objectPtr.reset();
381 database_ptr<TObject>::m_null = true;
382 }
383 else
384 {
385 if (m_ownerID == 0 || object_id_is_child_of_parent(id, m_ownerID))
386 {
387 database_ptr<TObject>::m_objectID = id;
388 database_ptr<TObject>::m_objectPtr.reset();
389 database_ptr<TObject>::m_null = true;
390 }
391 }
392 }
393
394 void reset(typename database_ptr<TObject>::TObjectPtr object = nullptr)
395 {
396 // Fill our get_parent ID if we didn't have it already
397 if (m_ownerID == 0 && database_ptr<TObject>::m_objectID != 0)
398 {
399 m_ownerID = get_parent_id_from_id(database_ptr<TObject>::m_objectID);
400 }
401
402 // Reset pointed to values but retain the owner ID
403 if (object == nullptr)
404 {
405 database_ptr<TObject>::m_objectID = 0;
406 database_ptr<TObject>::m_objectPtr.reset();
407 database_ptr<TObject>::m_null = true;
408 }
409 // Point to new object if it's a child of our owner
410 else
411 {
412 sbk_id newObjectID = static_cast<typename database_ptr<TObject>::TIdentifierType>(*object);
413
414 if (m_ownerID == 0 || object_id_is_child_of_parent(newObjectID, m_ownerID))
415 {
416 database_ptr<TObject>::m_objectID = newObjectID;
417 database_ptr<TObject>::m_objectPtr.reset();
418 database_ptr<TObject>::m_null = true;
419 }
420 }
421 }
422
423 private:
424 typename database_ptr<TObject>::TIdentifierType m_ownerID = 0;
425 };
426} // namespace sbk::core
427
428namespace std
429{
430 template <typename T>
431 struct hash<sbk::core::database_ptr<T>>
432 {
433 size_t operator()(const sbk::core::database_ptr<T>& k) const { return hash<sbk_id>{}(k.id()); }
434 };
435
436 template <typename T>
437 struct hash<sbk::core::child_ptr<T>>
438 {
439 size_t operator()(const sbk::core::child_ptr<T>& k) const { return hash<sbk_id>{}(k.id()); }
440 };
441} // namespace std
442
443#include <rttr/wrapper_mapper.h>
444
445namespace rttr
446{
447 template <typename T>
448 struct wrapper_mapper<sbk::core::child_ptr<T>>
449 {
450 using wrapped_type = decltype(sbk::core::child_ptr<T>(0).id());
452
453 inline static wrapped_type get(const type& obj) { return obj.id(); }
454
455 inline static type create(const wrapped_type& t) { return type(t); }
456
457 template <typename T2>
458 inline static sbk::core::child_ptr<T2> convert(const type& source, bool& ok)
459 {
460 sbk::core::child_ptr<T2> convertedLazyPtr(source.id());
461
462 ok = source.has_id() == convertedLazyPtr.has_id();
463
464 return convertedLazyPtr;
465 }
466 };
467
468 template <typename T>
469 struct wrapper_mapper<sbk::core::database_ptr<T>>
470 {
471 using wrapped_type = decltype(sbk::core::database_ptr<T>().id());
473
474 inline static wrapped_type get(const type& obj) { return obj.id(); }
475
476 inline static type create(const wrapped_type& t) { return type(t); }
477
478 template <typename T2>
479 inline static sbk::core::database_ptr<T2> convert(const type& source, bool& ok)
480 {
481 sbk::core::database_ptr<T2> convertedLazyPtr(source.id());
482
483 ok = source.has_id() == convertedLazyPtr.has_id();
484
485 return convertedLazyPtr;
486 }
487 };
488
489} // namespace rttr
Syntactic type to define a pointer that must be a child of the owning object.
Definition database_ptr.h:276
child_ptr(const database_object &owner)
Construct a new Child Ptr object with an owner.
Definition database_ptr.h:311
child_ptr(sbk_id id)
Construct a new child_ptr that points to the ID.
Definition database_ptr.h:318
child_ptr()=default
Default constructor is exposed for RTTR but not for the user.
Base object type for any object that can exist in the editor/database. Holds an ID and name.
Definition database_object.h:12
Definition database_ptr.h:23
auto raw() const noexcept -> TObjectPtr
Get raw pointer of the referenced object.
Definition database_ptr.h:106
auto stale() const noexcept -> bool
Returns true if we previously referenced an object that has been destroyed.
Definition database_ptr.h:135
TObjectPtr operator->() const
Access the raw object.
Definition database_ptr.h:231
database_ptr(std::nullptr_t)
Create an empty and null LazyPtr.
Definition database_ptr.h:77
database_ptr(sbk_id id)
Creates a LazyPtr that can lookup its object pointer after construction.
Definition database_ptr.h:49
auto pending() const noexcept -> bool
Returns true if we hold an ID but haven't found the live object to point to yet.
Definition database_ptr.h:129
auto reset(TObjectPtr object=nullptr) -> void
Clear all references.
Definition database_ptr.h:160
bool operator!() const
Returns true if this LazyPtr is invalid.
Definition database_ptr.h:225
database_ptr()
Creates an empty and null LazyPtr.
Definition database_ptr.h:39
database_ptr(const TObjectShared &object)
Create a valid LazyPtr.
Definition database_ptr.h:55
TThisType & operator=(TObjectPtr object)
Assign this LazyPtr to a new object, potentially destroying the current object if we're acting as a U...
Definition database_ptr.h:184
database_ptr(const TObjectPtr &object)
Create a valid LazyPtr.
Definition database_ptr.h:66
auto null() const noexcept -> bool
Returns true if the object pointer is not set.
Definition database_ptr.h:123
auto valid() const noexcept -> bool
Returns true if we hold an ID and a valid pointer to the object.
Definition database_ptr.h:141
auto has_id() const noexcept -> bool
Returns true if we hold a valid ID and can search for an object at runtime.
Definition database_ptr.h:118
auto lookup() const noexcept -> bool
Find the live object referenced by the ID and store it.
Definition database_ptr.h:147
auto id() const noexcept -> sbk_id
Get ID of the referenced object.
Definition database_ptr.h:85
Base object that all sound Bakery objects should inherit from.
Definition object.h:23