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.

bitset.c 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. #include "bitset.h"
  2. #include <string.h>
  3. #include <strings.h>
  4. #include <limits.h>
  5. #include <stdio.h>
  6. #define ENTSIZ (sizeof(l2_bitset_entry) * CHAR_BIT)
  7. static l2_bitset_entry first_unset_bit(l2_bitset_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_bitset_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_bitset *bs) {
  28. while (bs->currtable >= bs->tableslen) {
  29. bs->tables = realloc(bs->tables, bs->tableslen * 2 * sizeof(*bs->tables));
  30. memset(bs->tables + bs->tableslen, 0, sizeof(*bs->tables) * bs->tableslen);
  31. bs->tableslen *= 2;
  32. }
  33. }
  34. void l2_bitset_init(struct l2_bitset *bs) {
  35. bs->tableslen = 4;
  36. bs->tables = calloc(bs->tableslen, sizeof(*bs->tables));
  37. bs->currtable = 0;
  38. bs->dirslen = 1;
  39. bs->dirs = calloc(bs->dirslen, sizeof(*bs->dirs));
  40. bs->currdir = 0;
  41. }
  42. void l2_bitset_free(struct l2_bitset *bs) {
  43. free(bs->tables);
  44. free(bs->dirs);
  45. }
  46. int l2_bitset_get(struct l2_bitset *bs, size_t id) {
  47. size_t tblidx = id / ENTSIZ;
  48. size_t tblbit = id % ENTSIZ;
  49. if (tblidx >= bs->tableslen) {
  50. return 0;
  51. }
  52. return !!(bs->tables[tblidx] & (l2_bitset_entry)1 << tblbit);
  53. }
  54. size_t l2_bitset_set_next(struct l2_bitset *bs) {
  55. l2_bitset_entry *table = &bs->tables[bs->currtable];
  56. l2_bitset_entry bit = first_unset_bit(*table);
  57. *table |= bit;
  58. size_t ret = bs->currtable * ENTSIZ + first_set(bit) - 1;
  59. // Still free space?
  60. if (*table != ~(l2_bitset_entry)0) {
  61. return ret;
  62. }
  63. // Ok, this table is full then...
  64. l2_bitset_entry *dir = &bs->dirs[bs->currdir];
  65. *dir |= (l2_bitset_entry)1 << (bs->currtable % ENTSIZ);
  66. // Is there still space in this directory?
  67. if (*dir != ~(l2_bitset_entry)0) {
  68. bs->currtable = bs->currdir * ENTSIZ + first_set(first_unset_bit(*dir)) - 1;
  69. expand_tables(bs);
  70. return ret;
  71. }
  72. // Is there a directory with free space?
  73. for (size_t i = 0; i < bs->dirslen; ++i) {
  74. dir = &bs->dirs[i];
  75. if (*dir == ~(l2_bitset_entry)0) {
  76. continue;
  77. }
  78. bs->currdir = i;
  79. bs->currtable = bs->currdir * ENTSIZ + first_set(first_unset_bit(*dir)) - 1;
  80. expand_tables(bs);
  81. return ret;
  82. }
  83. // Ok, we gotta make a new dir then
  84. bs->currdir = bs->dirslen;
  85. bs->currtable = bs->currdir * ENTSIZ;
  86. bs->dirs = realloc(bs->dirs, bs->dirslen * 2 * sizeof(*bs->dirs));
  87. memset(bs->dirs + bs->dirslen, 0, sizeof(*bs->dirs) * bs->dirslen);
  88. bs->dirslen *= 2;
  89. expand_tables(bs);
  90. return ret;
  91. }
  92. void l2_bitset_unset(struct l2_bitset *bs, 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 >= bs->tableslen) {
  98. return;
  99. }
  100. bs->tables[tblidx] &= ~((l2_bitset_entry)1 << tblbit);
  101. bs->dirs[diridx] &= ~((l2_bitset_entry)1 << dirbit);
  102. }