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 | |
12 | namespace 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. */ |
18 | class SmallObjectPool |
19 | { |
20 | private: |
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 | |
28 | public: |
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 |