You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bitmap.c 2.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. #include "bitmap.h"
  2. #include <string.h>
  3. #include <strings.h>
  4. #include <limits.h>
  5. #include <stdio.h>
  6. #define ENTSIZ (sizeof(l2_bitmap_entry) * CHAR_BIT)
  7. static l2_bitmap_entry first_unset_bit(l2_bitmap_entry n) {
  8. return ~n & (n + 1);
  9. }
  10. #if defined(__GLIBC__) && ( \
  11. (__GLIBC__>= 2 && __GLIBC_MINOR__ >= 27) || \
  12. _GNU_SOURCE)
  13. #define first_set ffsll
  14. #else
  15. static int first_set(l2_bitmap_entry n) {
  16. }
  17. #endif
  18. static void expand_tables(struct l2_bitmap *bm) {
  19. while (bm->currtable >= bm->tableslen) {
  20. bm->tables = realloc(bm->tables, bm->tableslen * 2 * sizeof(*bm->tables));
  21. memset(bm->tables + bm->tableslen, 0, sizeof(*bm->tables) * bm->tableslen);
  22. bm->tableslen *= 2;
  23. }
  24. }
  25. void l2_bitmap_init(struct l2_bitmap *bm) {
  26. bm->tableslen = 4;
  27. bm->tables = calloc(bm->tableslen, sizeof(*bm->tables));
  28. bm->currtable = 0;
  29. bm->dirslen = 1;
  30. bm->dirs = calloc(bm->dirslen, sizeof(*bm->dirs));
  31. bm->currdir = 0;
  32. }
  33. void l2_bitmap_free(struct l2_bitmap *bm) {
  34. free(bm->tables);
  35. free(bm->dirs);
  36. }
  37. int l2_bitmap_get(struct l2_bitmap *bm, size_t id) {
  38. size_t tblidx = id / ENTSIZ;
  39. size_t tblbit = id % ENTSIZ;
  40. if (tblidx >= bm->tableslen) {
  41. return 0;
  42. }
  43. return !!(bm->tables[tblidx] & (l2_bitmap_entry)1 << tblbit);
  44. }
  45. size_t l2_bitmap_set_next(struct l2_bitmap *bm) {
  46. l2_bitmap_entry *table = &bm->tables[bm->currtable];
  47. l2_bitmap_entry bit = first_unset_bit(*table);
  48. *table |= bit;
  49. size_t ret = bm->currtable * ENTSIZ + first_set(bit) - 1;
  50. // Still free space?
  51. if (*table != ~(l2_bitmap_entry)0) {
  52. return ret;
  53. }
  54. // Ok, this entry is full then...
  55. l2_bitmap_entry *dir = &bm->dirs[bm->currdir];
  56. *dir |= (l2_bitmap_entry)1 << (bm->currtable % ENTSIZ);
  57. // Is there still space in this directory?
  58. if (*dir != ~(l2_bitmap_entry)0) {
  59. bm->currtable = bm->currdir * ENTSIZ + first_set(first_unset_bit(*dir)) - 1;
  60. expand_tables(bm);
  61. return ret;
  62. }
  63. // Is there a directory with free space?
  64. for (size_t i = 0; i < bm->dirslen; ++i) {
  65. dir = &bm->dirs[i];
  66. if (*dir == ~(l2_bitmap_entry)0) {
  67. continue;
  68. }
  69. bm->currdir = i;
  70. bm->currtable = bm->currdir * ENTSIZ + first_set(first_unset_bit(*dir)) - 1;
  71. expand_tables(bm);
  72. return ret;
  73. }
  74. // Ok, we gotta make a new dir then
  75. bm->currdir = bm->dirslen;
  76. bm->currtable = bm->currdir * ENTSIZ;
  77. bm->dirs = realloc(bm->dirs, bm->dirslen * 2 * sizeof(*bm->dirs));
  78. memset(bm->dirs + bm->dirslen, 0, sizeof(*bm->dirs) * bm->dirslen);
  79. bm->dirslen *= 2;
  80. expand_tables(bm);
  81. return ret;
  82. }
  83. void l2_bitmap_unset(struct l2_bitmap *bm, size_t id) {
  84. size_t tblidx = id / ENTSIZ;
  85. size_t tblbit = id % ENTSIZ;
  86. size_t diridx = id / (ENTSIZ * ENTSIZ);
  87. size_t dirbit = (id / ENTSIZ) % ENTSIZ;
  88. if (tblidx >= bm->tableslen) {
  89. return;
  90. }
  91. bm->tables[tblidx] &= ~((l2_bitmap_entry)1 << tblbit);
  92. bm->dirs[diridx] &= ~((l2_bitmap_entry)1 << dirbit);
  93. }