]> git.tdb.fi Git - libs/game.git/blob - source/game/pool.h
Add reflection infrastructure
[libs/game.git] / source / game / pool.h
1 #ifndef MSP_GAME_POOL_H_
2 #define MSP_GAME_POOL_H_
3
4 #include <cstdint>
5 #include <memory>
6 #include <vector>
7 #include <msp/core/noncopyable.h>
8
9 namespace Msp::Game {
10
11 class PoolBase;
12
13 template<typename T>
14 class Pool;
15
16 class PoolPool: public NonCopyable
17 {
18 private:
19         std::vector<std::unique_ptr<PoolBase>> pools;
20
21 public:
22         PoolPool() = default;
23         PoolPool(PoolPool &&) = default;
24         PoolPool &operator=(PoolPool &&) = default;
25
26 private:
27         static unsigned get_next_id();
28
29 public:
30         template<typename T>
31         static unsigned get_type_id() { static unsigned id = get_next_id(); return id; }
32
33         template<typename T>
34         Pool<T> &get_pool();
35 };
36
37
38 class PoolBase: public NonCopyable
39 {
40 private:
41         using DeleteFunc = void(void *);
42         using FlagType = uint32_t;
43
44         static constexpr std::size_t BLOCK_SIZE = 512;
45         static constexpr std::size_t BLOCK_ALIGNMENT = 64;
46         static constexpr std::size_t FLAG_BITS = sizeof(FlagType)*8;
47
48         std::size_t object_size = 0;
49         char **blocks = nullptr;
50         std::uint32_t *free_list = nullptr;
51         std::uint32_t object_count = 0;
52         std::uint32_t capacity = 0;
53         DeleteFunc *deleter = nullptr;
54
55 protected:
56         PoolBase(std::uint32_t, DeleteFunc);
57 public:
58         PoolBase(PoolBase &&);
59         PoolBase &operator=(PoolBase &&);
60         ~PoolBase();
61
62 protected:
63         void destroy_all();
64
65         template<typename F>
66         void iterate_objects(const F &);
67
68         void *prepare_allocate();
69         void commit_allocate(void *);
70
71 private:
72         void add_block();
73
74 public:
75         std::uint32_t get_capacity() const { return capacity; }
76         void destroy(void *);
77 };
78
79
80 template<typename T>
81 class Pool: public PoolBase
82 {
83 public:
84         Pool(): PoolBase(sizeof(T), delete_object) { }
85
86         template<typename... Args>
87         T *create(Args &&...);
88
89         template<typename F>
90         void iterate_objects(const F &func)
91         { PoolBase::iterate_objects([&func](void *ptr){ func(*static_cast<T *>(ptr)); }); }
92
93 private:
94         static void delete_object(void *ptr) { std::destroy_at(static_cast<T *>(ptr)); }
95 };
96
97
98 template<typename T>
99 inline Pool<T> &PoolPool::get_pool()
100 {
101         unsigned id = get_type_id<T>();
102         if(pools.size()<=id)
103                 pools.resize(id+1);
104
105         std::unique_ptr<PoolBase> &ptr = pools[id];
106         if(!ptr)
107                 ptr = std::make_unique<Pool<T>>();
108
109         return *static_cast<Pool<T> *>(ptr.get());
110 }
111
112
113 template<typename F>
114 inline void PoolBase::iterate_objects(const F &func)
115 {
116         unsigned block_count = capacity/BLOCK_SIZE;
117         for(unsigned i=0; i<block_count; ++i)
118         {
119                 char *ptr = blocks[i];
120                 const FlagType *flags = reinterpret_cast<FlagType *>(ptr+BLOCK_SIZE*object_size);
121                 for(unsigned j=0; j<BLOCK_SIZE; j+=FLAG_BITS)
122                 {
123                         char *end = ptr+FLAG_BITS*object_size;
124                         if(FlagType f = *flags)
125                         {
126                                 if(!static_cast<FlagType>(~f))
127                                 {
128                                         for(; ptr!=end; ptr+=object_size)
129                                                 func(static_cast<void *>(ptr));
130                                 }
131                                 else
132                                 {
133                                         for(; ptr!=end; ptr+=object_size, f>>=1)
134                                                 if(f&1)
135                                                         func(static_cast<void *>(ptr));
136                                 }
137                         }
138                         else
139                                 ptr = end;
140                         ++flags;
141                 }
142         }
143 }
144
145
146 template<typename T>
147 template<typename... Args>
148 inline T *Pool<T>::create(Args &&... args)
149 {
150         void *ptr = prepare_allocate();
151         T *obj = std::construct_at(static_cast<T *>(ptr), std::forward<Args>(args)...);
152         commit_allocate(ptr);
153         return obj;
154 }
155
156 } // namespace Msp::Game
157
158 #endif