Logo
ApraPipes 1.0
Loading...
Searching...
No Matches
ApraPool.h
1#pragma once
2
3#include<stddef.h>
4#include <functional> // std::greater
5#include <boost/pool/object_pool.hpp>
6
8{
9public:
10 ApraChunk() :ptr(nullptr), next(nullptr)
11 {
12
13 }
14
15 void set(void* _ptr, ApraChunk* _next)
16 {
17 ptr = _ptr;
18 next = _next;
19 }
20
21 void setNext(ApraChunk* _next)
22 {
23 next = _next;
24 }
25
26 void* get()
27 {
28 return ptr;
29 }
30
32 {
33 return next;
34 }
35
36private:
37 void* ptr;
39};
40
42{
43public:
45 virtual ~ApraSegregatedStorage();
46
47 void* malloc_n(const size_t n, const size_t partition_size);
48 void add_ordered_block(void* const block, const size_t nsz, const size_t npartition_sz);
49 void ordered_free_n(void* const chunks, const size_t n, const size_t partition_size);
50
51protected:
52 bool empty() const;
53
54//private:
55 ApraChunk* segregate(void* block, size_t sz, size_t partition_sz, ApraChunk* end = nullptr);
56 ApraChunk* find_prev(void * const ptr);
57 ApraChunk* try_malloc_n(ApraChunk*& start, size_t n, const size_t partition_size);
58
60 void addToJunk(ApraChunk* start, ApraChunk* end);
61 void releaseChunks();
62
64 ApraChunk* junkList; // used to store unused ApraChunks
65 boost::object_pool<ApraChunk> chunk_opool; // object pool takes c are of deleting the memory
66};
67
69{
70private:
71 char * ptr;
72 char* end_ptr;
73 size_t sz;
74
76
77public:
78 ApraNode(char * const nptr, const size_t nsize)
79 :ptr(nptr), sz(nsize), end_ptr(nptr + nsize), next(nullptr)
80 {
81 }
82
84 {
85 ptr = nullptr;
86 next = nullptr;
87 end_ptr = nullptr;
88 }
89
90 bool valid() const
91 {
92 return (begin() != 0);
93 }
95 {
96 begin() = 0;
97 }
98 char * & begin()
99 {
100 return ptr;
101 }
102 char * begin() const
103 {
104 return ptr;
105 }
106 char * end() const
107 {
108 return end_ptr;
109 }
110 size_t total_size() const
111 {
112 return sz;
113 }
114
116 {
117 return next;
118 }
119
120 void setNext(ApraNode* _next)
121 {
122 next = _next;
123 }
124};
125
126template <typename UserAllocator>
128{
129public:
130 explicit ApraPool(const size_t nRequestedSize, const size_t nnext_size = 32, const size_t nmax_size = 0);
131 virtual ~ApraPool();
132
133 void* ordered_malloc(const size_t n);
134 void ordered_free(void* ptr, const size_t n);
135
136 bool release_memory();
137 bool purge_memory();
138private:
139
140 bool is_from(void* const chunk, char* const start, char* const end);
141
143 {
144 return *this;
145 }
147 {
148 return *this;
149 }
150
151 const size_t requested_size;
153 size_t next_size;
154 size_t max_size;
155
157 boost::object_pool<ApraNode> node_opool;
158};
159
160template <typename UserAllocator>
161ApraPool<UserAllocator>::ApraPool(const size_t nRequestedSize, const size_t nnext_size, const size_t nmax_size) : requested_size(nRequestedSize), start_size(nnext_size), next_size(nnext_size), max_size(nmax_size), list(nullptr)
162{
163
164}
165
166template <typename UserAllocator>
168{
169 purge_memory();
170}
171
172template <typename UserAllocator>
174{
175 if (list == nullptr)
176 {
177 return false;
178 }
179
180 ApraNode* prev = nullptr;
181 while (list != nullptr)
182 {
183 // delete the storage
184 (UserAllocator::free)(list->begin());
185 prev = list;
186 list = list->getNext();
187 node_opool.destroy(prev);
188 }
189
190 this->releaseChunks();
191 next_size = start_size;
192
193 return true;
194}
195
196template <typename UserAllocator>
198{
199 bool ret = false;
200
201 ApraNode* ptr = list;
202 ApraNode* prev = nullptr;
203
204 ApraChunk* free_chunk = this->first;
205 ApraChunk* prev_free_chunk = nullptr;
206
207 while (ptr != nullptr)
208 {
209 ApraNode& node = *ptr;
210 if (free_chunk == nullptr)
211 {
212 break;
213 }
214
215 bool all_chunks_free = true;
216
217 ApraChunk* saved_free = free_chunk;
218 ApraChunk* last_free = nullptr;
219 for (char * i = node.begin(); i != node.end(); i += requested_size)
220 {
221 if (i != free_chunk->get())
222 {
223 all_chunks_free = false;
224
225 free_chunk = saved_free;
226 break;
227 }
228
229 if (i + requested_size == node.end())
230 {
231 // all chunks are free
232 last_free = free_chunk;
233 }
234
235 free_chunk = free_chunk->getNext();
236 }
237
238 ApraNode* next = ptr->getNext();
239
240 if (!all_chunks_free)
241 {
242 if (is_from(free_chunk->get(), node.begin(), node.end()))
243 {
244 std::less<void *> lt;
245 void* const end = node.end();
246 do
247 {
248 prev_free_chunk = free_chunk;
249 free_chunk = free_chunk->getNext();
250 } while (free_chunk && lt(free_chunk->get(), end));
251 }
252
253 prev = ptr;
254 }
255 else
256 {
257 // All chunks from this block are free
258 // Remove block from list
259 if (prev != nullptr)
260 {
261 prev->setNext(next);
262 }
263 else
264 {
265 list = next;
266 }
267
268 if (prev_free_chunk != nullptr)
269 {
270 prev_free_chunk->setNext(free_chunk);
271 }
272 else
273 {
274 this->first = free_chunk;
275 }
276 this->addToJunk(saved_free, last_free);
277
278 // And release memory
279 (UserAllocator::free)(node.begin());
280 node_opool.destroy(ptr);
281 ret = true;
282 }
283
284 ptr = next;
285 }
286
287 next_size = start_size;
288 return ret;
289}
290
291template <typename UserAllocator>
292bool ApraPool<UserAllocator>::is_from(void* const chunk, char* const start, char* const end)
293{
294 std::less_equal<void *> lt_eq;
295 std::less<void *> lt;
296 return (lt_eq(start, chunk) && lt(chunk, end));
297}
298
299template <typename UserAllocator>
300void* ApraPool<UserAllocator>::ordered_malloc(const size_t num_chunks)
301{
302 void * ret = store().malloc_n(num_chunks, requested_size);
303
304 if ((ret != 0) || (num_chunks == 0))
305 {
306 return ret;
307 }
308
309 // Not enough memory in our storages; make a new storage,
310 next_size = std::max(next_size, num_chunks);
311 size_t POD_size = next_size * requested_size;
312 char * ptr = (UserAllocator::malloc)(POD_size);
313 if (ptr == 0)
314 {
315 if (num_chunks < next_size)
316 {
317 // Try again with just enough memory to do the job, or at least whatever we
318 // allocated last time:
319 next_size >>= 1;
320 next_size = std::max(next_size, num_chunks);
321 POD_size = next_size * requested_size;
322 ptr = (UserAllocator::malloc)(POD_size);
323 }
324 if (ptr == nullptr)
325 {
326 return nullptr;
327 }
328 }
329
330 ApraNode* node = node_opool.construct(ptr, POD_size);
331
332 // Split up block so we can use what wasn't requested.
333 if (next_size > num_chunks)
334 {
335 store().add_ordered_block(node->begin() + num_chunks * requested_size, POD_size - num_chunks * requested_size, requested_size);
336 }
337
338 if (!max_size)
339 {
340 next_size <<= 1;
341 }
342 else if (next_size < max_size)
343 {
344 next_size = std::min(next_size << 1, max_size);
345 }
346
347 // insert it into the list,
348 // handle border case.
349 if (list == nullptr || std::greater<void *>()(list->begin(), node->begin()))
350 {
351 node->setNext(list);
352 list = node;
353 }
354 else
355 {
356 ApraNode* prev = list;
357
358 while (true)
359 {
360 // if we're about to hit the end, or if we've found where "node" goes.
361 if (prev->getNext() == nullptr || std::greater<void *>()(prev->getNext()->begin(), node->begin()))
362 {
363 break;
364 }
365
366 prev = prev->getNext();
367 }
368
369 node->setNext(prev->getNext());
370 prev->setNext(node);
371 }
372
373 // and return it.
374 return node->begin();
375}
376
377template <typename UserAllocator>
378void ApraPool<UserAllocator>::ordered_free(void* ptr, const size_t n)
379{
380 store().ordered_free_n(ptr, n, requested_size);
381}
Definition ApraPool.h:8
void set(void *_ptr, ApraChunk *_next)
Definition ApraPool.h:15
void setNext(ApraChunk *_next)
Definition ApraPool.h:21
void * get()
Definition ApraPool.h:26
ApraChunk * getNext()
Definition ApraPool.h:31
ApraChunk()
Definition ApraPool.h:10
ApraChunk * next
Definition ApraPool.h:38
void * ptr
Definition ApraPool.h:37
Definition ApraPool.h:69
char * ptr
Definition ApraPool.h:71
char * end() const
Definition ApraPool.h:106
void invalidate()
Definition ApraPool.h:94
size_t total_size() const
Definition ApraPool.h:110
char * end_ptr
Definition ApraPool.h:72
size_t sz
Definition ApraPool.h:73
~ApraNode()
Definition ApraPool.h:83
ApraNode * getNext()
Definition ApraPool.h:115
ApraNode * next
Definition ApraPool.h:75
bool valid() const
Definition ApraPool.h:90
char * begin() const
Definition ApraPool.h:102
ApraNode(char *const nptr, const size_t nsize)
Definition ApraPool.h:78
char *& begin()
Definition ApraPool.h:98
void setNext(ApraNode *_next)
Definition ApraPool.h:120
Definition ApraPool.h:128
bool purge_memory()
Definition ApraPool.h:173
const ApraSegregatedStorage & store() const
Definition ApraPool.h:146
void ordered_free(void *ptr, const size_t n)
Definition ApraPool.h:378
size_t next_size
Definition ApraPool.h:153
ApraPool(const size_t nRequestedSize, const size_t nnext_size=32, const size_t nmax_size=0)
Definition ApraPool.h:161
size_t max_size
Definition ApraPool.h:154
virtual ~ApraPool()
Definition ApraPool.h:167
boost::object_pool< ApraNode > node_opool
Definition ApraPool.h:157
const size_t requested_size
Definition ApraPool.h:151
ApraNode * list
Definition ApraPool.h:156
bool release_memory()
Definition ApraPool.h:197
bool is_from(void *const chunk, char *const start, char *const end)
Definition ApraPool.h:292
void * ordered_malloc(const size_t n)
Definition ApraPool.h:300
ApraSegregatedStorage & store()
Definition ApraPool.h:142
size_t start_size
Definition ApraPool.h:152
Definition ApraPool.h:42
boost::object_pool< ApraChunk > chunk_opool
Definition ApraPool.h:65
ApraSegregatedStorage()
Definition ApraPool.cpp:3
ApraChunk * try_malloc_n(ApraChunk *&start, size_t n, const size_t partition_size)
Definition ApraPool.cpp:117
ApraChunk * find_prev(void *const ptr)
Definition ApraPool.cpp:98
void * malloc_n(const size_t n, const size_t partition_size)
Definition ApraPool.cpp:133
void releaseChunks()
Definition ApraPool.cpp:13
ApraChunk * segregate(void *block, size_t sz, size_t partition_sz, ApraChunk *end=nullptr)
Definition ApraPool.cpp:67
void add_ordered_block(void *const block, const size_t nsz, const size_t npartition_sz)
Definition ApraPool.cpp:44
virtual ~ApraSegregatedStorage()
Definition ApraPool.cpp:8
void addToJunk(ApraChunk *start, ApraChunk *end)
Definition ApraPool.cpp:18
bool empty() const
Definition ApraPool.cpp:39
ApraChunk * first
Definition ApraPool.h:63
ApraChunk * getFreeApraChunk()
Definition ApraPool.cpp:24
ApraChunk * junkList
Definition ApraPool.h:64
void ordered_free_n(void *const chunks, const size_t n, const size_t partition_size)
Definition ApraPool.cpp:59