1#pragma once
2
3#include <Common/Arena.h>
4#include <common/likely.h>
5#include <ext/range.h>
6#include <ext/size.h>
7#include <ext/bit_cast.h>
8#include <cstdlib>
9#include <memory>
10
11
12namespace DB
13{
14
15
16/** Can allocate memory objects of fixed size with deletion support.
17 * For small `object_size`s allocated no less than getMinAllocationSize() bytes. */
18class SmallObjectPool
19{
20private:
21 struct Block { Block * next; };
22 static constexpr auto getMinAllocationSize() { return sizeof(Block); }
23
24 const size_t object_size;
25 Arena pool;
26 Block * free_list{};
27
28public:
29 SmallObjectPool(
30 const size_t object_size_, const size_t initial_size = 4096, const size_t growth_factor = 2,
31 const size_t linear_growth_threshold = 128 * 1024 * 1024)
32 : object_size{std::max(object_size_, getMinAllocationSize())},
33 pool{initial_size, growth_factor, linear_growth_threshold}
34 {
35 if (pool.size() < object_size)
36 return;
37
38 const auto num_objects = pool.size() / object_size;
39 auto head = free_list = ext::bit_cast<Block *>(pool.alloc(num_objects * object_size));
40
41 for (const auto i : ext::range(0, num_objects - 1))
42 {
43 (void) i;
44 head->next = ext::bit_cast<Block *>(ext::bit_cast<char *>(head) + object_size);
45 head = head->next;
46 }
47
48 head->next = nullptr;
49 }
50
51 char * alloc()
52 {
53 if (free_list)
54 {
55 const auto res = reinterpret_cast<char *>(free_list);
56 free_list = free_list->next;
57 return res;
58 }
59
60 return pool.alloc(object_size);
61 }
62
63 void free(const void * ptr)
64 {
65 union
66 {
67 const void * p_v;
68 Block * block;
69 };
70
71 p_v = ptr;
72 block->next = free_list;
73
74 free_list = block;
75 }
76
77 /// The size of the allocated pool in bytes
78 size_t size() const
79 {
80 return pool.size();
81 }
82
83};
84
85
86}
87