1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * bitmask user library implementation.
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * Copyright (c) 2004-2006 Silicon Graphics, Inc. All rights reserved.
5f08c3bdfSopenharmony_ci *
6f08c3bdfSopenharmony_ci * Paul Jackson <pj@sgi.com>
7f08c3bdfSopenharmony_ci */
8f08c3bdfSopenharmony_ci
9f08c3bdfSopenharmony_ci/*
10f08c3bdfSopenharmony_ci *  This program is free software; you can redistribute it and/or modify
11f08c3bdfSopenharmony_ci *  it under the terms of the GNU Lesser General Public License as published by
12f08c3bdfSopenharmony_ci *  the Free Software Foundation; either version 2.1 of the License, or
13f08c3bdfSopenharmony_ci *  (at your option) any later version.
14f08c3bdfSopenharmony_ci *
15f08c3bdfSopenharmony_ci *  This program is distributed in the hope that it will be useful,
16f08c3bdfSopenharmony_ci *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17f08c3bdfSopenharmony_ci *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18f08c3bdfSopenharmony_ci *  GNU Lesser General Public License for more details.
19f08c3bdfSopenharmony_ci *
20f08c3bdfSopenharmony_ci *  You should have received a copy of the GNU Lesser General Public License
21f08c3bdfSopenharmony_ci *  along with this program; if not, write to the Free Software
22f08c3bdfSopenharmony_ci *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
23f08c3bdfSopenharmony_ci */
24f08c3bdfSopenharmony_ci
25f08c3bdfSopenharmony_ci#include <stdio.h>
26f08c3bdfSopenharmony_ci#include <string.h>
27f08c3bdfSopenharmony_ci#include <stdlib.h>
28f08c3bdfSopenharmony_ci#include <stdint.h>
29f08c3bdfSopenharmony_ci
30f08c3bdfSopenharmony_ci#include "bitmask.h"
31f08c3bdfSopenharmony_ci#include "tst_minmax.h"
32f08c3bdfSopenharmony_ci
33f08c3bdfSopenharmony_cistruct bitmask {
34f08c3bdfSopenharmony_ci	unsigned int size;
35f08c3bdfSopenharmony_ci	unsigned long *maskp;
36f08c3bdfSopenharmony_ci};
37f08c3bdfSopenharmony_ci
38f08c3bdfSopenharmony_ci/* How many bits in an unsigned long */
39f08c3bdfSopenharmony_ci#define bitsperlong (8 * sizeof(unsigned long))
40f08c3bdfSopenharmony_ci
41f08c3bdfSopenharmony_ci/* howmany(a,b) : how many elements of size b needed to hold all of a */
42f08c3bdfSopenharmony_ci#define howmany(x,y) (((x)+((y)-1))/(y))
43f08c3bdfSopenharmony_ci
44f08c3bdfSopenharmony_ci/* How many longs in mask of n bits */
45f08c3bdfSopenharmony_ci#define longsperbits(n) howmany(n, bitsperlong)
46f08c3bdfSopenharmony_ci
47f08c3bdfSopenharmony_ci/*
48f08c3bdfSopenharmony_ci * The routines _getbit() and _setbit() are the only
49f08c3bdfSopenharmony_ci * routines that actually understand the layout of bmp->maskp[].
50f08c3bdfSopenharmony_ci *
51f08c3bdfSopenharmony_ci * On little endian architectures, this could simply be an array of
52f08c3bdfSopenharmony_ci * bytes.  But the kernel layout of bitmasks _is_ visible to userspace
53f08c3bdfSopenharmony_ci * via the sched_(set/get)affinity calls in Linux 2.6, and on big
54f08c3bdfSopenharmony_ci * endian architectures, it is painfully obvious that this is an
55f08c3bdfSopenharmony_ci * array of unsigned longs.
56f08c3bdfSopenharmony_ci */
57f08c3bdfSopenharmony_ci
58f08c3bdfSopenharmony_ci/* Return the value (0 or 1) of bit n in bitmask bmp */
59f08c3bdfSopenharmony_cistatic unsigned int _getbit(const struct bitmask *bmp, unsigned int n)
60f08c3bdfSopenharmony_ci{
61f08c3bdfSopenharmony_ci	if (n < bmp->size)
62f08c3bdfSopenharmony_ci		return (bmp->maskp[n / bitsperlong] >> (n % bitsperlong)) & 1;
63f08c3bdfSopenharmony_ci	else
64f08c3bdfSopenharmony_ci		return 0;
65f08c3bdfSopenharmony_ci}
66f08c3bdfSopenharmony_ci
67f08c3bdfSopenharmony_ci/* Set bit n in bitmask bmp to value v (0 or 1) */
68f08c3bdfSopenharmony_cistatic void _setbit(struct bitmask *bmp, unsigned int n, unsigned int v)
69f08c3bdfSopenharmony_ci{
70f08c3bdfSopenharmony_ci	if (n < bmp->size) {
71f08c3bdfSopenharmony_ci		if (v)
72f08c3bdfSopenharmony_ci			bmp->maskp[n / bitsperlong] |= 1UL << (n % bitsperlong);
73f08c3bdfSopenharmony_ci		else
74f08c3bdfSopenharmony_ci			bmp->maskp[n / bitsperlong] &=
75f08c3bdfSopenharmony_ci			    ~(1UL << (n % bitsperlong));
76f08c3bdfSopenharmony_ci	}
77f08c3bdfSopenharmony_ci}
78f08c3bdfSopenharmony_ci
79f08c3bdfSopenharmony_ci/*
80f08c3bdfSopenharmony_ci * Allocate and free `struct bitmask *`
81f08c3bdfSopenharmony_ci */
82f08c3bdfSopenharmony_ci
83f08c3bdfSopenharmony_ci/* Allocate a new `struct bitmask` with a size of n bits */
84f08c3bdfSopenharmony_cistruct bitmask *bitmask_alloc(unsigned int n)
85f08c3bdfSopenharmony_ci{
86f08c3bdfSopenharmony_ci	struct bitmask *bmp;
87f08c3bdfSopenharmony_ci
88f08c3bdfSopenharmony_ci	bmp = malloc(sizeof(*bmp));
89f08c3bdfSopenharmony_ci	if (bmp == 0)
90f08c3bdfSopenharmony_ci		return 0;
91f08c3bdfSopenharmony_ci	bmp->size = n;
92f08c3bdfSopenharmony_ci	bmp->maskp = calloc(longsperbits(n), sizeof(unsigned long));
93f08c3bdfSopenharmony_ci	if (bmp->maskp == 0) {
94f08c3bdfSopenharmony_ci		free(bmp);
95f08c3bdfSopenharmony_ci		return 0;
96f08c3bdfSopenharmony_ci	}
97f08c3bdfSopenharmony_ci	return bmp;
98f08c3bdfSopenharmony_ci}
99f08c3bdfSopenharmony_ci
100f08c3bdfSopenharmony_ci/* Free `struct bitmask` */
101f08c3bdfSopenharmony_civoid bitmask_free(struct bitmask *bmp)
102f08c3bdfSopenharmony_ci{
103f08c3bdfSopenharmony_ci	if (bmp == 0)
104f08c3bdfSopenharmony_ci		return;
105f08c3bdfSopenharmony_ci	free(bmp->maskp);
106f08c3bdfSopenharmony_ci	bmp->maskp = (unsigned long *)0xdeadcdef;	/* double free tripwire */
107f08c3bdfSopenharmony_ci	free(bmp);
108f08c3bdfSopenharmony_ci}
109f08c3bdfSopenharmony_ci
110f08c3bdfSopenharmony_ci/*
111f08c3bdfSopenharmony_ci * Display and parse ascii string representations.
112f08c3bdfSopenharmony_ci */
113f08c3bdfSopenharmony_ci
114f08c3bdfSopenharmony_ci#define HEXCHUNKSZ 32		/* hex binary format shows 32 bits per chunk */
115f08c3bdfSopenharmony_ci#define HEXCHARSZ 8		/* hex ascii format has up to 8 chars per chunk */
116f08c3bdfSopenharmony_ci
117f08c3bdfSopenharmony_ci/*
118f08c3bdfSopenharmony_ci * Write hex word representation of bmp to buf, 32 bits per
119f08c3bdfSopenharmony_ci * comma-separated, zero-filled hex word.  Do not write more
120f08c3bdfSopenharmony_ci * than buflen chars to buf.
121f08c3bdfSopenharmony_ci *
122f08c3bdfSopenharmony_ci * Return number of chars that would have been written
123f08c3bdfSopenharmony_ci * if buf were large enough.
124f08c3bdfSopenharmony_ci */
125f08c3bdfSopenharmony_ci
126f08c3bdfSopenharmony_ciint bitmask_displayhex(char *buf, int buflen, const struct bitmask *bmp)
127f08c3bdfSopenharmony_ci{
128f08c3bdfSopenharmony_ci	int chunk;
129f08c3bdfSopenharmony_ci	int cnt = 0;
130f08c3bdfSopenharmony_ci	const char *sep = "";
131f08c3bdfSopenharmony_ci
132f08c3bdfSopenharmony_ci	if (buflen < 1)
133f08c3bdfSopenharmony_ci		return 0;
134f08c3bdfSopenharmony_ci	buf[0] = 0;
135f08c3bdfSopenharmony_ci
136f08c3bdfSopenharmony_ci	for (chunk = howmany(bmp->size, HEXCHUNKSZ) - 1; chunk >= 0; chunk--) {
137f08c3bdfSopenharmony_ci		uint32_t val = 0;
138f08c3bdfSopenharmony_ci		int bit;
139f08c3bdfSopenharmony_ci
140f08c3bdfSopenharmony_ci		for (bit = HEXCHUNKSZ - 1; bit >= 0; bit--)
141f08c3bdfSopenharmony_ci			val = val << 1 | _getbit(bmp, chunk * HEXCHUNKSZ + bit);
142f08c3bdfSopenharmony_ci		cnt += snprintf(buf + cnt, MAX(buflen - cnt, 0), "%s%0*x",
143f08c3bdfSopenharmony_ci				sep, HEXCHARSZ, val);
144f08c3bdfSopenharmony_ci		sep = ",";
145f08c3bdfSopenharmony_ci	}
146f08c3bdfSopenharmony_ci	return cnt;
147f08c3bdfSopenharmony_ci}
148f08c3bdfSopenharmony_ci
149f08c3bdfSopenharmony_ci/*
150f08c3bdfSopenharmony_ci * emit(buf, buflen, rbot, rtop, len)
151f08c3bdfSopenharmony_ci *
152f08c3bdfSopenharmony_ci * Helper routine for bitmask_displaylist().  Write decimal number
153f08c3bdfSopenharmony_ci * or range to buf+len, suppressing output past buf+buflen, with optional
154f08c3bdfSopenharmony_ci * comma-prefix.  Return len of what would be written to buf, if it
155f08c3bdfSopenharmony_ci * all fit.
156f08c3bdfSopenharmony_ci */
157f08c3bdfSopenharmony_ci
158f08c3bdfSopenharmony_cistatic inline int emit(char *buf, int buflen, int rbot, int rtop, int len)
159f08c3bdfSopenharmony_ci{
160f08c3bdfSopenharmony_ci	if (len > 0)
161f08c3bdfSopenharmony_ci		len += snprintf(buf + len, MAX(buflen - len, 0), ",");
162f08c3bdfSopenharmony_ci	if (rbot == rtop)
163f08c3bdfSopenharmony_ci		len += snprintf(buf + len, MAX(buflen - len, 0), "%d", rbot);
164f08c3bdfSopenharmony_ci	else
165f08c3bdfSopenharmony_ci		len +=
166f08c3bdfSopenharmony_ci		    snprintf(buf + len, MAX(buflen - len, 0), "%d-%d", rbot,
167f08c3bdfSopenharmony_ci			     rtop);
168f08c3bdfSopenharmony_ci	return len;
169f08c3bdfSopenharmony_ci}
170f08c3bdfSopenharmony_ci
171f08c3bdfSopenharmony_ci/*
172f08c3bdfSopenharmony_ci * Write decimal list representation of bmp to buf.
173f08c3bdfSopenharmony_ci *
174f08c3bdfSopenharmony_ci * Output format is a comma-separated list of decimal numbers and
175f08c3bdfSopenharmony_ci * ranges.  Consecutively set bits are shown as two hyphen-separated
176f08c3bdfSopenharmony_ci * decimal numbers, the smallest and largest bit numbers set in
177f08c3bdfSopenharmony_ci * the range.  Output format is compatible with the format
178f08c3bdfSopenharmony_ci * accepted as input by bitmap_parselist().
179f08c3bdfSopenharmony_ci *
180f08c3bdfSopenharmony_ci * The return value is the number of characters which would be
181f08c3bdfSopenharmony_ci * generated for the given input, excluding the trailing '\0', as
182f08c3bdfSopenharmony_ci * per ISO C99.
183f08c3bdfSopenharmony_ci */
184f08c3bdfSopenharmony_ci
185f08c3bdfSopenharmony_ciint bitmask_displaylist(char *buf, int buflen, const struct bitmask *bmp)
186f08c3bdfSopenharmony_ci{
187f08c3bdfSopenharmony_ci	int len = 0;
188f08c3bdfSopenharmony_ci	/* current bit is 'cur', most recently seen range is [rbot, rtop] */
189f08c3bdfSopenharmony_ci	unsigned int cur, rbot, rtop;
190f08c3bdfSopenharmony_ci
191f08c3bdfSopenharmony_ci	if (buflen > 0)
192f08c3bdfSopenharmony_ci		*buf = 0;
193f08c3bdfSopenharmony_ci	rbot = cur = bitmask_first(bmp);
194f08c3bdfSopenharmony_ci	while (cur < bmp->size) {
195f08c3bdfSopenharmony_ci		rtop = cur;
196f08c3bdfSopenharmony_ci		cur = bitmask_next(bmp, cur + 1);
197f08c3bdfSopenharmony_ci		if (cur >= bmp->size || cur > rtop + 1) {
198f08c3bdfSopenharmony_ci			len = emit(buf, buflen, rbot, rtop, len);
199f08c3bdfSopenharmony_ci			rbot = cur;
200f08c3bdfSopenharmony_ci		}
201f08c3bdfSopenharmony_ci	}
202f08c3bdfSopenharmony_ci	return len;
203f08c3bdfSopenharmony_ci}
204f08c3bdfSopenharmony_ci
205f08c3bdfSopenharmony_cistatic const char *nexttoken(const char *q, int sep)
206f08c3bdfSopenharmony_ci{
207f08c3bdfSopenharmony_ci	if (q)
208f08c3bdfSopenharmony_ci		q = strchr(q, sep);
209f08c3bdfSopenharmony_ci	if (q)
210f08c3bdfSopenharmony_ci		q++;
211f08c3bdfSopenharmony_ci	return q;
212f08c3bdfSopenharmony_ci}
213f08c3bdfSopenharmony_ci
214f08c3bdfSopenharmony_ci/*
215f08c3bdfSopenharmony_ci * Parse hex word representation in buf to bmp.
216f08c3bdfSopenharmony_ci *
217f08c3bdfSopenharmony_ci * Returns -1 on error, leaving unspecified results in bmp.
218f08c3bdfSopenharmony_ci */
219f08c3bdfSopenharmony_ci
220f08c3bdfSopenharmony_ciint bitmask_parsehex(const char *buf, struct bitmask *bmp)
221f08c3bdfSopenharmony_ci{
222f08c3bdfSopenharmony_ci	const char *p, *q;
223f08c3bdfSopenharmony_ci	int nchunks = 0, chunk;
224f08c3bdfSopenharmony_ci	unsigned int size = 0;
225f08c3bdfSopenharmony_ci
226f08c3bdfSopenharmony_ci	bitmask_clearall(bmp);
227f08c3bdfSopenharmony_ci	size = longsperbits(bmp->size) * 8 * sizeof(unsigned long);
228f08c3bdfSopenharmony_ci
229f08c3bdfSopenharmony_ci	q = buf;
230f08c3bdfSopenharmony_ci	while (p = q, q = nexttoken(q, ','), p)
231f08c3bdfSopenharmony_ci		nchunks++;
232f08c3bdfSopenharmony_ci
233f08c3bdfSopenharmony_ci	chunk = nchunks - 1;
234f08c3bdfSopenharmony_ci	q = buf;
235f08c3bdfSopenharmony_ci	while (p = q, q = nexttoken(q, ','), p) {
236f08c3bdfSopenharmony_ci		uint32_t val;
237f08c3bdfSopenharmony_ci		int bit;
238f08c3bdfSopenharmony_ci		char *endptr;
239f08c3bdfSopenharmony_ci		int nchars_read, nchars_unread;
240f08c3bdfSopenharmony_ci
241f08c3bdfSopenharmony_ci		val = strtoul(p, &endptr, 16);
242f08c3bdfSopenharmony_ci
243f08c3bdfSopenharmony_ci		/* We should have consumed 1 to 8 (HEXCHARSZ) chars */
244f08c3bdfSopenharmony_ci		nchars_read = endptr - p;
245f08c3bdfSopenharmony_ci		if (nchars_read < 1 || nchars_read > HEXCHARSZ)
246f08c3bdfSopenharmony_ci			goto err;
247f08c3bdfSopenharmony_ci
248f08c3bdfSopenharmony_ci		/* We should have consumed up to next comma */
249f08c3bdfSopenharmony_ci		nchars_unread = q - endptr;
250f08c3bdfSopenharmony_ci		if (q != NULL && nchars_unread != 1)
251f08c3bdfSopenharmony_ci			goto err;
252f08c3bdfSopenharmony_ci
253f08c3bdfSopenharmony_ci		for (bit = HEXCHUNKSZ - 1; bit >= 0; bit--) {
254f08c3bdfSopenharmony_ci			unsigned int n = chunk * HEXCHUNKSZ + bit;
255f08c3bdfSopenharmony_ci			if (n >= size)
256f08c3bdfSopenharmony_ci				goto err;
257f08c3bdfSopenharmony_ci			_setbit(bmp, n, (val >> bit) & 1);
258f08c3bdfSopenharmony_ci		}
259f08c3bdfSopenharmony_ci		chunk--;
260f08c3bdfSopenharmony_ci	}
261f08c3bdfSopenharmony_ci	return 0;
262f08c3bdfSopenharmony_cierr:
263f08c3bdfSopenharmony_ci	bitmask_clearall(bmp);
264f08c3bdfSopenharmony_ci	return -1;
265f08c3bdfSopenharmony_ci}
266f08c3bdfSopenharmony_ci
267f08c3bdfSopenharmony_ci/*
268f08c3bdfSopenharmony_ci * When parsing bitmask lists, only allow numbers, separated by one
269f08c3bdfSopenharmony_ci * of the allowed next characters.
270f08c3bdfSopenharmony_ci *
271f08c3bdfSopenharmony_ci * The parameter 'sret' is the return from a sscanf "%u%c".  It is
272f08c3bdfSopenharmony_ci * -1 if the sscanf input string was empty.  It is 0 if the first
273f08c3bdfSopenharmony_ci * character in the sscanf input string was not a decimal number.
274f08c3bdfSopenharmony_ci * It is 1 if the unsigned number matching the "%u" was the end of the
275f08c3bdfSopenharmony_ci * input string.  It is 2 if one or more additional characters followed
276f08c3bdfSopenharmony_ci * the matched unsigned number.  If it is 2, then 'nextc' is the first
277f08c3bdfSopenharmony_ci * character following the number.  The parameter 'ok_next_chars'
278f08c3bdfSopenharmony_ci * is the nul-terminated list of allowed next characters.
279f08c3bdfSopenharmony_ci *
280f08c3bdfSopenharmony_ci * The mask term just scanned was ok if and only if either the numbers
281f08c3bdfSopenharmony_ci * matching the %u were all of the input or if the next character in
282f08c3bdfSopenharmony_ci * the input past the numbers was one of the allowed next characters.
283f08c3bdfSopenharmony_ci */
284f08c3bdfSopenharmony_cistatic int scan_was_ok(int sret, char nextc, const char *ok_next_chars)
285f08c3bdfSopenharmony_ci{
286f08c3bdfSopenharmony_ci	return sret == 1 || (sret == 2 && strchr(ok_next_chars, nextc) != NULL);
287f08c3bdfSopenharmony_ci}
288f08c3bdfSopenharmony_ci
289f08c3bdfSopenharmony_ci/*
290f08c3bdfSopenharmony_ci * Parses a comma-separated list of numbers and ranges of numbers,
291f08c3bdfSopenharmony_ci * with optional ':%u' strides modifying ranges, into provided bitmask.
292f08c3bdfSopenharmony_ci * Some examples of input lists and their equivalent simple list:
293f08c3bdfSopenharmony_ci *	Input		Equivalent to
294f08c3bdfSopenharmony_ci *	0-3		0,1,2,3
295f08c3bdfSopenharmony_ci *	0-7:2		0,2,4,6
296f08c3bdfSopenharmony_ci *	1,3,5-7		1,3,5,6,7
297f08c3bdfSopenharmony_ci *	0-3:2,8-15:4	0,2,8,12
298f08c3bdfSopenharmony_ci */
299f08c3bdfSopenharmony_ciint bitmask_parselist(const char *buf, struct bitmask *bmp)
300f08c3bdfSopenharmony_ci{
301f08c3bdfSopenharmony_ci	const char *p, *q;
302f08c3bdfSopenharmony_ci
303f08c3bdfSopenharmony_ci	bitmask_clearall(bmp);
304f08c3bdfSopenharmony_ci
305f08c3bdfSopenharmony_ci	q = buf;
306f08c3bdfSopenharmony_ci	while (p = q, q = nexttoken(q, ','), p) {
307f08c3bdfSopenharmony_ci		unsigned int a;	/* begin of range */
308f08c3bdfSopenharmony_ci		unsigned int b;	/* end of range */
309f08c3bdfSopenharmony_ci		unsigned int s;	/* stride */
310f08c3bdfSopenharmony_ci		const char *c1, *c2;	/* next tokens after '-' or ',' */
311f08c3bdfSopenharmony_ci		char nextc;	/* char after sscanf %u match */
312f08c3bdfSopenharmony_ci		int sret;	/* sscanf return (number of matches) */
313f08c3bdfSopenharmony_ci
314f08c3bdfSopenharmony_ci		sret = sscanf(p, "%u%c", &a, &nextc);
315f08c3bdfSopenharmony_ci		if (!scan_was_ok(sret, nextc, ",-"))
316f08c3bdfSopenharmony_ci			goto err;
317f08c3bdfSopenharmony_ci		b = a;
318f08c3bdfSopenharmony_ci		s = 1;
319f08c3bdfSopenharmony_ci		c1 = nexttoken(p, '-');
320f08c3bdfSopenharmony_ci		c2 = nexttoken(p, ',');
321f08c3bdfSopenharmony_ci		if (c1 != NULL && (c2 == NULL || c1 < c2)) {
322f08c3bdfSopenharmony_ci			sret = sscanf(c1, "%u%c", &b, &nextc);
323f08c3bdfSopenharmony_ci			if (!scan_was_ok(sret, nextc, ",:"))
324f08c3bdfSopenharmony_ci				goto err;
325f08c3bdfSopenharmony_ci			c1 = nexttoken(c1, ':');
326f08c3bdfSopenharmony_ci			if (c1 != NULL && (c2 == NULL || c1 < c2)) {
327f08c3bdfSopenharmony_ci				sret = sscanf(c1, "%u%c", &s, &nextc);
328f08c3bdfSopenharmony_ci				if (!scan_was_ok(sret, nextc, ","))
329f08c3bdfSopenharmony_ci					goto err;
330f08c3bdfSopenharmony_ci			}
331f08c3bdfSopenharmony_ci		}
332f08c3bdfSopenharmony_ci		if (!(a <= b))
333f08c3bdfSopenharmony_ci			goto err;
334f08c3bdfSopenharmony_ci		if (b >= bmp->size)
335f08c3bdfSopenharmony_ci			goto err;
336f08c3bdfSopenharmony_ci		while (a <= b) {
337f08c3bdfSopenharmony_ci			_setbit(bmp, a, 1);
338f08c3bdfSopenharmony_ci			a += s;
339f08c3bdfSopenharmony_ci		}
340f08c3bdfSopenharmony_ci	}
341f08c3bdfSopenharmony_ci	return 0;
342f08c3bdfSopenharmony_cierr:
343f08c3bdfSopenharmony_ci	bitmask_clearall(bmp);
344f08c3bdfSopenharmony_ci	return -1;
345f08c3bdfSopenharmony_ci}
346f08c3bdfSopenharmony_ci
347f08c3bdfSopenharmony_ci/*
348f08c3bdfSopenharmony_ci * Basic assignment operations
349f08c3bdfSopenharmony_ci */
350f08c3bdfSopenharmony_ci
351f08c3bdfSopenharmony_ci/* Copy bmp2 to bmp1 */
352f08c3bdfSopenharmony_cistruct bitmask *bitmask_copy(struct bitmask *bmp1, const struct bitmask *bmp2)
353f08c3bdfSopenharmony_ci{
354f08c3bdfSopenharmony_ci	unsigned int i;
355f08c3bdfSopenharmony_ci	for (i = 0; i < bmp1->size; i++)
356f08c3bdfSopenharmony_ci		_setbit(bmp1, i, _getbit(bmp2, i));
357f08c3bdfSopenharmony_ci	return bmp1;
358f08c3bdfSopenharmony_ci}
359f08c3bdfSopenharmony_ci
360f08c3bdfSopenharmony_ci/* Set all bits in bitmask: bmp = ~0 */
361f08c3bdfSopenharmony_cistruct bitmask *bitmask_setall(struct bitmask *bmp)
362f08c3bdfSopenharmony_ci{
363f08c3bdfSopenharmony_ci	unsigned int i;
364f08c3bdfSopenharmony_ci	for (i = 0; i < bmp->size; i++)
365f08c3bdfSopenharmony_ci		_setbit(bmp, i, 1);
366f08c3bdfSopenharmony_ci	return bmp;
367f08c3bdfSopenharmony_ci}
368f08c3bdfSopenharmony_ci
369f08c3bdfSopenharmony_ci/* Clear all bits in bitmask: bmp = 0 */
370f08c3bdfSopenharmony_cistruct bitmask *bitmask_clearall(struct bitmask *bmp)
371f08c3bdfSopenharmony_ci{
372f08c3bdfSopenharmony_ci	unsigned int i;
373f08c3bdfSopenharmony_ci	for (i = 0; i < bmp->size; i++)
374f08c3bdfSopenharmony_ci		_setbit(bmp, i, 0);
375f08c3bdfSopenharmony_ci	return bmp;
376f08c3bdfSopenharmony_ci}
377f08c3bdfSopenharmony_ci
378f08c3bdfSopenharmony_ci/*
379f08c3bdfSopenharmony_ci * Interface to kernel sched_setaffinity system call
380f08c3bdfSopenharmony_ci */
381f08c3bdfSopenharmony_ci
382f08c3bdfSopenharmony_ci/* Length in bytes of mask - use as second argument to sched_setaffinity */
383f08c3bdfSopenharmony_ciunsigned int bitmask_nbytes(struct bitmask *bmp)
384f08c3bdfSopenharmony_ci{
385f08c3bdfSopenharmony_ci	return longsperbits(bmp->size) * sizeof(unsigned long);
386f08c3bdfSopenharmony_ci}
387f08c3bdfSopenharmony_ci
388f08c3bdfSopenharmony_ci/* Direct pointer to bit mask - use as third argument to sched_setaffinty */
389f08c3bdfSopenharmony_ciunsigned long *bitmask_mask(struct bitmask *bmp)
390f08c3bdfSopenharmony_ci{
391f08c3bdfSopenharmony_ci	return bmp->maskp;
392f08c3bdfSopenharmony_ci}
393f08c3bdfSopenharmony_ci
394f08c3bdfSopenharmony_ci/*
395f08c3bdfSopenharmony_ci * Unary numeric queries
396f08c3bdfSopenharmony_ci */
397f08c3bdfSopenharmony_ci
398f08c3bdfSopenharmony_ci/* Size in bits of entire bitmask */
399f08c3bdfSopenharmony_ciunsigned int bitmask_nbits(const struct bitmask *bmp)
400f08c3bdfSopenharmony_ci{
401f08c3bdfSopenharmony_ci	return bmp->size;
402f08c3bdfSopenharmony_ci}
403f08c3bdfSopenharmony_ci
404f08c3bdfSopenharmony_ci/* Hamming Weight: number of set bits */
405f08c3bdfSopenharmony_ciunsigned int bitmask_weight(const struct bitmask *bmp)
406f08c3bdfSopenharmony_ci{
407f08c3bdfSopenharmony_ci	unsigned int i;
408f08c3bdfSopenharmony_ci	unsigned int w = 0;
409f08c3bdfSopenharmony_ci	for (i = 0; i < bmp->size; i++)
410f08c3bdfSopenharmony_ci		if (_getbit(bmp, i))
411f08c3bdfSopenharmony_ci			w++;
412f08c3bdfSopenharmony_ci	return w;
413f08c3bdfSopenharmony_ci}
414f08c3bdfSopenharmony_ci
415f08c3bdfSopenharmony_ci/*
416f08c3bdfSopenharmony_ci * Unary Boolean queries
417f08c3bdfSopenharmony_ci */
418f08c3bdfSopenharmony_ci
419f08c3bdfSopenharmony_ci/* True if specified bit i is set */
420f08c3bdfSopenharmony_ciint bitmask_isbitset(const struct bitmask *bmp, unsigned int i)
421f08c3bdfSopenharmony_ci{
422f08c3bdfSopenharmony_ci	return _getbit(bmp, i);
423f08c3bdfSopenharmony_ci}
424f08c3bdfSopenharmony_ci
425f08c3bdfSopenharmony_ci/* True if specified bit i is clear */
426f08c3bdfSopenharmony_ciint bitmask_isbitclear(const struct bitmask *bmp, unsigned int i)
427f08c3bdfSopenharmony_ci{
428f08c3bdfSopenharmony_ci	return !_getbit(bmp, i);
429f08c3bdfSopenharmony_ci}
430f08c3bdfSopenharmony_ci
431f08c3bdfSopenharmony_ci/* True if all bits are set */
432f08c3bdfSopenharmony_ciint bitmask_isallset(const struct bitmask *bmp)
433f08c3bdfSopenharmony_ci{
434f08c3bdfSopenharmony_ci	unsigned int i;
435f08c3bdfSopenharmony_ci	for (i = 0; i < bmp->size; i++)
436f08c3bdfSopenharmony_ci		if (!_getbit(bmp, i))
437f08c3bdfSopenharmony_ci			return 0;
438f08c3bdfSopenharmony_ci	return 1;
439f08c3bdfSopenharmony_ci}
440f08c3bdfSopenharmony_ci
441f08c3bdfSopenharmony_ci/* True if all bits are clear */
442f08c3bdfSopenharmony_ciint bitmask_isallclear(const struct bitmask *bmp)
443f08c3bdfSopenharmony_ci{
444f08c3bdfSopenharmony_ci	unsigned int i;
445f08c3bdfSopenharmony_ci	for (i = 0; i < bmp->size; i++)
446f08c3bdfSopenharmony_ci		if (_getbit(bmp, i))
447f08c3bdfSopenharmony_ci			return 0;
448f08c3bdfSopenharmony_ci	return 1;
449f08c3bdfSopenharmony_ci}
450f08c3bdfSopenharmony_ci
451f08c3bdfSopenharmony_ci/*
452f08c3bdfSopenharmony_ci * Single bit operations
453f08c3bdfSopenharmony_ci */
454f08c3bdfSopenharmony_ci
455f08c3bdfSopenharmony_ci/* Set a single bit i in bitmask */
456f08c3bdfSopenharmony_cistruct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i)
457f08c3bdfSopenharmony_ci{
458f08c3bdfSopenharmony_ci	_setbit(bmp, i, 1);
459f08c3bdfSopenharmony_ci	return bmp;
460f08c3bdfSopenharmony_ci}
461f08c3bdfSopenharmony_ci
462f08c3bdfSopenharmony_ci/* Clear a single bit i in bitmask */
463f08c3bdfSopenharmony_cistruct bitmask *bitmask_clearbit(struct bitmask *bmp, unsigned int i)
464f08c3bdfSopenharmony_ci{
465f08c3bdfSopenharmony_ci	_setbit(bmp, i, 0);
466f08c3bdfSopenharmony_ci	return bmp;
467f08c3bdfSopenharmony_ci}
468f08c3bdfSopenharmony_ci
469f08c3bdfSopenharmony_ci/*
470f08c3bdfSopenharmony_ci * Binary Boolean operations: bmp1 op? bmp2
471f08c3bdfSopenharmony_ci */
472f08c3bdfSopenharmony_ci
473f08c3bdfSopenharmony_ci/* True if two bitmasks are equal */
474f08c3bdfSopenharmony_ciint bitmask_equal(const struct bitmask *bmp1, const struct bitmask *bmp2)
475f08c3bdfSopenharmony_ci{
476f08c3bdfSopenharmony_ci	unsigned int i;
477f08c3bdfSopenharmony_ci	for (i = 0; i < bmp1->size || i < bmp2->size; i++)
478f08c3bdfSopenharmony_ci		if (_getbit(bmp1, i) != _getbit(bmp2, i))
479f08c3bdfSopenharmony_ci			return 0;
480f08c3bdfSopenharmony_ci	return 1;
481f08c3bdfSopenharmony_ci}
482f08c3bdfSopenharmony_ci
483f08c3bdfSopenharmony_ci/* True if first bitmask is subset of second */
484f08c3bdfSopenharmony_ciint bitmask_subset(const struct bitmask *bmp1, const struct bitmask *bmp2)
485f08c3bdfSopenharmony_ci{
486f08c3bdfSopenharmony_ci	unsigned int i;
487f08c3bdfSopenharmony_ci	for (i = 0; i < bmp1->size; i++)
488f08c3bdfSopenharmony_ci		if (_getbit(bmp1, i) > _getbit(bmp2, i))
489f08c3bdfSopenharmony_ci			return 0;
490f08c3bdfSopenharmony_ci	return 1;
491f08c3bdfSopenharmony_ci}
492f08c3bdfSopenharmony_ci
493f08c3bdfSopenharmony_ci/* True if two bitmasks don't overlap */
494f08c3bdfSopenharmony_ciint bitmask_disjoint(const struct bitmask *bmp1, const struct bitmask *bmp2)
495f08c3bdfSopenharmony_ci{
496f08c3bdfSopenharmony_ci	unsigned int i;
497f08c3bdfSopenharmony_ci	for (i = 0; i < bmp1->size; i++)
498f08c3bdfSopenharmony_ci		if (_getbit(bmp1, i) & _getbit(bmp2, i))
499f08c3bdfSopenharmony_ci			return 0;
500f08c3bdfSopenharmony_ci	return 1;
501f08c3bdfSopenharmony_ci}
502f08c3bdfSopenharmony_ci
503f08c3bdfSopenharmony_ci/* True if two bitmasks do overlap */
504f08c3bdfSopenharmony_ciint bitmask_intersects(const struct bitmask *bmp1, const struct bitmask *bmp2)
505f08c3bdfSopenharmony_ci{
506f08c3bdfSopenharmony_ci	unsigned int i;
507f08c3bdfSopenharmony_ci	for (i = 0; i < bmp1->size; i++)
508f08c3bdfSopenharmony_ci		if (_getbit(bmp1, i) & _getbit(bmp2, i))
509f08c3bdfSopenharmony_ci			return 1;
510f08c3bdfSopenharmony_ci	return 0;
511f08c3bdfSopenharmony_ci}
512f08c3bdfSopenharmony_ci
513f08c3bdfSopenharmony_ci/*
514f08c3bdfSopenharmony_ci * Range operations
515f08c3bdfSopenharmony_ci */
516f08c3bdfSopenharmony_ci
517f08c3bdfSopenharmony_ci/* Set bits of bitmask in specified range [i, j) */
518f08c3bdfSopenharmony_cistruct bitmask *bitmask_setrange(struct bitmask *bmp,
519f08c3bdfSopenharmony_ci				 unsigned int i, unsigned int j)
520f08c3bdfSopenharmony_ci{
521f08c3bdfSopenharmony_ci	unsigned int n;
522f08c3bdfSopenharmony_ci	for (n = i; n < j; n++)
523f08c3bdfSopenharmony_ci		_setbit(bmp, n, 1);
524f08c3bdfSopenharmony_ci	return bmp;
525f08c3bdfSopenharmony_ci}
526f08c3bdfSopenharmony_ci
527f08c3bdfSopenharmony_ci/* Clear bits of bitmask in specified range */
528f08c3bdfSopenharmony_cistruct bitmask *bitmask_clearrange(struct bitmask *bmp,
529f08c3bdfSopenharmony_ci				   unsigned int i, unsigned int j)
530f08c3bdfSopenharmony_ci{
531f08c3bdfSopenharmony_ci	unsigned int n;
532f08c3bdfSopenharmony_ci	for (n = i; n < j; n++)
533f08c3bdfSopenharmony_ci		_setbit(bmp, n, 0);
534f08c3bdfSopenharmony_ci	return bmp;
535f08c3bdfSopenharmony_ci}
536f08c3bdfSopenharmony_ci
537f08c3bdfSopenharmony_ci/* Clear all but specified range */
538f08c3bdfSopenharmony_cistruct bitmask *bitmask_keeprange(struct bitmask *bmp,
539f08c3bdfSopenharmony_ci				  unsigned int i, unsigned int j)
540f08c3bdfSopenharmony_ci{
541f08c3bdfSopenharmony_ci	bitmask_clearrange(bmp, 0, i);
542f08c3bdfSopenharmony_ci	bitmask_clearrange(bmp, j, bmp->size);
543f08c3bdfSopenharmony_ci	return bmp;
544f08c3bdfSopenharmony_ci}
545f08c3bdfSopenharmony_ci
546f08c3bdfSopenharmony_ci/*
547f08c3bdfSopenharmony_ci * Unary operations: bmp1 = op(struct bitmask *bmp2)
548f08c3bdfSopenharmony_ci */
549f08c3bdfSopenharmony_ci
550f08c3bdfSopenharmony_ci/* Complement: bmp1 = ~bmp2 */
551f08c3bdfSopenharmony_cistruct bitmask *bitmask_complement(struct bitmask *bmp1,
552f08c3bdfSopenharmony_ci				   const struct bitmask *bmp2)
553f08c3bdfSopenharmony_ci{
554f08c3bdfSopenharmony_ci	unsigned int i;
555f08c3bdfSopenharmony_ci	for (i = 0; i < bmp1->size; i++)
556f08c3bdfSopenharmony_ci		_setbit(bmp1, i, !_getbit(bmp2, i));
557f08c3bdfSopenharmony_ci	return bmp1;
558f08c3bdfSopenharmony_ci}
559f08c3bdfSopenharmony_ci
560f08c3bdfSopenharmony_ci/* Right shift: bmp1 = bmp2 >> n */
561f08c3bdfSopenharmony_cistruct bitmask *bitmask_shiftright(struct bitmask *bmp1,
562f08c3bdfSopenharmony_ci				   const struct bitmask *bmp2, unsigned int n)
563f08c3bdfSopenharmony_ci{
564f08c3bdfSopenharmony_ci	unsigned int i;
565f08c3bdfSopenharmony_ci	for (i = 0; i < bmp1->size; i++)
566f08c3bdfSopenharmony_ci		_setbit(bmp1, i, _getbit(bmp2, i + n));
567f08c3bdfSopenharmony_ci	return bmp1;
568f08c3bdfSopenharmony_ci}
569f08c3bdfSopenharmony_ci
570f08c3bdfSopenharmony_ci/* Left shift: bmp1 = bmp2 << n */
571f08c3bdfSopenharmony_cistruct bitmask *bitmask_shiftleft(struct bitmask *bmp1,
572f08c3bdfSopenharmony_ci				  const struct bitmask *bmp2, unsigned int n)
573f08c3bdfSopenharmony_ci{
574f08c3bdfSopenharmony_ci	int i;
575f08c3bdfSopenharmony_ci	for (i = bmp1->size - 1; i >= 0; i--)
576f08c3bdfSopenharmony_ci		_setbit(bmp1, i, _getbit(bmp2, i - n));
577f08c3bdfSopenharmony_ci	return bmp1;
578f08c3bdfSopenharmony_ci}
579f08c3bdfSopenharmony_ci
580f08c3bdfSopenharmony_ci/*
581f08c3bdfSopenharmony_ci * Binary operations: bmp1 = bmp2 op bmp3
582f08c3bdfSopenharmony_ci */
583f08c3bdfSopenharmony_ci
584f08c3bdfSopenharmony_ci/* Logical `and` of two bitmasks: bmp1 = bmp2 & bmp3 */
585f08c3bdfSopenharmony_cistruct bitmask *bitmask_and(struct bitmask *bmp1, const struct bitmask *bmp2,
586f08c3bdfSopenharmony_ci			    const struct bitmask *bmp3)
587f08c3bdfSopenharmony_ci{
588f08c3bdfSopenharmony_ci	unsigned int i;
589f08c3bdfSopenharmony_ci	for (i = 0; i < bmp1->size; i++)
590f08c3bdfSopenharmony_ci		_setbit(bmp1, i, _getbit(bmp2, i) & _getbit(bmp3, i));
591f08c3bdfSopenharmony_ci	return bmp1;
592f08c3bdfSopenharmony_ci}
593f08c3bdfSopenharmony_ci
594f08c3bdfSopenharmony_ci/* Logical `andnot` of two bitmasks: bmp1 = bmp2 & ~bmp3 */
595f08c3bdfSopenharmony_cistruct bitmask *bitmask_andnot(struct bitmask *bmp1, const struct bitmask *bmp2,
596f08c3bdfSopenharmony_ci			       const struct bitmask *bmp3)
597f08c3bdfSopenharmony_ci{
598f08c3bdfSopenharmony_ci	unsigned int i;
599f08c3bdfSopenharmony_ci	for (i = 0; i < bmp1->size; i++)
600f08c3bdfSopenharmony_ci		_setbit(bmp1, i, _getbit(bmp2, i) & ~_getbit(bmp3, i));
601f08c3bdfSopenharmony_ci	return bmp1;
602f08c3bdfSopenharmony_ci}
603f08c3bdfSopenharmony_ci
604f08c3bdfSopenharmony_ci/* Logical `or` of two bitmasks: bmp1 = bmp2 | bmp3 */
605f08c3bdfSopenharmony_cistruct bitmask *bitmask_or(struct bitmask *bmp1, const struct bitmask *bmp2,
606f08c3bdfSopenharmony_ci			   const struct bitmask *bmp3)
607f08c3bdfSopenharmony_ci{
608f08c3bdfSopenharmony_ci	unsigned int i;
609f08c3bdfSopenharmony_ci	for (i = 0; i < bmp1->size; i++)
610f08c3bdfSopenharmony_ci		_setbit(bmp1, i, _getbit(bmp2, i) | _getbit(bmp3, i));
611f08c3bdfSopenharmony_ci	return bmp1;
612f08c3bdfSopenharmony_ci}
613f08c3bdfSopenharmony_ci
614f08c3bdfSopenharmony_ci/* Logical `eor` of two bitmasks: bmp1 = bmp2 ^ bmp3 */
615f08c3bdfSopenharmony_cistruct bitmask *bitmask_eor(struct bitmask *bmp1, const struct bitmask *bmp2,
616f08c3bdfSopenharmony_ci			    const struct bitmask *bmp3)
617f08c3bdfSopenharmony_ci{
618f08c3bdfSopenharmony_ci	unsigned int i;
619f08c3bdfSopenharmony_ci	for (i = 0; i < bmp1->size; i++)
620f08c3bdfSopenharmony_ci		_setbit(bmp1, i, _getbit(bmp2, i) ^ _getbit(bmp3, i));
621f08c3bdfSopenharmony_ci	return bmp1;
622f08c3bdfSopenharmony_ci}
623f08c3bdfSopenharmony_ci
624f08c3bdfSopenharmony_ci/*
625f08c3bdfSopenharmony_ci * Iteration operators
626f08c3bdfSopenharmony_ci */
627f08c3bdfSopenharmony_ci
628f08c3bdfSopenharmony_ci/* Number of lowest set bit (min) */
629f08c3bdfSopenharmony_ciunsigned int bitmask_first(const struct bitmask *bmp)
630f08c3bdfSopenharmony_ci{
631f08c3bdfSopenharmony_ci	return bitmask_next(bmp, 0);
632f08c3bdfSopenharmony_ci}
633f08c3bdfSopenharmony_ci
634f08c3bdfSopenharmony_ci/* Number of next set bit at or above given bit i */
635f08c3bdfSopenharmony_ciunsigned int bitmask_next(const struct bitmask *bmp, unsigned int i)
636f08c3bdfSopenharmony_ci{
637f08c3bdfSopenharmony_ci	unsigned int n;
638f08c3bdfSopenharmony_ci	for (n = i; n < bmp->size; n++)
639f08c3bdfSopenharmony_ci		if (_getbit(bmp, n))
640f08c3bdfSopenharmony_ci			break;
641f08c3bdfSopenharmony_ci	return n;
642f08c3bdfSopenharmony_ci}
643f08c3bdfSopenharmony_ci
644f08c3bdfSopenharmony_ci/* Absolute position of nth set bit */
645f08c3bdfSopenharmony_ciunsigned int bitmask_rel_to_abs_pos(const struct bitmask *bmp, unsigned int n)
646f08c3bdfSopenharmony_ci{
647f08c3bdfSopenharmony_ci	unsigned int i;
648f08c3bdfSopenharmony_ci	for (i = 0; i < bmp->size; i++)
649f08c3bdfSopenharmony_ci		if (_getbit(bmp, i))
650f08c3bdfSopenharmony_ci			if (n-- == 0)
651f08c3bdfSopenharmony_ci				break;
652f08c3bdfSopenharmony_ci	return i;
653f08c3bdfSopenharmony_ci}
654f08c3bdfSopenharmony_ci
655f08c3bdfSopenharmony_ci/* Relative position amongst set bits of bit n */
656f08c3bdfSopenharmony_ciunsigned int bitmask_abs_to_rel_pos(const struct bitmask *bmp, unsigned int n)
657f08c3bdfSopenharmony_ci{
658f08c3bdfSopenharmony_ci	unsigned int i;
659f08c3bdfSopenharmony_ci	unsigned int w = 0;
660f08c3bdfSopenharmony_ci
661f08c3bdfSopenharmony_ci	if (!_getbit(bmp, n))
662f08c3bdfSopenharmony_ci		return bmp->size;
663f08c3bdfSopenharmony_ci	/* Add in number bits set before bit n */
664f08c3bdfSopenharmony_ci	for (i = 0; i < n; i++)
665f08c3bdfSopenharmony_ci		if (_getbit(bmp, i))
666f08c3bdfSopenharmony_ci			w++;
667f08c3bdfSopenharmony_ci	return w;
668f08c3bdfSopenharmony_ci}
669f08c3bdfSopenharmony_ci
670f08c3bdfSopenharmony_ci/* Number of highest set bit (max) */
671f08c3bdfSopenharmony_ciunsigned int bitmask_last(const struct bitmask *bmp)
672f08c3bdfSopenharmony_ci{
673f08c3bdfSopenharmony_ci	unsigned int i;
674f08c3bdfSopenharmony_ci	unsigned int m = bmp->size;
675f08c3bdfSopenharmony_ci	for (i = 0; i < bmp->size; i++)
676f08c3bdfSopenharmony_ci		if (_getbit(bmp, i))
677f08c3bdfSopenharmony_ci			m = i;
678f08c3bdfSopenharmony_ci	return m;
679f08c3bdfSopenharmony_ci}
680