3 #include <msp/io/print.h>
9 unsigned PoolPool::get_next_id()
11 static unsigned next_id = 0;
16 PoolBase::PoolBase(uint32_t s, DeleteFunc d):
21 PoolBase::PoolBase(PoolBase &&other):
22 object_size(other.object_size),
24 free_list(other.free_list),
25 object_count(other.object_count),
26 capacity(other.capacity),
27 deleter(other.deleter)
29 other.blocks = nullptr;
30 other.free_list = nullptr;
31 other.object_count = 0;
35 PoolBase &PoolBase::operator=(PoolBase &&other)
39 object_size = other.object_size;
40 blocks = other.blocks;
41 free_list = other.free_list;
42 object_count = other.object_count;
43 capacity = other.capacity;
44 deleter = other.deleter;
46 other.blocks = nullptr;
47 other.free_list = nullptr;
48 other.object_count = 0;
59 void PoolBase::destroy_all()
62 IO::print(IO::cerr, "Warning: pool is being destroyed but has %d live objects", object_count);
64 unsigned block_count = capacity/BLOCK_SIZE;
65 for(unsigned i=0; i<block_count; ++i)
67 delete[] reinterpret_cast<char *>(blocks);
70 void *PoolBase::prepare_allocate()
72 if(object_count>=capacity)
75 uint32_t full_index = free_list[object_count];
76 unsigned block_index = full_index/BLOCK_SIZE;
77 unsigned object_index = full_index%BLOCK_SIZE;
78 return blocks[block_index]+object_index*object_size;
81 void PoolBase::commit_allocate(void *ptr)
83 uint32_t full_index = free_list[object_count];
84 unsigned block_index = full_index/BLOCK_SIZE;
85 unsigned object_index = full_index%BLOCK_SIZE;
86 void *expected = blocks[block_index]+object_index*object_size;
88 throw logic_error("PoolBase::commit_allocate does not match prepare_allocate");
90 FlagType *flags = reinterpret_cast<FlagType *>(blocks[block_index]+BLOCK_SIZE*object_size);
91 FlagType bit = 1<<(object_index%FLAG_BITS);
92 if(flags[object_index/FLAG_BITS]&bit)
93 throw logic_error("PoolBase::commit_allocate to a not-free index");
95 flags[object_index/FLAG_BITS] |= bit;
99 void PoolBase::add_block()
101 unsigned block_count = capacity/BLOCK_SIZE;
102 char *new_mem = new alignas(char *) char[(block_count+1)*(sizeof(char *)+BLOCK_SIZE*sizeof(uint32_t))];
103 char **new_blocks = reinterpret_cast<char **>(new_mem);
104 uint32_t *new_free = reinterpret_cast<uint32_t *>(new_mem+(block_count+1)*sizeof(char *));
106 copy(blocks, blocks+block_count, new_blocks);
107 copy(free_list, free_list+capacity, new_free);
109 char *block = new alignas(BLOCK_ALIGNMENT) char[BLOCK_SIZE*object_size+BLOCK_SIZE/8];
110 new_blocks[block_count] = block;
111 FlagType *flags = reinterpret_cast<FlagType *>(block+BLOCK_SIZE*object_size);
112 for(unsigned i=0; i<BLOCK_SIZE; ++i)
113 new_free[capacity+i] = capacity+i;
114 for(unsigned i=0; i<BLOCK_SIZE/FLAG_BITS; ++i)
117 delete[] reinterpret_cast<char *>(blocks);
119 free_list = new_free;
120 capacity += BLOCK_SIZE;
123 void PoolBase::destroy(void *obj)
125 unsigned block_index = 0;
126 unsigned object_index = BLOCK_SIZE;
127 intptr_t addr = reinterpret_cast<intptr_t>(obj);
128 unsigned block_count = capacity/BLOCK_SIZE;
129 while(block_index<block_count)
131 intptr_t mem = reinterpret_cast<intptr_t>(blocks[block_index]);
132 intptr_t mem_end = mem+BLOCK_SIZE*object_size;
133 if(addr>=mem && addr<mem_end)
135 object_index = (addr-mem)/object_size;
141 if(object_index>=BLOCK_SIZE)
142 throw invalid_argument("PoolBase::destroy");
144 FlagType *flags = reinterpret_cast<FlagType *>(blocks[block_index]+BLOCK_SIZE*object_size);
145 FlagType bit = 1<<(object_index%FLAG_BITS);
146 if(!(flags[object_index/FLAG_BITS]&bit))
147 throw invalid_argument("PoolBase::destroy");
150 flags[object_index/FLAG_BITS] &= ~bit;
152 free_list[object_count] = block_index*BLOCK_SIZE+object_index;
155 } // namespace Msp::Game