bitmask.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <helpers/bitmask.h>
  5. /* How many bits in an unsigned long */
  6. #define bitsperlong (8 * sizeof(unsigned long))
  7. /* howmany(a,b) : how many elements of size b needed to hold all of a */
  8. #define howmany(x, y) (((x)+((y)-1))/(y))
  9. /* How many longs in mask of n bits */
  10. #define longsperbits(n) howmany(n, bitsperlong)
  11. #define max(a, b) ((a) > (b) ? (a) : (b))
  12. /*
  13. * Allocate and free `struct bitmask *`
  14. */
  15. /* Allocate a new `struct bitmask` with a size of n bits */
  16. struct bitmask *bitmask_alloc(unsigned int n)
  17. {
  18. struct bitmask *bmp;
  19. bmp = malloc(sizeof(*bmp));
  20. if (bmp == 0)
  21. return 0;
  22. bmp->size = n;
  23. bmp->maskp = calloc(longsperbits(n), sizeof(unsigned long));
  24. if (bmp->maskp == 0) {
  25. free(bmp);
  26. return 0;
  27. }
  28. return bmp;
  29. }
  30. /* Free `struct bitmask` */
  31. void bitmask_free(struct bitmask *bmp)
  32. {
  33. if (bmp == 0)
  34. return;
  35. free(bmp->maskp);
  36. bmp->maskp = (unsigned long *)0xdeadcdef; /* double free tripwire */
  37. free(bmp);
  38. }
  39. /*
  40. * The routines _getbit() and _setbit() are the only
  41. * routines that actually understand the layout of bmp->maskp[].
  42. *
  43. * On little endian architectures, this could simply be an array of
  44. * bytes. But the kernel layout of bitmasks _is_ visible to userspace
  45. * via the sched_(set/get)affinity calls in Linux 2.6, and on big
  46. * endian architectures, it is painfully obvious that this is an
  47. * array of unsigned longs.
  48. */
  49. /* Return the value (0 or 1) of bit n in bitmask bmp */
  50. static unsigned int _getbit(const struct bitmask *bmp, unsigned int n)
  51. {
  52. if (n < bmp->size)
  53. return (bmp->maskp[n/bitsperlong] >> (n % bitsperlong)) & 1;
  54. else
  55. return 0;
  56. }
  57. /* Set bit n in bitmask bmp to value v (0 or 1) */
  58. static void _setbit(struct bitmask *bmp, unsigned int n, unsigned int v)
  59. {
  60. if (n < bmp->size) {
  61. if (v)
  62. bmp->maskp[n/bitsperlong] |= 1UL << (n % bitsperlong);
  63. else
  64. bmp->maskp[n/bitsperlong] &=
  65. ~(1UL << (n % bitsperlong));
  66. }
  67. }
  68. /*
  69. * When parsing bitmask lists, only allow numbers, separated by one
  70. * of the allowed next characters.
  71. *
  72. * The parameter 'sret' is the return from a sscanf "%u%c". It is
  73. * -1 if the sscanf input string was empty. It is 0 if the first
  74. * character in the sscanf input string was not a decimal number.
  75. * It is 1 if the unsigned number matching the "%u" was the end of the
  76. * input string. It is 2 if one or more additional characters followed
  77. * the matched unsigned number. If it is 2, then 'nextc' is the first
  78. * character following the number. The parameter 'ok_next_chars'
  79. * is the nul-terminated list of allowed next characters.
  80. *
  81. * The mask term just scanned was ok if and only if either the numbers
  82. * matching the %u were all of the input or if the next character in
  83. * the input past the numbers was one of the allowed next characters.
  84. */
  85. static int scan_was_ok(int sret, char nextc, const char *ok_next_chars)
  86. {
  87. return sret == 1 ||
  88. (sret == 2 && strchr(ok_next_chars, nextc) != NULL);
  89. }
  90. static const char *nexttoken(const char *q, int sep)
  91. {
  92. if (q)
  93. q = strchr(q, sep);
  94. if (q)
  95. q++;
  96. return q;
  97. }
  98. /* Set a single bit i in bitmask */
  99. struct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i)
  100. {
  101. _setbit(bmp, i, 1);
  102. return bmp;
  103. }
  104. /* Set all bits in bitmask: bmp = ~0 */
  105. struct bitmask *bitmask_setall(struct bitmask *bmp)
  106. {
  107. unsigned int i;
  108. for (i = 0; i < bmp->size; i++)
  109. _setbit(bmp, i, 1);
  110. return bmp;
  111. }
  112. /* Clear all bits in bitmask: bmp = 0 */
  113. struct bitmask *bitmask_clearall(struct bitmask *bmp)
  114. {
  115. unsigned int i;
  116. for (i = 0; i < bmp->size; i++)
  117. _setbit(bmp, i, 0);
  118. return bmp;
  119. }
  120. /* True if all bits are clear */
  121. int bitmask_isallclear(const struct bitmask *bmp)
  122. {
  123. unsigned int i;
  124. for (i = 0; i < bmp->size; i++)
  125. if (_getbit(bmp, i))
  126. return 0;
  127. return 1;
  128. }
  129. /* True if specified bit i is set */
  130. int bitmask_isbitset(const struct bitmask *bmp, unsigned int i)
  131. {
  132. return _getbit(bmp, i);
  133. }
  134. /* Number of lowest set bit (min) */
  135. unsigned int bitmask_first(const struct bitmask *bmp)
  136. {
  137. return bitmask_next(bmp, 0);
  138. }
  139. /* Number of highest set bit (max) */
  140. unsigned int bitmask_last(const struct bitmask *bmp)
  141. {
  142. unsigned int i;
  143. unsigned int m = bmp->size;
  144. for (i = 0; i < bmp->size; i++)
  145. if (_getbit(bmp, i))
  146. m = i;
  147. return m;
  148. }
  149. /* Number of next set bit at or above given bit i */
  150. unsigned int bitmask_next(const struct bitmask *bmp, unsigned int i)
  151. {
  152. unsigned int n;
  153. for (n = i; n < bmp->size; n++)
  154. if (_getbit(bmp, n))
  155. break;
  156. return n;
  157. }
  158. /*
  159. * Parses a comma-separated list of numbers and ranges of numbers,
  160. * with optional ':%u' strides modifying ranges, into provided bitmask.
  161. * Some examples of input lists and their equivalent simple list:
  162. * Input Equivalent to
  163. * 0-3 0,1,2,3
  164. * 0-7:2 0,2,4,6
  165. * 1,3,5-7 1,3,5,6,7
  166. * 0-3:2,8-15:4 0,2,8,12
  167. */
  168. int bitmask_parselist(const char *buf, struct bitmask *bmp)
  169. {
  170. const char *p, *q;
  171. bitmask_clearall(bmp);
  172. q = buf;
  173. while (p = q, q = nexttoken(q, ','), p) {
  174. unsigned int a; /* begin of range */
  175. unsigned int b; /* end of range */
  176. unsigned int s; /* stride */
  177. const char *c1, *c2; /* next tokens after '-' or ',' */
  178. char nextc; /* char after sscanf %u match */
  179. int sret; /* sscanf return (number of matches) */
  180. sret = sscanf(p, "%u%c", &a, &nextc);
  181. if (!scan_was_ok(sret, nextc, ",-"))
  182. goto err;
  183. b = a;
  184. s = 1;
  185. c1 = nexttoken(p, '-');
  186. c2 = nexttoken(p, ',');
  187. if (c1 != NULL && (c2 == NULL || c1 < c2)) {
  188. sret = sscanf(c1, "%u%c", &b, &nextc);
  189. if (!scan_was_ok(sret, nextc, ",:"))
  190. goto err;
  191. c1 = nexttoken(c1, ':');
  192. if (c1 != NULL && (c2 == NULL || c1 < c2)) {
  193. sret = sscanf(c1, "%u%c", &s, &nextc);
  194. if (!scan_was_ok(sret, nextc, ","))
  195. goto err;
  196. }
  197. }
  198. if (!(a <= b))
  199. goto err;
  200. if (b >= bmp->size)
  201. goto err;
  202. while (a <= b) {
  203. _setbit(bmp, a, 1);
  204. a += s;
  205. }
  206. }
  207. return 0;
  208. err:
  209. bitmask_clearall(bmp);
  210. return -1;
  211. }
  212. /*
  213. * emit(buf, buflen, rbot, rtop, len)
  214. *
  215. * Helper routine for bitmask_displaylist(). Write decimal number
  216. * or range to buf+len, suppressing output past buf+buflen, with optional
  217. * comma-prefix. Return len of what would be written to buf, if it
  218. * all fit.
  219. */
  220. static inline int emit(char *buf, int buflen, int rbot, int rtop, int len)
  221. {
  222. if (len > 0)
  223. len += snprintf(buf + len, max(buflen - len, 0), ",");
  224. if (rbot == rtop)
  225. len += snprintf(buf + len, max(buflen - len, 0), "%d", rbot);
  226. else
  227. len += snprintf(buf + len, max(buflen - len, 0), "%d-%d",
  228. rbot, rtop);
  229. return len;
  230. }
  231. /*
  232. * Write decimal list representation of bmp to buf.
  233. *
  234. * Output format is a comma-separated list of decimal numbers and
  235. * ranges. Consecutively set bits are shown as two hyphen-separated
  236. * decimal numbers, the smallest and largest bit numbers set in
  237. * the range. Output format is compatible with the format
  238. * accepted as input by bitmap_parselist().
  239. *
  240. * The return value is the number of characters which would be
  241. * generated for the given input, excluding the trailing '\0', as
  242. * per ISO C99.
  243. */
  244. int bitmask_displaylist(char *buf, int buflen, const struct bitmask *bmp)
  245. {
  246. int len = 0;
  247. /* current bit is 'cur', most recently seen range is [rbot, rtop] */
  248. unsigned int cur, rbot, rtop;
  249. if (buflen > 0)
  250. *buf = 0;
  251. rbot = cur = bitmask_first(bmp);
  252. while (cur < bmp->size) {
  253. rtop = cur;
  254. cur = bitmask_next(bmp, cur+1);
  255. if (cur >= bmp->size || cur > rtop + 1) {
  256. len = emit(buf, buflen, rbot, rtop, len);
  257. rbot = cur;
  258. }
  259. }
  260. return len;
  261. }