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