Joedb 10.4.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 > freedom_size
111 )
112 {
113 return false;
114 }
115
116 for (size_t i = 0; i < size; i++)
117 if (is_free_f(index + i))
118 return false;
119
120 return true;
121 }
122
123 bool is_dense() const {return freedom_size == used_count;}
124
125 //////////////////////////////////////////////////////////////////////////
127 {
128 Record_Id result = next_f(free_list);
129 if (result == free_list)
130 {
131 push_back();
132 result = next_f(free_list);
133 }
134 return result;
135 }
136
137 //////////////////////////////////////////////////////////////////////////
139 {
140 const Record_Id index = freedom_size;
142
143 is_free_f(index) = true;
144 next_f(index) = next_f(free_list);
145 previous_f(index) = free_list;
146
147 previous_f(next_f(free_list)) = index;
148 next_f(free_list) = index;
149
150 return index;
151 }
152
153 //////////////////////////////////////////////////////////////////////////
154 void resize(const Record_Id new_size)
155 {
156 while(get_size() < new_size)
157 push_back();
158 }
159
160 //////////////////////////////////////////////////////////////////////////
161 void use(const Record_Id index)
162 {
163 JOEDB_DEBUG_ASSERT(index >= Record_Id{0});
166
167 is_free_f(index) = false;
168
169 next_f(previous_f(index)) = next_f(index);
170 previous_f(next_f(index)) = previous_f(index);
171
173 next_f(index) = used_list;
174
175 next_f(previous_f(index)) = index;
176 previous_f(used_list) = index;
177
178 ++used_count;
179 }
180
181 //////////////////////////////////////////////////////////////////////////
182 void free(Record_Id index)
183 {
184 JOEDB_DEBUG_ASSERT(index >= Record_Id{0});
187
188 is_free_f(index) = true;
189
190 next_f(previous_f(index)) = next_f(index);
191 previous_f(next_f(index)) = previous_f(index);
192
193 next_f(index) = next_f(free_list);
194 previous_f(index) = free_list;
195
196 previous_f(next_f(free_list)) = index;
197 next_f(free_list) = index;
198
199 --used_count;
200 }
201
202 //////////////////////////////////////////////////////////////////////////
203 void use_vector(Record_Id index, size_t size)
204 {
205 for (size_t i = 0; i < size; ++i)
206 use(index + i);
207 }
208
209 //////////////////////////////////////////////////////////////////////////
210 void free_vector(Record_Id index, size_t size)
211 {
212 for (size_t i = 0; i < size; ++i)
213 free(index + i);
214 }
215 };
216
217 /// @ingroup joedb
219 {
220 private:
221 Record_Id used_size{0};
222 Record_Id free_size{0};
223
224 public:
225 Record_Id get_used_count() const {return used_size;}
226 Record_Id get_size() const {return free_size;}
227 size_t size() const {return size_t(free_size);}
228
230 {
231 if (used_size == free_size)
232 return free_list;
233 else
234 return used_size;
235 }
236
238 {
239 if (to_underlying(used_size) == 0)
240 return used_list;
241 else
242 return Record_Id{0};
243 }
244
246 {
247 if (index == used_list)
248 return get_first_used();
249
250 if (index == free_list)
251 return get_first_free();
252
253 const Record_Id result = index + 1;
254
255 if (result == used_size)
256 return used_list;
257
258 if (result == free_size)
259 return free_list;
260
261 return result;
262 }
263
265 {
266 if (index == used_list)
267 {
268 if (used_size == Record_Id{0})
269 return used_list;
270 else
271 return used_size - 1;
272 }
273
274 if (index == free_list)
275 {
276 if (used_size == free_size)
277 return free_list;
278 else
279 return free_size - 1;
280 }
281
282 const Record_Id result = index - 1;
283
284 if (result == Record_Id{-1})
285 return used_list;
286
287 if (result == used_size - 1)
288 return free_list;
289
290 return result;
291 }
292
293 bool is_used(Record_Id index) const
294 {
295 return index.is_not_null() && index < used_size;
296 }
297
298 bool is_free(Record_Id index) const
299 {
300 return index >= used_size;
301 }
302
303 bool is_free_vector(Record_Id index, size_t size) const
304 {
305 return index >= used_size;
306 }
307
308 bool is_used_vector(Record_Id index, size_t size) const
309 {
310 return
311 index.is_not_null() &&
312 index + size >= index &&
313 index + size <= used_size;
314 }
315
316 bool is_dense() const {return true;}
317
319 {
320 if (free_size == used_size)
321 ++free_size;
322 return used_size;
323 }
324
325 Record_Id push_back() {return ++free_size - 1;}
326
328 {
329 if (free_size < size)
330 free_size = size;
331 }
332
333 bool use(Record_Id index)
334 {
335 if (index == used_size && used_size < free_size)
336 {
337 ++used_size;
338 return true;
339 }
340 else
341 return false;
342 }
343
344 bool free(Record_Id index)
345 {
346 if (index == used_size - 1 && index >= Record_Id{0})
347 {
348 --used_size;
349 return true;
350 }
351 else
352 return false;
353 }
354
355 bool use_vector(Record_Id index, size_t size)
356 {
357 if (index == used_size && used_size + size <= free_size)
358 {
359 used_size = used_size + size;
360 return true;
361 }
362 else
363 return false;
364 }
365
366 bool free_vector(Record_Id index, size_t size)
367 {
368 if (index + size == used_size)
369 {
370 used_size = used_size - size;
371 return true;
372 }
373 else
374 return false;
375 }
376 };
377
378 /// @ingroup joedb
380 {
381 private:
384
385 bool dense = true;
386
387 void lose_compactness()
388 {
390
391 while (lfk.get_size() < dfk.get_size())
392 lfk.push_back();
393
394 for (Record_Id i{0}; i < dfk.get_used_count(); ++i)
395 lfk.use(i);
396
397 dense = false;
398 }
399
400 public:
401#define SWITCH(f) (dense ? dfk.f : lfk.f)
403 Record_Id get_size() const {return SWITCH(get_size());}
404 size_t size() const {return SWITCH(size());}
405
410
411 Record_Id get_next(Record_Id index) const {return SWITCH(get_next(index));}
412 Record_Id get_previous(Record_Id index) const {return SWITCH(get_previous(index));}
413 bool is_used(Record_Id index) const {return SWITCH(is_used(index));}
414 bool is_free(Record_Id index) const {return !is_used(index);}
415 bool is_dense() const {return dense;}
416
417 bool is_used_vector(Record_Id index, size_t size) const
418 {
419 return SWITCH(is_used_vector(index, size));
420 }
421
422 bool is_free_vector(Record_Id index, size_t size) const
423 {
424 return SWITCH(is_free_vector(index, size));
425 }
426
429 void resize(Record_Id new_size) {SWITCH(resize(new_size));}
430 void resize(size_t new_size) {resize(Record_Id(new_size));}
431#undef SWITCH
432
433 void use(Record_Id index)
434 {
435 if (dense)
436 {
437 if (!dfk.use(index))
438 {
439 lose_compactness();
440 lfk.use(index);
441 }
442 }
443 else
444 lfk.use(index);
445 }
446
447 void free(Record_Id index)
448 {
449 if (dense)
450 {
451 if (!dfk.free(index))
452 {
453 lose_compactness();
454 lfk.free(index);
455 }
456 }
457 else
458 lfk.free(index);
459 }
460
461 void use_vector(Record_Id index, size_t size)
462 {
463 if (dense)
464 {
465 if (!dfk.use_vector(index, size))
466 {
467 lose_compactness();
468 lfk.use_vector(index, size);
469 }
470 }
471 else
472 lfk.use_vector(index, size);
473 }
474
475 void free_vector(Record_Id index, size_t size)
476 {
477 if (dense)
478 {
479 if (!dfk.free_vector(index, size))
480 {
481 lose_compactness();
482 lfk.free_vector(index, size);
483 }
484 }
485 else
486 lfk.free_vector(index, size);
487 }
488 };
489}
490
491#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
constexpr index_t to_underlying(Record_Id id)
Definition index_types.h:59