Joedb 10.0.1
The Journal-Only Embedded Database
Loading...
Searching...
No Matches
Freedom_Keeper.h
Go to the documentation of this file.
1#ifndef joedb_Freedom_Keeper_declared
2#define joedb_Freedom_Keeper_declared
3
4#include "joedb/index_types.h"
6
7#include <vector>
8
9namespace joedb
10{
12 {
13 public:
14 static constexpr Record_Id used_list{-2};
15 static constexpr Record_Id free_list{-1};
16 };
17
19 {
20 private:
21 std::vector<uint8_t> is_free_v;
22 std::vector<Record_Id> next_v;
23 std::vector<Record_Id> previous_v;
24
25 protected:
26 uint8_t *is_free_p;
29
30 uint8_t &is_free_f(Record_Id id) {return is_free_p[to_underlying(id)];}
33
34 uint8_t is_free_f(Record_Id id) const {return is_free_p[to_underlying(id)];}
37
39
41 {
42 this->freedom_size = size;
43
44 is_free_v.resize(to_underlying(size) + 2);
45 next_v.resize(to_underlying(size) + 2);
46 previous_v.resize(to_underlying(size) + 2);
47
48 is_free_p = is_free_v.data() + 2;
49 next_p = next_v.data() + 2;
50 previous_p = previous_v.data() + 2;
51 }
52
54 List_Data(const List_Data &) = delete;
55 List_Data &operator=(const List_Data &) = delete;
56 };
57
58 /// @ingroup joedb
60 {
61 private: //////////////////////////////////////////////////////////////////
62 Record_Id used_count;
63
64 public: ///////////////////////////////////////////////////////////////////
75
76 Record_Id get_used_count() const {return used_count;}
78 size_t size() const {return size_t(freedom_size);}
81 Record_Id get_next(const Record_Id index) const {return next_f(index);}
82 Record_Id get_previous(const Record_Id index) const {return previous_f(index);}
83 bool is_used(Record_Id index) const
84 {
85 return index.is_not_null() && index < freedom_size && !is_free_f(index);
86 }
87 bool is_free(Record_Id index) const {return !is_used(index);}
88
89 bool is_free_vector(Record_Id index, size_t size) const
90 {
91 if (index.is_null())
92 return false;
93
94 for (size_t i = 0; i < size; i++)
95 {
96 if (index + i >= freedom_size)
97 return true;
98 else if (!is_free_f(index + i))
99 return false;
100 }
101
102 return true;
103 }
104
105 bool is_used_vector(Record_Id index, size_t size) const
106 {
107 if
108 (
109 index.is_null() ||
110 index + size < index ||
111 index + size > freedom_size
112 )
113 {
114 return false;
115 }
116
117 for (size_t i = 0; i < size; i++)
118 if (is_free_f(index + i))
119 return false;
120
121 return true;
122 }
123
124 bool is_dense() const {return freedom_size == used_count;}
125
126 //////////////////////////////////////////////////////////////////////////
128 {
129 Record_Id result = next_f(free_list);
130 if (result == free_list)
131 {
132 push_back();
133 result = next_f(free_list);
134 }
135 return result;
136 }
137
138 //////////////////////////////////////////////////////////////////////////
140 {
141 const Record_Id index = freedom_size;
143
144 is_free_f(index) = true;
145 next_f(index) = next_f(free_list);
146 previous_f(index) = free_list;
147
148 previous_f(next_f(free_list)) = index;
149 next_f(free_list) = index;
150
151 return index;
152 }
153
154 //////////////////////////////////////////////////////////////////////////
155 void resize(const Record_Id new_size)
156 {
157 while(get_size() < new_size)
158 push_back();
159 }
160
161 //////////////////////////////////////////////////////////////////////////
162 void use(const Record_Id index)
163 {
164 JOEDB_DEBUG_ASSERT(index >= Record_Id{0});
167
168 is_free_f(index) = false;
169
170 next_f(previous_f(index)) = next_f(index);
171 previous_f(next_f(index)) = previous_f(index);
172
174 next_f(index) = used_list;
175
176 next_f(previous_f(index)) = index;
177 previous_f(used_list) = index;
178
179 ++used_count;
180 }
181
182 //////////////////////////////////////////////////////////////////////////
183 void free(Record_Id index)
184 {
185 JOEDB_DEBUG_ASSERT(index >= Record_Id{0});
188
189 is_free_f(index) = true;
190
191 next_f(previous_f(index)) = next_f(index);
192 previous_f(next_f(index)) = previous_f(index);
193
194 next_f(index) = next_f(free_list);
195 previous_f(index) = free_list;
196
197 previous_f(next_f(free_list)) = index;
198 next_f(free_list) = index;
199
200 --used_count;
201 }
202
203 //////////////////////////////////////////////////////////////////////////
204 void use_vector(Record_Id index, size_t size)
205 {
206 for (size_t i = 0; i < size; ++i)
207 use(index + i);
208 }
209
210 //////////////////////////////////////////////////////////////////////////
211 void free_vector(Record_Id index, size_t size)
212 {
213 for (size_t i = 0; i < size; ++i)
214 free(index + i);
215 }
216 };
217
218 /// @ingroup joedb
220 {
221 private:
222 Record_Id used_size{0};
223 Record_Id free_size{0};
224
225 public:
226 Record_Id get_used_count() const {return used_size;}
227 Record_Id get_size() const {return free_size;}
228 size_t size() const {return size_t(free_size);}
229
231 {
232 if (used_size == free_size)
233 return free_list;
234 else
235 return used_size;
236 }
237
239 {
240 if (to_underlying(used_size) == 0)
241 return used_list;
242 else
243 return Record_Id{0};
244 }
245
247 {
248 if (index == used_list)
249 return get_first_used();
250
251 if (index == free_list)
252 return get_first_free();
253
254 const Record_Id result = index + 1;
255
256 if (result == used_size)
257 return used_list;
258
259 if (result == free_size)
260 return free_list;
261
262 return result;
263 }
264
266 {
267 if (index == used_list)
268 {
269 if (used_size == Record_Id{0})
270 return used_list;
271 else
272 return used_size - 1;
273 }
274
275 if (index == free_list)
276 {
277 if (used_size == free_size)
278 return free_list;
279 else
280 return free_size - 1;
281 }
282
283 const Record_Id result = index - 1;
284
285 if (result == Record_Id{-1})
286 return used_list;
287
288 if (result == used_size - 1)
289 return free_list;
290
291 return result;
292 }
293
294 bool is_used(Record_Id index) const
295 {
296 return index.is_not_null() && index < used_size;
297 }
298
299 bool is_free(Record_Id index) const
300 {
301 return index >= used_size;
302 }
303
304 bool is_free_vector(Record_Id index, size_t size) const
305 {
306 return index >= used_size;
307 }
308
309 bool is_used_vector(Record_Id index, size_t size) const
310 {
311 return
312 index.is_not_null() &&
313 index + size >= index &&
314 index + size <= used_size;
315 }
316
317 bool is_dense() const {return true;}
318
320 {
321 if (free_size == used_size)
322 ++free_size;
323 return used_size;
324 }
325
326 Record_Id push_back() {return ++free_size - 1;}
327
329 {
330 if (free_size < size)
331 free_size = size;
332 }
333
334 bool use(Record_Id index)
335 {
336 if (index == used_size && used_size < free_size)
337 {
338 ++used_size;
339 return true;
340 }
341 else
342 return false;
343 }
344
345 bool free(Record_Id index)
346 {
347 if (index == used_size - 1 && index >= Record_Id{0})
348 {
349 --used_size;
350 return true;
351 }
352 else
353 return false;
354 }
355
356 bool use_vector(Record_Id index, size_t size)
357 {
358 if (index == used_size && used_size + size <= free_size)
359 {
360 used_size = used_size + size;
361 return true;
362 }
363 else
364 return false;
365 }
366
367 bool free_vector(Record_Id index, size_t size)
368 {
369 if (index + size == used_size)
370 {
371 used_size = used_size - size;
372 return true;
373 }
374 else
375 return false;
376 }
377 };
378
379 /// @ingroup joedb
381 {
382 private:
385
386 bool dense = true;
387
388 void lose_compactness()
389 {
391
392 while (lfk.get_size() < dfk.get_size())
393 lfk.push_back();
394
395 for (Record_Id i{0}; i < dfk.get_used_count(); ++i)
396 lfk.use(i);
397
398 dense = false;
399 }
400
401 public:
402#define SWITCH(f) (dense ? dfk.f : lfk.f)
404 Record_Id get_size() const {return SWITCH(get_size());}
405 size_t size() const {return SWITCH(size());}
406
411
412 Record_Id get_next(Record_Id index) const {return SWITCH(get_next(index));}
413 Record_Id get_previous(Record_Id index) const {return SWITCH(get_previous(index));}
414 bool is_used(Record_Id index) const {return SWITCH(is_used(index));}
415 bool is_free(Record_Id index) const {return !is_used(index);}
416 bool is_dense() const {return dense;}
417
418 bool is_used_vector(Record_Id index, size_t size) const
419 {
420 return SWITCH(is_used_vector(index, size));
421 }
422
423 bool is_free_vector(Record_Id index, size_t size) const
424 {
425 return SWITCH(is_free_vector(index, size));
426 }
427
430 void resize(Record_Id new_size) {SWITCH(resize(new_size));}
431 void resize(size_t new_size) {resize(Record_Id(new_size));}
432#undef SWITCH
433
434 void use(Record_Id index)
435 {
436 if (dense)
437 {
438 if (!dfk.use(index))
439 {
440 lose_compactness();
441 lfk.use(index);
442 }
443 }
444 else
445 lfk.use(index);
446 }
447
448 void free(Record_Id index)
449 {
450 if (dense)
451 {
452 if (!dfk.free(index))
453 {
454 lose_compactness();
455 lfk.free(index);
456 }
457 }
458 else
459 lfk.free(index);
460 }
461
462 void use_vector(Record_Id index, size_t size)
463 {
464 if (dense)
465 {
466 if (!dfk.use_vector(index, size))
467 {
468 lose_compactness();
469 lfk.use_vector(index, size);
470 }
471 }
472 else
473 lfk.use_vector(index, size);
474 }
475
476 void free_vector(Record_Id index, size_t size)
477 {
478 if (dense)
479 {
480 if (!dfk.free_vector(index, size))
481 {
482 lose_compactness();
483 lfk.free_vector(index, size);
484 }
485 }
486 else
487 lfk.free_vector(index, size);
488 }
489 };
490}
491
492#endif
#define SWITCH(f)
Record_Id get_previous(Record_Id index) const
Record_Id get_first_used() const
Record_Id get_next(Record_Id index) const
bool is_used(Record_Id index) const
bool is_free(Record_Id index) const
Record_Id get_first_free() const
bool is_used_vector(Record_Id index, size_t size) const
bool use(Record_Id index)
bool free_vector(Record_Id index, size_t size)
bool use_vector(Record_Id index, size_t size)
Record_Id get_used_count() const
bool free(Record_Id index)
bool is_free_vector(Record_Id index, size_t size) const
void resize(Record_Id size)
static constexpr Record_Id free_list
static constexpr Record_Id used_list
Record_Id get_last_used() const
void resize(size_t new_size)
Record_Id get_size() const
Record_Id get_first_free() const
void use(Record_Id index)
bool is_free_vector(Record_Id index, size_t size) const
void free_vector(Record_Id index, size_t size)
Record_Id get_last_free() const
void use_vector(Record_Id index, size_t size)
bool is_used_vector(Record_Id index, size_t size) const
bool is_used(Record_Id index) const
bool is_free(Record_Id index) const
void resize(Record_Id new_size)
Record_Id get_previous(Record_Id index) const
Record_Id get_next(Record_Id index) const
Record_Id get_used_count() const
void free(Record_Id index)
Record_Id get_first_used() const
Record_Id next_f(Record_Id id) const
uint8_t is_free_f(Record_Id id) const
void resize_vector(Record_Id size)
List_Data(const List_Data &)=delete
Record_Id * next_p
Record_Id freedom_size
Record_Id & previous_f(Record_Id id)
Record_Id & next_f(Record_Id id)
uint8_t & is_free_f(Record_Id id)
Record_Id previous_f(Record_Id id) const
Record_Id * previous_p
List_Data & operator=(const List_Data &)=delete
Record_Id get_size() const
bool is_used_vector(Record_Id index, size_t size) const
Record_Id get_previous(const Record_Id index) const
bool is_used(Record_Id index) const
void free_vector(Record_Id index, size_t size)
Record_Id get_used_count() const
Record_Id get_first_used() const
bool is_free(Record_Id index) const
Record_Id get_next(const Record_Id index) const
Record_Id get_first_free() const
bool is_free_vector(Record_Id index, size_t size) const
void resize(const Record_Id new_size)
void free(Record_Id index)
void use_vector(Record_Id index, size_t size)
void use(const Record_Id index)
constexpr bool is_null() const
Definition index_types.h:41
constexpr bool is_not_null() const
Definition index_types.h:42
#define JOEDB_DEBUG_ASSERT(x)
assertion tested in debug mode
Definition assert.h:19
#define JOEDB_RELEASE_ASSERT(x)
always-tested assertion (release and debug mode)
Definition assert.h:24
Definition Blob.h:7
constexpr index_t to_underlying(Record_Id id)
Definition index_types.h:59