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 findObject(sbk_id id);
11 bool SB_API objectIdIsChildOfParent(sbk_id childToCheck, sbk_id parent);
12 sbk_id SB_API getParentIdFromId(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), m_objectPtr(findObject(id())), m_null(object == nullptr)
68 {
69 }
70
75 database_ptr(std::nullptr_t) : m_objectID(), m_objectPtr(), m_null(true) {}
76
77 ~database_ptr() = default;
78
79 public:
84 sbk_id id() const noexcept { return m_objectID; }
85
86 TObjectShared shared() const noexcept
87 {
88 lookup();
89
90 if (m_objectPtr.expired())
91 {
92 return std::shared_ptr<TObject>();
93 }
94 else
95 {
96 return std::static_pointer_cast<TObject>(m_objectPtr.lock());
97 }
98 }
99
100 TObjectWeak weak() const noexcept { return m_objectPtr; }
101
106 TObjectPtr raw() const noexcept { return shared().get(); }
107
108 TObjectPtr lookupRaw() const noexcept
109 {
110 lookup();
111 return raw();
112 }
113
119 bool hasId() const { return m_objectID != TIdentifierType(); }
120
125 bool null() const { return m_null || m_objectPtr.expired(); }
126
132 bool pending() const { return hasId() && null(); }
133
139 bool stale() const { return !m_null && m_objectPtr.expired(); }
140
146 bool valid() const { return hasId() && !null(); }
147
148 public:
153 bool lookup() const
154 {
155 if (pending())
156 {
157 m_objectPtr = findObject(id());
158 m_null = m_objectPtr.expired();
159 }
160 return valid();
161 }
162
166 void reset(TObjectPtr object = nullptr)
167 {
168 m_objectID = object ? static_cast<TIdentifierType>(*object) : TIdentifierType();
169 m_objectPtr.reset();
170 m_null = true;
171
172 lookup();
173 }
174
175 public:
176 TThisType& operator=(TObjectShared object)
177 {
178 if (raw() != object.get())
179 {
180 reset(object.get());
181 }
182 return *this;
183 }
184
191 TThisType& operator=(TObjectPtr object)
192 {
193 if (raw() != object)
194 {
195 reset(object);
196 }
197 return *this;
198 }
199
200 TThisType& operator=(const TThisType& other)
201 {
202 if (id() != other.id())
203 {
204 m_objectID = other.id();
205 m_objectPtr = other.weak();
206 m_null = other.null();
207 }
208
209 return *this;
210 }
211
212 TThisType& operator=(const TThisType&& other)
213 {
214 if (id() != other.id())
215 {
216 m_objectID = other.id();
217 m_objectPtr = other.weak();
218 m_null = other.null();
219 }
220
221 return *this;
222 }
223
227 operator bool() const { return valid(); }
228
232 bool operator!() const { return !valid(); }
233
238 TObjectPtr operator->() const { return raw(); }
239
240 protected:
241 sbk_id m_objectID;
242 mutable TPtrType m_objectPtr = TPtrType();
243 mutable bool m_null;
244 };
245
256 template <typename T1, typename T2>
257 bool operator==(const database_ptr<T1>& lhs, const database_ptr<T2>& rhs)
258 {
259 return lhs.id() == rhs.id();
260 }
261
270 template <typename T>
271 bool operator==(const database_ptr<T>& lhs, const T* rhs)
272 {
273 return lhs.raw() == rhs;
274 }
275
286 template <typename T1, typename T2>
287 bool operator<(const database_ptr<T1>& lhs, const database_ptr<T2>& rhs)
288 {
289 return lhs.id() < rhs.id();
290 }
291
296 template <typename TObject>
297 class child_ptr final : public database_ptr<TObject>
298 {
299 public:
301
302 public:
309 child_ptr() = default;
310
311 child_ptr(const TThisType& other) : database_ptr<TObject>(other), m_ownerID(other.m_ownerID)
312 {
313 // If we don't have an owner, try finding it now
314 // We can't do any other checks because we were empty before this copy
315 // Because we can't do checks, we're just hoping the passed in object is valid
316 if (m_ownerID == 0)
317 {
318 m_ownerID = getParentIdFromId(other.m_objectID);
319 }
320 }
321
322 child_ptr(TThisType&& other) = default;
323 ~child_ptr() = default;
324
333 child_ptr(const database_object& owner) : database_ptr<TObject>(), m_ownerID(owner.get_database_id()) {}
334
340 child_ptr(sbk_id id) : database_ptr<TObject>(id), m_ownerID(getParentIdFromId(id)) {}
341
342 TThisType& operator=(typename database_ptr<TObject>::TIdentifierType id)
343 {
344 setID(id);
345
346 return *this;
347 }
348
349 TThisType& operator=(typename database_ptr<TObject>::TObjectPtr object)
350 {
351 reset(object);
352
353 return *this;
354 }
355
356 TThisType& operator=(const TThisType& other)
357 {
358 if (database_ptr<TObject>::id() != other.id())
359 {
360 if (m_ownerID == 0 && database_ptr<TObject>::m_objectID != 0)
361 {
362 m_ownerID = getParentIdFromId(database_ptr<TObject>::m_objectID);
363 }
364
365 // If we don't have an owner, we don't care about checking children
366 // We can completely copy other
367 if (m_ownerID == 0)
368 {
369 database_ptr<TObject>::m_objectID = other.id();
370 database_ptr<TObject>::m_objectPtr = other.weak();
371 database_ptr<TObject>::m_null = other.null();
372 m_ownerID = other.m_ownerID;
373 }
374 // If owner isn't trying to be changed, we can just check children and update the pointed to ID
375 else if (m_ownerID == other.m_ownerID || other.m_ownerID == 0)
376 {
377 // Do child check
378 if (objectIdIsChildOfParent(other.m_objectID, m_ownerID))
379 {
380 database_ptr<TObject>::m_objectID = other.id();
381 database_ptr<TObject>::m_objectPtr = other.weak();
382 database_ptr<TObject>::m_null = other.null();
383 }
384 }
385 // else: don't allow changing owner IDs once they're set
386 }
387
388 return *this;
389 }
390
391 void setID(typename database_ptr<TObject>::TIdentifierType id = 0)
392 {
393 // Fill our get_parent ID if we didn't have it already
394 if (m_ownerID == 0 && database_ptr<TObject>::m_objectID != 0)
395 {
396 m_ownerID = getParentIdFromId(database_ptr<TObject>::m_objectID);
397 }
398
399 if (id == 0)
400 {
401 database_ptr<TObject>::m_objectID = 0;
402 database_ptr<TObject>::m_objectPtr.reset();
403 database_ptr<TObject>::m_null = true;
404 }
405 else
406 {
407 if (m_ownerID == 0 || objectIdIsChildOfParent(id, m_ownerID))
408 {
409 database_ptr<TObject>::m_objectID = id;
410 database_ptr<TObject>::m_objectPtr.reset();
411 database_ptr<TObject>::m_null = true;
412 }
413 }
414 }
415
416 void reset(typename database_ptr<TObject>::TObjectPtr object = nullptr)
417 {
418 // Fill our get_parent ID if we didn't have it already
419 if (m_ownerID == 0 && database_ptr<TObject>::m_objectID != 0)
420 {
421 m_ownerID = getParentIdFromId(database_ptr<TObject>::m_objectID);
422 }
423
424 // Reset pointed to values but retain the owner ID
425 if (object == nullptr)
426 {
427 database_ptr<TObject>::m_objectID = 0;
428 database_ptr<TObject>::m_objectPtr.reset();
429 database_ptr<TObject>::m_null = true;
430 }
431 // Point to new object if it's a child of our owner
432 else
433 {
434 sbk_id newObjectID = static_cast<typename database_ptr<TObject>::TIdentifierType>(*object);
435
436 if (m_ownerID == 0 || objectIdIsChildOfParent(newObjectID, m_ownerID))
437 {
438 database_ptr<TObject>::m_objectID = newObjectID;
439 database_ptr<TObject>::m_objectPtr.reset();
440 database_ptr<TObject>::m_null = true;
441 }
442 }
443 }
444
445 private:
446 typename database_ptr<TObject>::TIdentifierType m_ownerID = 0;
447 };
448} // namespace sbk::core
449
450namespace std
451{
452 template <typename T>
453 struct hash<sbk::core::database_ptr<T>>
454 {
455 size_t operator()(const sbk::core::database_ptr<T>& k) const { return hash<sbk_id>{}(k.id()); }
456 };
457
458 template <typename T>
459 struct hash<sbk::core::child_ptr<T>>
460 {
461 size_t operator()(const sbk::core::child_ptr<T>& k) const { return hash<sbk_id>{}(k.id()); }
462 };
463} // namespace std
464
465#include <rttr/wrapper_mapper.h>
466
467namespace rttr
468{
469 template <typename T>
470 struct wrapper_mapper<sbk::core::child_ptr<T>>
471 {
472 using wrapped_type = decltype(sbk::core::child_ptr<T>(0).id());
474
475 inline static wrapped_type get(const type& obj) { return obj.id(); }
476
477 inline static type create(const wrapped_type& t) { return type(t); }
478
479 template <typename T2>
480 inline static sbk::core::child_ptr<T2> convert(const type& source, bool& ok)
481 {
482 sbk::core::child_ptr<T2> convertedLazyPtr(source.id());
483
484 ok = source.hasId() == convertedLazyPtr.hasId();
485
486 return convertedLazyPtr;
487 }
488 };
489
490 template <typename T>
491 struct wrapper_mapper<sbk::core::database_ptr<T>>
492 {
493 using wrapped_type = decltype(sbk::core::database_ptr<T>().id());
495
496 inline static wrapped_type get(const type& obj) { return obj.id(); }
497
498 inline static type create(const wrapped_type& t) { return type(t); }
499
500 template <typename T2>
501 inline static sbk::core::database_ptr<T2> convert(const type& source, bool& ok)
502 {
503 sbk::core::database_ptr<T2> convertedLazyPtr(source.id());
504
505 ok = source.hasId() == convertedLazyPtr.hasId();
506
507 return convertedLazyPtr;
508 }
509 };
510
511} // namespace rttr
Syntactic type to define a pointer that must be a child of the owning object.
Definition database_ptr.h:298
child_ptr(const database_object &owner)
Construct a new Child Ptr object with an owner.
Definition database_ptr.h:333
child_ptr(sbk_id id)
Construct a new child_ptr that points to the ID.
Definition database_ptr.h:340
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
TObjectPtr operator->() const
Access the raw object.
Definition database_ptr.h:238
database_ptr(std::nullptr_t)
Create an empty and null LazyPtr.
Definition database_ptr.h:75
database_ptr(sbk_id id)
Creates a LazyPtr that can lookup its object pointer after construction.
Definition database_ptr.h:49
bool pending() const
Returns true if we hold an ID but haven't found the live object to point to yet.
Definition database_ptr.h:132
bool operator!() const
Returns true if this LazyPtr is invalid.
Definition database_ptr.h:232
bool stale() const
Returns true if we previously referenced an object that has been destroyed.
Definition database_ptr.h:139
bool null() const
Returns true if the object pointer is not set.
Definition database_ptr.h:125
void reset(TObjectPtr object=nullptr)
Clear all references.
Definition database_ptr.h:166
TObjectPtr raw() const noexcept
Get raw pointer of the referenced object.
Definition database_ptr.h:106
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:191
database_ptr(const TObjectPtr &object)
Create a valid LazyPtr.
Definition database_ptr.h:66
sbk_id id() const noexcept
Get ID of the referenced object.
Definition database_ptr.h:84
bool hasId() const
Returns true if we hold a valid ID and can search for an object at runtime.
Definition database_ptr.h:119
bool valid() const
Returns true if we hold an ID and a valid pointer to the object.
Definition database_ptr.h:146
bool lookup() const
Find the live object referenced by the ID and store it.
Definition database_ptr.h:153
Base object that all sound Bakery objects should inherit from.
Definition object.h:21