bitmask.c 7.3 KB

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