Simulant  21.12-194
A portable game engine for Windows, OSX, Linux, Dreamcast, and PSP
object_manager.h
1 #pragma once
2 
3 #include <chrono>
4 #include <unordered_map>
5 #include <unordered_set>
6 #include <memory>
7 
8 #include "default_init_ptr.h"
9 #include "unique_id.h"
10 
11 #include "../logging.h"
12 #include "../signals/signal.h"
13 #include "../macros.h"
14 
15 namespace smlt {
16 
17 const bool DONT_REFCOUNT = false;
18 const bool DO_REFCOUNT = true;
19 
20 namespace _object_manager_impl {
21 
22 /* All managers of the same type should share a counter */
23 template<typename T>
24 class IDCounter {
25 public:
26  static uint32_t next_id() {
27  static uint32_t id = 0;
28  return ++id;
29  }
30 };
31 
32 template<typename IDType, typename ObjectType, typename ObjectTypePtrType, typename SmartPointerConverter>
34 public:
36  typedef ObjectTypePtrType ObjectTypePtr;
37  typedef typename ObjectTypePtrType::element_type object_type;
38 
39  virtual void update() = 0;
40 
41  uint32_t count() const {
42  return objects_.size();
43  }
44 
45  /* Clones an object and returns an new ID to the clone */
46  ObjectTypePtrType clone(IDType id, this_type* target_manager=nullptr) {
47  if(!target_manager) {
48  target_manager = this;
49  }
50 
51  auto source = get(id);
52  auto copy = target_manager->make(&source->asset_manager());
53  *copy = *source;
54 
55  return copy;
56  }
57 
58  template<typename... Args>
59  ObjectTypePtrType make(Args&&... args) {
60  return make_as<ObjectType>(std::forward<Args>(args)...);
61  }
62 
63  template<typename T, typename... Args>
64  ObjectTypePtrType make_as(Args&&... args) {
65  IDType new_id(next_id()); // Unbound
66 
67  S_DEBUG("Creating a new object with ID: {0}", new_id);
68  auto obj = T::create(new_id, std::forward<Args>(args)...);
69 
70  S_DEBUG("Binding ID pointer");
71  obj->_bind_id_pointer(obj);
72 
73  objects_.insert(std::make_pair(obj->id(), obj));
74 
75  S_DEBUG("Calling on_make()");
76  on_make(obj->id());
77 
78  S_DEBUG("Created");
79  return SmartPointerConverter::convert(obj);
80  }
81 
82  void destroy(IDType id) {
83  on_destroy(id);
84  objects_.erase(id);
85  }
86 
87  void destroy_all() {
88  for(auto& p: objects_) {
89  on_destroy(p.first);
90  }
91 
92  objects_.clear();
93  }
94 
95  ObjectTypePtr get(IDType id) const {
96  auto it = objects_.find(id);
97  if(it == objects_.end()) {
98  return ObjectTypePtr();
99  }
100 
101  return SmartPointerConverter::convert(it->second);
102  }
103 
104  bool contains(IDType id) const {
105  return objects_.count(id) > 0;
106  }
107 
108  void each(std::function<void (uint32_t, ObjectTypePtr)> callback) {
109  uint32_t i = 0;
110  for(auto& p: objects_) {
111  auto ptr = p.second;
112  callback(i++, SmartPointerConverter::convert(ptr));
113  }
114  }
115 
116  void each(std::function<void (uint32_t, const ObjectTypePtr)> callback) const {
117  uint32_t i = 0;
118  for(auto& p: objects_) {
119  auto ptr = p.second;
120  callback(i++, SmartPointerConverter::convert(ptr));
121  }
122  }
123 
124  ObjectTypePtr find_object(const std::string& name) const {
125  for(auto& p: objects_) {
126  if(p.second->name() == name) {
127  return p.second;
128  }
129  }
130 
131  return ObjectTypePtr();
132  }
133 
134 protected:
135  uint32_t next_id() {
137  }
138 
139  typedef std::shared_ptr<ObjectType> ObjectTypeInternalPtrType;
140 
141  std::unordered_map<
142  IDType, ObjectTypeInternalPtrType
143  > objects_;
144 
145  sig::signal<void (ObjectType&, IDType)> signal_post_create_;
146  sig::signal<void (ObjectType&, IDType)> signal_pre_destroy_;
147 
148  virtual void on_make(IDType id) {
149  _S_UNUSED(id);
150  }
151 
152  virtual void on_get(IDType id) {
153  _S_UNUSED(id);
154  }
155 
156  virtual void on_destroy(IDType id) {
157  _S_UNUSED(id);
158  }
159 };
160 
161 
162 template<typename T>
163 struct ToSharedPtr {
164  static std::shared_ptr<T> convert(std::shared_ptr<T> ptr) {
165  return ptr;
166  }
167 };
168 
169 template<typename T>
171  static default_init_ptr<T> convert(std::shared_ptr<T> ptr) {
172  return ptr.get();
173  }
174 };
175 
176 
177 }
178 
179 template<typename IDType, typename ObjectType, bool RefCounted>
181 
182 template<typename IDType, typename ObjectType>
183 class ObjectManager<IDType, ObjectType, false>:
185  IDType, ObjectType, default_init_ptr<ObjectType>,
186  _object_manager_impl::ToDefaultInitPtr<ObjectType>
187  > {
188 
189 public:
192  > parent_class;
193 
195  typedef typename parent_class::object_type object_type;
196 
197  void update() override {}
198 };
199 
200 enum GarbageCollectMethod {
201  GARBAGE_COLLECT_NEVER,
202  GARBAGE_COLLECT_PERIODIC
203 };
204 
205 template<typename IDType, typename ObjectType>
206 class ObjectManager<IDType, ObjectType, true>:
208  IDType, ObjectType, std::shared_ptr<ObjectType>,
209  _object_manager_impl::ToSharedPtr<ObjectType>
210  > {
211 
212 public:
214  IDType, ObjectType, std::shared_ptr<ObjectType>, _object_manager_impl::ToSharedPtr<ObjectType>
215  > parent_class;
216 
217  typedef typename parent_class::ObjectTypePtr ObjectTypePtr;
218  typedef typename parent_class::object_type object_type;
219 
220  void update() override {
221  for(auto it = this->objects_.begin(); it != this->objects_.end();) {
222  ObjMeta meta = object_metas_.at(it->first);
223  bool collect = meta.collection_method == GARBAGE_COLLECT_PERIODIC;
224 
225  if(collect && it->second.unique()) {
226  // The user accessed this, and GC is enabled, and now there is only the
227  // single ref left
228  on_destroy(it->first);
229  it = this->objects_.erase(it);
230  } else {
231  ++it;
232  }
233  }
234  }
235 
236  void set_garbage_collection_method(IDType id, GarbageCollectMethod method) {
237  auto& meta = object_metas_.at(id);
238  meta.collection_method = method;
239  if(method != GARBAGE_COLLECT_NEVER) {
240  meta.created = std::chrono::system_clock::now();
241  }
242  }
243 
244 private:
245  typedef std::chrono::time_point<std::chrono::system_clock> date_time;
246 
247  struct ObjMeta {
248  ObjMeta():
249  created(std::chrono::system_clock::now()) {}
250 
251  GarbageCollectMethod collection_method = GARBAGE_COLLECT_PERIODIC;
252  date_time created;
253  };
254 
255  std::unordered_map<IDType, ObjMeta> object_metas_;
256 
257  void on_make(IDType id) override {
258  object_metas_.insert(std::make_pair(id, ObjMeta()));
259  }
260 
261  void on_destroy(IDType id) override {
262  S_DEBUG("Garbage collecting {0}", id);
263 
264  object_metas_.erase(id);
265  }
266 };
267 
268 
269 }
smlt::_object_manager_impl::ToDefaultInitPtr
Definition: object_manager.h:170
smlt::_object_manager_impl::ToSharedPtr
Definition: object_manager.h:163
smlt
Definition: animation.cpp:25
smlt::_object_manager_impl::IDCounter
Definition: object_manager.h:24
smlt::ObjectManager
Definition: object_manager.h:180
smlt::_object_manager_impl::ObjectManagerBase
Definition: object_manager.h:33
smlt::default_init_ptr
Definition: default_init_ptr.h:8
smlt::sig::signal
Definition: signal.h:319