]> git.tdb.fi Git - libs/game.git/blob - source/game/owned.h
Add move constructor and assignment from Owned of derived type
[libs/game.git] / source / game / owned.h
1 #ifndef MSP_GAME_OWNED_H_
2 #define MSP_GAME_OWNED_H_
3
4 #include <stdexcept>
5 #include "accessguard.h"
6 #include "events.h"
7 #include "handle.h"
8 #include "stage.h"
9
10 namespace Msp::Game {
11
12 class Component;
13 class Entity;
14
15 template<typename T>
16 class Owned: public Handle<T>
17 {
18 public:
19         Owned() = default;
20
21         template<typename P, typename... Args>
22         Owned(Handle<P>, Args &&...);
23
24         template<typename P, typename... Args>
25         Owned(P *parent, Args &&... args): Owned(Handle<P>::from_object(parent), std::forward<Args>(args)...) { }
26
27         Owned(Owned &&other): Handle<T>(other) { other.ptr = nullptr; }
28
29         template<typename U>
30                 requires std::is_base_of_v<T, U>
31         Owned(Owned<U> &&other): Handle<T>(other) { other.ptr = nullptr; }
32
33         Owned &operator=(Owned &&other) { assign(std::move(other)); return *this; }
34
35         template<typename U>
36                 requires std::is_base_of_v<T, U>
37         Owned &operator=(Owned<U> &&other) { assign(std::move(other)); return *this; }
38
39         ~Owned() { destroy(); }
40
41 private:
42         template<typename U>
43         void assign(Owned<U> &&);
44
45         template<typename O>
46         static Stage &get_stage(O &);
47
48         void destroy();
49 };
50
51
52 template<typename T>
53 template<typename P, typename... Args>
54 Owned<T>::Owned(Handle<P> parent, Args &&... args)
55 {
56 #ifdef DEBUG
57         AccessGuard::get_instance().check<AccessGuard::Create>();
58 #endif
59
60         if(!parent)
61                 throw std::invalid_argument("Owned::Owned");
62
63         Stage &stage = get_stage(*parent);
64         Pool<T> &pool = stage.get_pools().get_pool<T>();
65         bool first_created = !pool.get_capacity();
66         this->ptr = pool.create(parent, std::forward<Args>(args)...);
67         if constexpr(std::is_base_of_v<Component, T>)
68         {
69                 if(first_created)
70                         stage.get_reflector().get_or_create_class<T>().template set_polymorphic_base<Component>(**this);
71                 parent->add_component(*this);
72                 stage.get_event_source().emit<Events::ComponentCreated>(*this);
73         }
74         else
75         {
76                 if(first_created)
77                         stage.get_reflector().get_or_create_class<T>().template set_polymorphic_base<Entity>(**this);
78                 parent->add_child(*this);
79                 stage.get_event_source().emit<Events::EntityCreated>(*this);
80         }
81 }
82
83 template<typename T>
84 template<typename U>
85 void Owned<T>::assign(Owned<U> &&other)
86 {
87         destroy();
88
89         this->ptr = other.ptr;
90         other.ptr = nullptr;
91 }
92
93 template<typename T>
94 template<typename O>
95 Stage &Owned<T>::get_stage(O &obj)
96 {
97         if constexpr(std::is_base_of_v<Component, O>)
98                 return get_stage(*obj.get_entity());
99         else
100                 return obj.get_stage();
101 }
102
103 template<typename T>
104 void Owned<T>::destroy()
105 {
106         T *obj = this->get();
107         if(!obj)
108                 return;
109
110 #ifdef DEBUG
111         AccessGuard::get_instance().check<AccessGuard::Destroy>();
112 #endif
113
114         Stage &stage = get_stage(*obj);
115
116         if constexpr(std::is_base_of_v<Component, T>)
117         {
118                 stage.get_event_source().emit<Events::ComponentDestroyed>(*this);
119                 obj->get_entity()->remove_component(*this);
120         }
121         else if(auto parent = obj->get_parent().get())
122         {
123                 stage.get_event_source().emit<Events::EntityDestroyed>(*this);
124                 parent->remove_child(*this);
125         }
126
127         Pool<T> &pool = stage.get_pools().get_pool<T>();
128         pool.destroy(this->ptr);
129 }
130
131 } // namespace Msp::Game
132
133 #endif