]> git.tdb.fi Git - libs/game.git/commitdiff
Keep track of object pools for derived types
authorMikko Rasa <tdb@tdb.fi>
Sun, 7 May 2023 15:07:41 +0000 (18:07 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sun, 7 May 2023 15:07:41 +0000 (18:07 +0300)
source/game/pool.cpp
source/game/pool.h
source/game/reflection.h
source/game/stage.cpp

index 869c571bb74949a70e3684b1936d0c19f187d481..174a939b9a8c1da16a25a757f9f4ef2525d91b7c 100644 (file)
@@ -1,5 +1,6 @@
 #include "pool.h"
 #include <stdexcept>
+#include <msp/core/except.h>
 #include <msp/io/print.h>
 
 using namespace std;
@@ -12,10 +13,43 @@ unsigned PoolPool::get_next_id()
        return next_id++;
 }
 
+void PoolPool::check_types()
+{
+       unsigned g = reflector.get_generation();
+       if(g==reflector_gen)
+               return;
+
+       for(const auto &p: pools)
+       {
+               const Reflection::ClassBase *type = &p->get_reflected_type();
+               PoolBase *parent = nullptr;
+               while(!parent && type)
+               {
+                       const vector<const Reflection::ClassBase *> &bases = type->get_direct_bases();
+                       if(bases.size()>1)
+                               throw unsupported("Multiple bases in pools are not supported");
+
+                       type = (bases.empty() ? nullptr : bases.front());
+                       if(type)
+                       {
+                               auto i = ranges::find_if(pools, [type](const auto &o){ return &o->get_reflected_type()==type; });
+                               if(i!=pools.end())
+                                       parent = i->get();
+                       }
+               }
+
+               if(parent)
+                       p->set_parent_pool(*parent);
+       }
+
+       reflector_gen = g;
+}
 
-PoolBase::PoolBase(uint32_t s, DeleteFunc d):
+
+PoolBase::PoolBase(const Reflection::ClassBase &t, uint32_t s, DeleteFunc d):
        object_size(s),
-       deleter(d)
+       deleter(d),
+       reflected_type(t)
 { }
 
 PoolBase::~PoolBase()
@@ -23,6 +57,22 @@ PoolBase::~PoolBase()
        destroy_all();
 }
 
+void PoolBase::set_parent_pool(PoolBase &p)
+{
+       if(!p.reflected_type.is_direct_base_of(reflected_type))
+               throw invalid_argument("PoolBase::set_parent_pool");
+
+       if(parent_pool)
+       {
+               auto i = ranges::find(parent_pool->derived_pools, this);
+               if(i!=parent_pool->derived_pools.end())
+                       parent_pool->derived_pools.erase(i);
+       }
+
+       parent_pool = &p;
+       parent_pool->derived_pools.push_back(this);
+}
+
 void PoolBase::destroy_all()
 {
        if(object_count>0)
index fd383fc06040494d39cf060c57e5cc1a847068c9..dde179defd3ebbad07bd1a3f17a2debe6827ecc3 100644 (file)
@@ -6,6 +6,7 @@
 #include <vector>
 #include <msp/core/noncopyable.h>
 #include "mspgame_api.h"
+#include "reflection.h"
 
 namespace Msp::Game {
 
@@ -17,16 +18,20 @@ class Pool;
 class MSPGAME_API PoolPool: public NonCopyable
 {
 private:
+       Reflection::Reflector &reflector;
        std::vector<std::unique_ptr<PoolBase>> pools;
+       unsigned reflector_gen = 0;
 
 public:
-       PoolPool() = default;
+       PoolPool(Reflection::Reflector &r): reflector(r) { }
        PoolPool(PoolPool &&) = default;
        PoolPool &operator=(PoolPool &&) = default;
 
 private:
        static unsigned get_next_id();
 
+       void check_types();
+
 public:
        template<typename T>
        static unsigned get_type_id() { static unsigned id = get_next_id(); return id; }
@@ -53,11 +58,18 @@ private:
        std::uint32_t capacity = 0;
        DeleteFunc *deleter = nullptr;
 
+       const Reflection::ClassBase &reflected_type;
+       PoolBase *parent_pool = nullptr;
+       std::vector<PoolBase *> derived_pools;
+
 protected:
-       PoolBase(std::uint32_t, DeleteFunc);
+       PoolBase(const Reflection::ClassBase &, std::uint32_t, DeleteFunc);
 public:
        virtual ~PoolBase();
 
+       const Reflection::ClassBase &get_reflected_type() const { return reflected_type; }
+       void set_parent_pool(PoolBase &);
+
 protected:
        void destroy_all();
 
@@ -80,7 +92,7 @@ template<typename T>
 class Pool: public PoolBase
 {
 public:
-       Pool(): PoolBase(sizeof(T), delete_object) { }
+       Pool(Reflection::Reflector &r): PoolBase(r.get_or_create_class<T>(), sizeof(T), delete_object) { }
 
        template<typename... Args>
        T *create(Args &&...);
@@ -103,7 +115,9 @@ inline Pool<T> &PoolPool::get_pool()
 
        std::unique_ptr<PoolBase> &ptr = pools[id];
        if(!ptr)
-               ptr = std::make_unique<Pool<T>>();
+               ptr = std::make_unique<Pool<T>>(reflector);
+
+       check_types();
 
        return *static_cast<Pool<T> *>(ptr.get());
 }
index d42c86040d37e84fc70cee4706c22e4745636f82..bfd4aeb1f6745b3827c33cede98ae844de1820b8 100644 (file)
@@ -57,6 +57,7 @@ public:
        const std::type_index &get_type() const { return type; }
        const std::string &get_name() const { return name; }
 
+       const std::vector<const ClassBase *> &get_direct_bases() const { return bases; }
        bool is_direct_base_of(const ClassBase &) const;
        bool is_base_of(const ClassBase &) const;
 
index 3888410a43c8bc976034b753693b56ab35f16d72..3a2f5cda9d243c294ce455e28a11a405087ac87b 100644 (file)
@@ -13,6 +13,7 @@ namespace Msp::Game {
 Stage::Stage(Reflection::Reflector &f, DataFile::Collection &r):
        reflector(f),
        resources(r),
+       pools(reflector),
        event_source(event_bus),
        event_observer(event_bus),
        root(std::make_unique<Root>(*this)),