bitmap.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /* $OpenBSD: bitmap.c,v 1.9 2017/10/20 01:56:39 djm Exp $ */
  2. /*
  3. * Copyright (c) 2015 Damien Miller <djm@mindrot.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include "includes.h"
  18. #include <sys/types.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include "bitmap.h"
  22. #define BITMAP_WTYPE u_int
  23. #define BITMAP_MAX (1<<24)
  24. #define BITMAP_BYTES (sizeof(BITMAP_WTYPE))
  25. #define BITMAP_BITS (sizeof(BITMAP_WTYPE) * 8)
  26. #define BITMAP_WMASK ((BITMAP_WTYPE)BITMAP_BITS - 1)
  27. struct bitmap {
  28. BITMAP_WTYPE *d;
  29. size_t len; /* number of words allocated */
  30. size_t top; /* index of top word allocated */
  31. };
  32. struct bitmap *
  33. bitmap_new(void)
  34. {
  35. struct bitmap *ret;
  36. if ((ret = calloc(1, sizeof(*ret))) == NULL)
  37. return NULL;
  38. if ((ret->d = calloc(1, BITMAP_BYTES)) == NULL) {
  39. free(ret);
  40. return NULL;
  41. }
  42. ret->len = 1;
  43. ret->top = 0;
  44. return ret;
  45. }
  46. void
  47. bitmap_free(struct bitmap *b)
  48. {
  49. if (b != NULL && b->d != NULL) {
  50. bitmap_zero(b);
  51. free(b->d);
  52. b->d = NULL;
  53. }
  54. free(b);
  55. }
  56. void
  57. bitmap_zero(struct bitmap *b)
  58. {
  59. memset(b->d, 0, b->len * BITMAP_BYTES);
  60. b->top = 0;
  61. }
  62. int
  63. bitmap_test_bit(struct bitmap *b, u_int n)
  64. {
  65. if (b->top >= b->len)
  66. return 0; /* invalid */
  67. if (b->len == 0 || (n / BITMAP_BITS) > b->top)
  68. return 0;
  69. return (b->d[n / BITMAP_BITS] >> (n & BITMAP_WMASK)) & 1;
  70. }
  71. static int
  72. reserve(struct bitmap *b, u_int n)
  73. {
  74. BITMAP_WTYPE *tmp;
  75. size_t nlen;
  76. if (b->top >= b->len || n > BITMAP_MAX)
  77. return -1; /* invalid */
  78. nlen = (n / BITMAP_BITS) + 1;
  79. if (b->len < nlen) {
  80. if ((tmp = recallocarray(b->d, b->len,
  81. nlen, BITMAP_BYTES)) == NULL)
  82. return -1;
  83. b->d = tmp;
  84. b->len = nlen;
  85. }
  86. return 0;
  87. }
  88. int
  89. bitmap_set_bit(struct bitmap *b, u_int n)
  90. {
  91. int r;
  92. size_t offset;
  93. if ((r = reserve(b, n)) != 0)
  94. return r;
  95. offset = n / BITMAP_BITS;
  96. if (offset > b->top)
  97. b->top = offset;
  98. b->d[offset] |= (BITMAP_WTYPE)1 << (n & BITMAP_WMASK);
  99. return 0;
  100. }
  101. /* Resets b->top to point to the most significant bit set in b->d */
  102. static void
  103. retop(struct bitmap *b)
  104. {
  105. if (b->top >= b->len)
  106. return;
  107. while (b->top > 0 && b->d[b->top] == 0)
  108. b->top--;
  109. }
  110. void
  111. bitmap_clear_bit(struct bitmap *b, u_int n)
  112. {
  113. size_t offset;
  114. if (b->top >= b->len || n > BITMAP_MAX)
  115. return; /* invalid */
  116. offset = n / BITMAP_BITS;
  117. if (offset > b->top)
  118. return;
  119. b->d[offset] &= ~((BITMAP_WTYPE)1 << (n & BITMAP_WMASK));
  120. /* The top may have changed as a result of the clear */
  121. retop(b);
  122. }
  123. size_t
  124. bitmap_nbits(struct bitmap *b)
  125. {
  126. size_t bits;
  127. BITMAP_WTYPE w;
  128. retop(b);
  129. if (b->top >= b->len)
  130. return 0; /* invalid */
  131. if (b->len == 0 || (b->top == 0 && b->d[0] == 0))
  132. return 0;
  133. /* Find MSB set */
  134. w = b->d[b->top];
  135. bits = (b->top + 1) * BITMAP_BITS;
  136. while (!(w & ((BITMAP_WTYPE)1 << (BITMAP_BITS - 1)))) {
  137. w <<= 1;
  138. bits--;
  139. }
  140. return bits;
  141. }
  142. size_t
  143. bitmap_nbytes(struct bitmap *b)
  144. {
  145. return (bitmap_nbits(b) + 7) / 8;
  146. }
  147. int
  148. bitmap_to_string(struct bitmap *b, void *p, size_t l)
  149. {
  150. u_char *s = (u_char *)p;
  151. size_t i, j, k, need = bitmap_nbytes(b);
  152. if (l < need || b->top >= b->len)
  153. return -1;
  154. if (l > need)
  155. l = need;
  156. /* Put the bytes from LSB backwards */
  157. for (i = k = 0; i < b->top + 1; i++) {
  158. for (j = 0; j < BITMAP_BYTES; j++) {
  159. if (k >= l)
  160. break;
  161. s[need - 1 - k++] = (b->d[i] >> (j * 8)) & 0xff;
  162. }
  163. }
  164. return 0;
  165. }
  166. int
  167. bitmap_from_string(struct bitmap *b, const void *p, size_t l)
  168. {
  169. int r;
  170. size_t i, offset, shift;
  171. const u_char *s = (const u_char *)p;
  172. if (l > BITMAP_MAX / 8)
  173. return -1;
  174. if ((r = reserve(b, l * 8)) != 0)
  175. return r;
  176. bitmap_zero(b);
  177. if (l == 0)
  178. return 0;
  179. b->top = offset = ((l + (BITMAP_BYTES - 1)) / BITMAP_BYTES) - 1;
  180. shift = ((l + (BITMAP_BYTES - 1)) % BITMAP_BYTES) * 8;
  181. for (i = 0; i < l; i++) {
  182. b->d[offset] |= (BITMAP_WTYPE)s[i] << shift;
  183. if (shift == 0) {
  184. offset--;
  185. shift = BITMAP_BITS - 8;
  186. } else
  187. shift -= 8;
  188. }
  189. retop(b);
  190. return 0;
  191. }