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.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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 0 && 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. if (n == 0) {
  17. return 0;
  18. }
  19. int num = 1;
  20. while ((n & 1) == 0) {
  21. n >>= 1;
  22. num += 1;
  23. }
  24. return num;
  25. }
  26. #endif
  27. static void expand_tables(struct l2_bitmap *bm) {
  28. while (bm->currtable >= bm->tableslen) {
  29. bm->tables = realloc(bm->tables, bm->tableslen * 2 * sizeof(*bm->tables));
  30. memset(bm->tables + bm->tableslen, 0, sizeof(*bm->tables) * bm->tableslen);
  31. bm->tableslen *= 2;
  32. }
  33. }
  34. void l2_bitmap_init(struct l2_bitmap *bm) {
  35. bm->tableslen = 4;
  36. bm->tables = calloc(bm->tableslen, sizeof(*bm->tables));
  37. bm->currtable = 0;
  38. bm->dirslen = 1;
  39. bm->dirs = calloc(bm->dirslen, sizeof(*bm->dirs));
  40. bm->currdir = 0;
  41. }
  42. void l2_bitmap_free(struct l2_bitmap *bm) {
  43. free(bm->tables);
  44. free(bm->dirs);
  45. }
  46. int l2_bitmap_get(struct l2_bitmap *bm, size_t id) {
  47. size_t tblidx = id / ENTSIZ;
  48. size_t tblbit = id % ENTSIZ;
  49. if (tblidx >= bm->tableslen) {
  50. return 0;
  51. }
  52. return !!(bm->tables[tblidx] & (l2_bitmap_entry)1 << tblbit);
  53. }
  54. size_t l2_bitmap_set_next(struct l2_bitmap *bm) {
  55. l2_bitmap_entry *table = &bm->tables[bm->currtable];
  56. l2_bitmap_entry bit = first_unset_bit(*table);
  57. *table |= bit;
  58. size_t ret = bm->currtable * ENTSIZ + first_set(bit) - 1;
  59. // Still free space?
  60. if (*table != ~(l2_bitmap_entry)0) {
  61. return ret;
  62. }
  63. // Ok, this entry is full then...
  64. l2_bitmap_entry *dir = &bm->dirs[bm->currdir];
  65. *dir |= (l2_bitmap_entry)1 << (bm->currtable % ENTSIZ);
  66. // Is there still space in this directory?
  67. if (*dir != ~(l2_bitmap_entry)0) {
  68. bm->currtable = bm->currdir * ENTSIZ + first_set(first_unset_bit(*dir)) - 1;
  69. expand_tables(bm);
  70. return ret;
  71. }
  72. // Is there a directory with free space?
  73. for (size_t i = 0; i < bm->dirslen; ++i) {
  74. dir = &bm->dirs[i];
  75. if (*dir == ~(l2_bitmap_entry)0) {
  76. continue;
  77. }
  78. bm->currdir = i;
  79. bm->currtable = bm->currdir * ENTSIZ + first_set(first_unset_bit(*dir)) - 1;
  80. expand_tables(bm);
  81. return ret;
  82. }
  83. // Ok, we gotta make a new dir then
  84. bm->currdir = bm->dirslen;
  85. bm->currtable = bm->currdir * ENTSIZ;
  86. bm->dirs = realloc(bm->dirs, bm->dirslen * 2 * sizeof(*bm->dirs));
  87. memset(bm->dirs + bm->dirslen, 0, sizeof(*bm->dirs) * bm->dirslen);
  88. bm->dirslen *= 2;
  89. expand_tables(bm);
  90. return ret;
  91. }
  92. void l2_bitmap_unset(struct l2_bitmap *bm, size_t id) {
  93. size_t tblidx = id / ENTSIZ;
  94. size_t tblbit = id % ENTSIZ;
  95. size_t diridx = id / (ENTSIZ * ENTSIZ);
  96. size_t dirbit = (id / ENTSIZ) % ENTSIZ;
  97. if (tblidx >= bm->tableslen) {
  98. return;
  99. }
  100. bm->tables[tblidx] &= ~((l2_bitmap_entry)1 << tblbit);
  101. bm->dirs[diridx] &= ~((l2_bitmap_entry)1 << dirbit);
  102. }