MxEngine
AbstractFactory.h
1 // Copyright(c) 2019 - 2020, #Momo
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met :
6 //
7 // 1. Redistributions of source code must retain the above copyright notice, this
8 // list of conditions and the following disclaimer.
9 //
10 // 2. Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and /or other materials provided with the distribution.
13 //
14 // 3. Neither the name of the copyright holder nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #pragma once
30 
31 #include "Utilities/UUID/UUID.h"
32 #include "Utilities/VectorPool/VectorPool.h"
33 
34 namespace MxEngine
35 {
36  template<typename T>
38  {
39  UUID uuid;
40  T value;
41  size_t refCount = 0;
42 
43  template<typename... Args>
44  ManagedResource(UUID uuid, Args&&... value)
45  : value(std::forward<Args>(value)...), uuid(uuid)
46  {
47  }
48 
49  ManagedResource(const ManagedResource&) = delete;
50  ManagedResource(ManagedResource&&) noexcept(std::is_nothrow_move_constructible_v<T>) = default;
51  ManagedResource& operator=(const ManagedResource&) = delete;
52  ManagedResource& operator=(ManagedResource&&) noexcept(std::is_nothrow_move_assignable_v<T>) = default;
53 
54  ~ManagedResource()
55  {
56  uuid = UUIDGenerator::GetNull();
57  }
58  };
59 
60  template<typename T, typename Factory>
61  class Resource
62  {
63  UUID uuid;
64  size_t handle;
65 
66  #if defined(MXENGINE_DEBUG)
67  mutable ManagedResource<T>* _resourcePtr = nullptr;
68  #endif
69 
70  static constexpr size_t InvalidHandle = std::numeric_limits<size_t>::max();
71 
72  void IncRef()
73  {
74  if (this->IsValid())
75  ++this->Dereference().refCount;
76  }
77 
78  void DecRef()
79  {
80  if (this->IsValid())
81  {
82  auto& resource = this->Dereference();
83  if ((--resource.refCount) == 0)
84  DestroyThis(*this);
85  }
86  }
87 
88  [[nodiscard]] ManagedResource<T>& Dereference() const
89  {
90  auto& resource = AccessThis(this->handle);
91 
92  #if defined(MXENGINE_DEBUG)
93  this->_resourcePtr = &resource;
94  #endif
95 
96  return resource;
97  }
98 
99  void DestroyThis(Resource<T, Factory>& resource)
100  {
101  Factory::Destroy(resource);
102  }
103 
104  ManagedResource<T>& AccessThis(size_t handle) const
105  {
106  return Factory::template Get<T>()[handle];
107  }
108  public:
109  Resource()
110  : uuid(UUIDGenerator::GetNull()), handle(InvalidHandle)
111  {
112 
113  }
114 
115  Resource(UUID uuid, size_t handle)
116  : uuid(uuid), handle(handle)
117  {
118  this->IncRef();
119  }
120 
121  Resource(const Resource& wrapper)
122  : uuid(wrapper.uuid), handle(wrapper.handle)
123  {
124  this->IncRef();
125  #if defined(MXENGINE_DEBUG)
126  this->_resourcePtr = wrapper._resourcePtr;
127  #endif
128  }
129 
130  Resource& operator=(const Resource& wrapper)
131  {
132  this->DecRef();
133 
134  #if defined(MXENGINE_DEBUG)
135  this->_resourcePtr = wrapper._resourcePtr;
136  #endif
137 
138  this->uuid = wrapper.uuid;
139  this->handle = wrapper.handle;
140  this->IncRef();
141 
142  return *this;
143  }
144 
145  Resource(Resource&& wrapper) noexcept
146  : uuid(wrapper.uuid), handle(wrapper.handle)
147  {
148  #if defined(MXENGINE_DEBUG)
149  this->_resourcePtr = wrapper._resourcePtr;
150  #endif
151  wrapper.handle = InvalidHandle;
152  }
153 
154  Resource& operator=(Resource&& wrapper) noexcept
155  {
156  this->DecRef();
157  this->uuid = wrapper.uuid;
158  this->handle = wrapper.handle;
159  wrapper.handle = InvalidHandle;
160 
161  #if defined(MXENGINE_DEBUG)
162  this->_resourcePtr = wrapper._resourcePtr;
163  #endif
164  return *this;
165  }
166 
167  [[nodiscard]] bool IsValid() const
168  {
169  return handle != InvalidHandle && Dereference().uuid == uuid;
170  }
171 
172  void MakeStatic()
173  {
174  this->IncRef();
175  }
176 
177  T* operator->()
178  {
179  MX_ASSERT(this->IsValid());
180  if (!this->IsValid()) return nullptr;
181  return this->GetUnchecked();
182  }
183 
184  [[nodiscard]] const T* operator->() const
185  {
186  MX_ASSERT(this->IsValid());
187  if (!this->IsValid()) return nullptr;
188  return this->GetUnchecked();
189  }
190 
191  [[nodiscard]] T& operator*()
192  {
193  MX_ASSERT(this->IsValid());
194  return *this->GetUnchecked();
195  }
196 
197  [[nodiscard]] const T& operator*() const
198  {
199  MX_ASSERT(this->IsValid());
200  return *this->GetUnchecked();
201  }
202 
203  [[nodiscard]] T* GetUnchecked()
204  {
205  return &this->Dereference().value;
206  }
207 
208  [[nodiscard]] const T* GetUnchecked() const
209  {
210  return &this->Dereference().value;
211  }
212 
213  [[nodiscard]] auto GetHandle() const
214  {
215  return this->handle;
216  }
217 
218  [[nodiscard]] const auto& GetUUID() const
219  {
220  return this->uuid;
221  }
222 
223  [[nodiscard]] bool operator==(const Resource& wrapper) const
224  {
225  return this->handle == wrapper.handle && this->uuid == wrapper.uuid;
226  }
227 
228  [[nodiscard]] bool operator!=(const Resource& wrapper) const
229  {
230  return !(*this == wrapper);
231  }
232 
233  ~Resource()
234  {
235  this->DecRef();
236  }
237  };
238 
239  template<typename T, typename Factory>
241  {
242  UUID uuid;
243  size_t handle;
244  mutable Factory* factory;
245 
246  #if defined(MXENGINE_DEBUG)
247  mutable ManagedResource<T>* _resourcePtr = nullptr;
248  #endif
249 
250  static constexpr size_t InvalidHandle = std::numeric_limits<size_t>::max();
251 
252  void IncRef()
253  {
254  if (this->IsValid())
255  ++this->Dereference().refCount;
256  }
257 
258  void DecRef()
259  {
260  if (this->IsValid())
261  {
262  auto& resource = this->Dereference();
263  if ((--resource.refCount) == 0)
264  DestroyThis(*this);
265  }
266  }
267 
268  [[nodiscard]] ManagedResource<T>& Dereference() const
269  {
270  auto& resource = AccessThis(this->handle);
271 
272  #if defined(MXENGINE_DEBUG)
273  this->_resourcePtr = &resource;
274  #endif
275 
276  return resource;
277  }
278 
279  void DestroyThis(LocalResource<T, Factory>& resource)
280  {
281  this->factory->Destroy(resource);
282  }
283 
284  ManagedResource<T>& AccessThis(size_t handle) const
285  {
286  return this->factory->template Get<T>()[handle];
287  }
288  public:
289  LocalResource()
290  : uuid(UUIDGenerator::GetNull()), handle(InvalidHandle), factory(nullptr)
291  {
292 
293  }
294 
295  LocalResource(UUID uuid, size_t handle, Factory* factory)
296  : uuid(uuid), handle(handle), factory(factory)
297  {
298  this->IncRef();
299  }
300 
301  LocalResource(const LocalResource& wrapper)
302  : uuid(wrapper.uuid), handle(wrapper.handle), factory(wrapper.factory)
303  {
304  this->IncRef();
305  }
306 
307  LocalResource& operator=(const LocalResource& wrapper)
308  {
309  this->DecRef();
310 
311  this->uuid = wrapper.uuid;
312  this->handle = wrapper.handle;
313  this->factory = wrapper.factory;
314  this->IncRef();
315 
316  return *this;
317  }
318 
319  LocalResource(LocalResource&& wrapper) noexcept
320  : uuid(wrapper.uuid), handle(wrapper.handle), factory(wrapper.factory)
321  {
322  wrapper.handle = InvalidHandle;
323  }
324 
325  LocalResource& operator=(LocalResource&& wrapper) noexcept
326  {
327  this->DecRef();
328  this->uuid = wrapper.uuid;
329  this->handle = wrapper.handle;
330  this->factory = wrapper.factory;
331  wrapper.handle = InvalidHandle;
332 
333  return *this;
334  }
335 
336  [[nodiscard]] bool IsValid() const
337  {
338  return handle != InvalidHandle && Dereference().uuid == uuid;
339  }
340 
341  void MakeStatic()
342  {
343  this->IncRef();
344  }
345 
346  T* operator->()
347  {
348  MX_ASSERT(this->IsValid());
349  if (!this->IsValid()) return nullptr;
350  return this->GetUnchecked();
351  }
352 
353  [[nodiscard]] const T* operator->() const
354  {
355  MX_ASSERT(this->IsValid());
356  if (!this->IsValid()) return nullptr;
357  return this->GetUnchecked();
358  }
359 
360  [[nodiscard]] T& operator*()
361  {
362  MX_ASSERT(this->IsValid());
363  return *this->GetUnchecked();
364  }
365 
366  [[nodiscard]] const T& operator*() const
367  {
368  MX_ASSERT(this->IsValid());
369  return *this->GetUnchecked();
370  }
371 
372  [[nodiscard]] T* GetUnchecked()
373  {
374  return &this->Dereference().value;
375  }
376 
377  [[nodiscard]] const T* GetUnchecked() const
378  {
379  return &this->Dereference().value;
380  }
381 
382  [[nodiscard]] auto GetHandle() const
383  {
384  return this->handle;
385  }
386 
387  [[nodiscard]] const auto& GetUUID() const
388  {
389  return this->uuid;
390  }
391 
392  ~LocalResource()
393  {
394  this->DecRef();
395  }
396  };
397 
398  template<typename T, typename... Args>
399  struct FactoryImpl : FactoryImpl<Args...>
400  {
401  using Base = FactoryImpl<Args...>;
403  Pool pool;
404 
405  template<typename U>
406  auto& GetPool()
407  {
408  if constexpr (std::is_same<T, U>::value)
409  return this->pool;
410  else
411  return static_cast<Base*>(this)->template GetPool<U>();
412  }
413 
414  template<typename F>
415  void ForEach(F&& func)
416  {
417  func(this->pool);
418  static_cast<Base*>(this)->ForEach(std::forward<F>(func));
419  }
420  };
421 
422  template<typename T>
423  struct FactoryImpl<T>
424  {
426  FactoryPool Pool;
427 
428  template<typename U>
429  auto& GetPool()
430  {
431  static_assert(std::is_same<T, U>::value, "cannot find appropriate Factory<T>");
432  return this->Pool;
433  }
434 
435  template<typename F>
436  void ForEach(F&& func)
437  {
438  func(this->Pool);
439  }
440  };
441 
442  template<typename... Args>
444  {
445  public:
446  using Factory = FactoryImpl<Args...>;
447  using ThisType = AbstractFactoryImpl<Args...>;
448  private:
449  inline static Factory* factory = nullptr;
450  public:
451 
452  static Factory* GetImpl()
453  {
454  return factory;
455  }
456 
457  static void Init()
458  {
459  if (factory == nullptr)
460  factory = new Factory(); // not deleted, but its static member, so it does not matter
461  }
462 
463  static void Clone(Factory* other)
464  {
465  factory = other;
466  }
467 
468  template<typename U>
469  static auto& Get()
470  {
471  return factory->template GetPool<U>();
472  }
473 
474  template<typename T, typename... ConstructArgs>
475  static Resource<T, ThisType> Create(ConstructArgs&&... args)
476  {
477  MX_ASSERT(factory != nullptr);
478  UUID uuid = UUIDGenerator::Get();
479  auto& pool = factory->template GetPool<T>();
480  size_t index = pool.Allocate(uuid, std::forward<ConstructArgs>(args)...);
481  return Resource<T, ThisType>(uuid, index);
482  }
483 
484  template<typename T>
485  static void Destroy(Resource<T, ThisType>& resource)
486  {
487  factory->template GetPool<T>().Deallocate(resource.GetHandle());
488  }
489  };
490 }
Definition: AbstractFactory.h:61
Definition: VectorPool.h:42
Definition: AbstractFactory.h:443
Definition: UUID.h:45
Definition: AbstractFactory.h:399
Definition: AbstractFactory.h:240
Definition: AbstractFactory.h:37
Definition: Application.cpp:49