1 /*
2  * Copyright © 2009 CNRS
3  * Copyright © 2009-2017 Inria.  All rights reserved.
4  * Copyright © 2009-2011 Université Bordeaux
5  * Copyright © 2009-2011 Cisco Systems, Inc.  All rights reserved.
6  * See COPYING in top-level directory.
7  */
8 
9 #include <private/autogen/config.h>
10 #include <hwloc/autogen/config.h>
11 #include <hwloc.h>
12 #include <private/misc.h>
13 #include <private/private.h>
14 #include <hwloc/bitmap.h>
15 
16 #include <stdarg.h>
17 #include <stdio.h>
18 #include <assert.h>
19 #include <errno.h>
20 #include <ctype.h>
21 
22 /* TODO
23  * - have a way to change the initial allocation size
24  * - preallocate inside the bitmap structure (so that the whole structure is a cacheline for instance)
25  *   and allocate a dedicated array only later when reallocating larger
26  */
27 
28 /* magic number */
29 #define HWLOC_BITMAP_MAGIC 0x20091007
30 
31 /* actual opaque type internals */
32 struct hwloc_bitmap_s {
33   unsigned ulongs_count; /* how many ulong bitmasks are valid, >= 1 */
34   unsigned ulongs_allocated; /* how many ulong bitmasks are allocated, >= ulongs_count */
35   unsigned long *ulongs;
36   int infinite; /* set to 1 if all bits beyond ulongs are set */
37 #ifdef HWLOC_DEBUG
38   int magic;
39 #endif
40 };
41 
42 /* overzealous check in debug-mode, not as powerful as valgrind but still useful */
43 #ifdef HWLOC_DEBUG
44 #define HWLOC__BITMAP_CHECK(set) do {                           \
45   assert((set)->magic == HWLOC_BITMAP_MAGIC);                   \
46   assert((set)->ulongs_count >= 1);                             \
47   assert((set)->ulongs_allocated >= (set)->ulongs_count);       \
48 } while (0)
49 #else
50 #define HWLOC__BITMAP_CHECK(set)
51 #endif
52 
53 /* extract a subset from a set using an index or a cpu */
54 #define HWLOC_SUBBITMAP_INDEX(cpu)              ((cpu)/(HWLOC_BITS_PER_LONG))
55 #define HWLOC_SUBBITMAP_CPU_ULBIT(cpu)          ((cpu)%(HWLOC_BITS_PER_LONG))
56 /* Read from a bitmap ulong without knowing whether x is valid.
57  * Writers should make sure that x is valid and modify set->ulongs[x] directly.
58  */
59 #define HWLOC_SUBBITMAP_READULONG(set,x)        ((x) < (set)->ulongs_count ? (set)->ulongs[x] : (set)->infinite ? HWLOC_SUBBITMAP_FULL : HWLOC_SUBBITMAP_ZERO)
60 
61 /* predefined subset values */
62 #define HWLOC_SUBBITMAP_ZERO                    0UL
63 #define HWLOC_SUBBITMAP_FULL                    (~0UL)
64 #define HWLOC_SUBBITMAP_ULBIT(bit)              (1UL<<(bit))
65 #define HWLOC_SUBBITMAP_CPU(cpu)                HWLOC_SUBBITMAP_ULBIT(HWLOC_SUBBITMAP_CPU_ULBIT(cpu))
66 #define HWLOC_SUBBITMAP_ULBIT_TO(bit)           (HWLOC_SUBBITMAP_FULL>>(HWLOC_BITS_PER_LONG-1-(bit)))
67 #define HWLOC_SUBBITMAP_ULBIT_FROM(bit)         (HWLOC_SUBBITMAP_FULL<<(bit))
68 #define HWLOC_SUBBITMAP_ULBIT_FROMTO(begin,end) (HWLOC_SUBBITMAP_ULBIT_TO(end) & HWLOC_SUBBITMAP_ULBIT_FROM(begin))
69 
hwloc_bitmap_alloc(void)70 struct hwloc_bitmap_s * hwloc_bitmap_alloc(void)
71 {
72   struct hwloc_bitmap_s * set;
73 
74   set = malloc(sizeof(struct hwloc_bitmap_s));
75   if (!set)
76     return NULL;
77 
78   set->ulongs_count = 1;
79   set->ulongs_allocated = 64/sizeof(unsigned long);
80   set->ulongs = malloc(64);
81   if (!set->ulongs) {
82     free(set);
83     return NULL;
84   }
85 
86   set->ulongs[0] = HWLOC_SUBBITMAP_ZERO;
87   set->infinite = 0;
88 #ifdef HWLOC_DEBUG
89   set->magic = HWLOC_BITMAP_MAGIC;
90 #endif
91   return set;
92 }
93 
hwloc_bitmap_alloc_full(void)94 struct hwloc_bitmap_s * hwloc_bitmap_alloc_full(void)
95 {
96   struct hwloc_bitmap_s * set = hwloc_bitmap_alloc();
97   if (set) {
98     set->infinite = 1;
99     set->ulongs[0] = HWLOC_SUBBITMAP_FULL;
100   }
101   return set;
102 }
103 
hwloc_bitmap_free(struct hwloc_bitmap_s * set)104 void hwloc_bitmap_free(struct hwloc_bitmap_s * set)
105 {
106   if (!set)
107     return;
108 
109   HWLOC__BITMAP_CHECK(set);
110 #ifdef HWLOC_DEBUG
111   set->magic = 0;
112 #endif
113 
114   free(set->ulongs);
115   free(set);
116 }
117 
118 /* enlarge until it contains at least needed_count ulongs.
119  */
120 static void
hwloc_bitmap_enlarge_by_ulongs(struct hwloc_bitmap_s * set,unsigned needed_count)121 hwloc_bitmap_enlarge_by_ulongs(struct hwloc_bitmap_s * set, unsigned needed_count)
122 {
123   unsigned tmp = 1 << hwloc_flsl((unsigned long) needed_count - 1);
124   if (tmp > set->ulongs_allocated) {
125     set->ulongs = realloc(set->ulongs, tmp * sizeof(unsigned long));
126     assert(set->ulongs);
127     set->ulongs_allocated = tmp;
128   }
129 }
130 
131 /* enlarge until it contains at least needed_count ulongs,
132  * and update new ulongs according to the infinite field.
133  */
134 static void
hwloc_bitmap_realloc_by_ulongs(struct hwloc_bitmap_s * set,unsigned needed_count)135 hwloc_bitmap_realloc_by_ulongs(struct hwloc_bitmap_s * set, unsigned needed_count)
136 {
137   unsigned i;
138 
139   HWLOC__BITMAP_CHECK(set);
140 
141   if (needed_count <= set->ulongs_count)
142     return;
143 
144   /* realloc larger if needed */
145   hwloc_bitmap_enlarge_by_ulongs(set, needed_count);
146 
147   /* fill the newly allocated subset depending on the infinite flag */
148   for(i=set->ulongs_count; i<needed_count; i++)
149     set->ulongs[i] = set->infinite ? HWLOC_SUBBITMAP_FULL : HWLOC_SUBBITMAP_ZERO;
150   set->ulongs_count = needed_count;
151 }
152 
153 /* realloc until it contains at least cpu+1 bits */
154 #define hwloc_bitmap_realloc_by_cpu_index(set, cpu) hwloc_bitmap_realloc_by_ulongs(set, ((cpu)/HWLOC_BITS_PER_LONG)+1)
155 
156 /* reset a bitmap to exactely the needed size.
157  * the caller must reinitialize all ulongs and the infinite flag later.
158  */
159 static void
hwloc_bitmap_reset_by_ulongs(struct hwloc_bitmap_s * set,unsigned needed_count)160 hwloc_bitmap_reset_by_ulongs(struct hwloc_bitmap_s * set, unsigned needed_count)
161 {
162   hwloc_bitmap_enlarge_by_ulongs(set, needed_count);
163   set->ulongs_count = needed_count;
164 }
165 
166 /* reset until it contains exactly cpu+1 bits (roundup to a ulong).
167  * the caller must reinitialize all ulongs and the infinite flag later.
168  */
169 #define hwloc_bitmap_reset_by_cpu_index(set, cpu) hwloc_bitmap_reset_by_ulongs(set, ((cpu)/HWLOC_BITS_PER_LONG)+1)
170 
hwloc_bitmap_dup(const struct hwloc_bitmap_s * old)171 struct hwloc_bitmap_s * hwloc_bitmap_dup(const struct hwloc_bitmap_s * old)
172 {
173   struct hwloc_bitmap_s * new;
174 
175   if (!old)
176     return NULL;
177 
178   HWLOC__BITMAP_CHECK(old);
179 
180   new = malloc(sizeof(struct hwloc_bitmap_s));
181   if (!new)
182     return NULL;
183 
184   new->ulongs = malloc(old->ulongs_allocated * sizeof(unsigned long));
185   if (!new->ulongs) {
186     free(new);
187     return NULL;
188   }
189   new->ulongs_allocated = old->ulongs_allocated;
190   new->ulongs_count = old->ulongs_count;
191   memcpy(new->ulongs, old->ulongs, new->ulongs_count * sizeof(unsigned long));
192   new->infinite = old->infinite;
193 #ifdef HWLOC_DEBUG
194   new->magic = HWLOC_BITMAP_MAGIC;
195 #endif
196   return new;
197 }
198 
hwloc_bitmap_copy(struct hwloc_bitmap_s * dst,const struct hwloc_bitmap_s * src)199 void hwloc_bitmap_copy(struct hwloc_bitmap_s * dst, const struct hwloc_bitmap_s * src)
200 {
201   HWLOC__BITMAP_CHECK(dst);
202   HWLOC__BITMAP_CHECK(src);
203 
204   hwloc_bitmap_reset_by_ulongs(dst, src->ulongs_count);
205 
206   memcpy(dst->ulongs, src->ulongs, src->ulongs_count * sizeof(unsigned long));
207   dst->infinite = src->infinite;
208 }
209 
210 /* Strings always use 32bit groups */
211 #define HWLOC_PRIxSUBBITMAP             "%08lx"
212 #define HWLOC_BITMAP_SUBSTRING_SIZE     32
213 #define HWLOC_BITMAP_SUBSTRING_LENGTH   (HWLOC_BITMAP_SUBSTRING_SIZE/4)
214 #define HWLOC_BITMAP_STRING_PER_LONG    (HWLOC_BITS_PER_LONG/HWLOC_BITMAP_SUBSTRING_SIZE)
215 
hwloc_bitmap_snprintf(char * __hwloc_restrict buf,size_t buflen,const struct hwloc_bitmap_s * __hwloc_restrict set)216 int hwloc_bitmap_snprintf(char * __hwloc_restrict buf, size_t buflen, const struct hwloc_bitmap_s * __hwloc_restrict set)
217 {
218   ssize_t size = buflen;
219   char *tmp = buf;
220   int res, ret = 0;
221   int needcomma = 0;
222   int i;
223   unsigned long accum = 0;
224   int accumed = 0;
225 #if HWLOC_BITS_PER_LONG == HWLOC_BITMAP_SUBSTRING_SIZE
226   const unsigned long accum_mask = ~0UL;
227 #else /* HWLOC_BITS_PER_LONG != HWLOC_BITMAP_SUBSTRING_SIZE */
228   const unsigned long accum_mask = ((1UL << HWLOC_BITMAP_SUBSTRING_SIZE) - 1) << (HWLOC_BITS_PER_LONG - HWLOC_BITMAP_SUBSTRING_SIZE);
229 #endif /* HWLOC_BITS_PER_LONG != HWLOC_BITMAP_SUBSTRING_SIZE */
230 
231   HWLOC__BITMAP_CHECK(set);
232 
233   /* mark the end in case we do nothing later */
234   if (buflen > 0)
235     tmp[0] = '\0';
236 
237   if (set->infinite) {
238     res = hwloc_snprintf(tmp, size, "0xf...f");
239     needcomma = 1;
240     if (res < 0)
241       return -1;
242     ret += res;
243     if (res >= size)
244       res = size>0 ? (int)size - 1 : 0;
245     tmp += res;
246     size -= res;
247   }
248 
249   i=set->ulongs_count-1;
250 
251   if (set->infinite) {
252     /* ignore starting FULL since we have 0xf...f already */
253     while (i>=0 && set->ulongs[i] == HWLOC_SUBBITMAP_FULL)
254       i--;
255   } else {
256     /* ignore starting ZERO except the last one */
257     while (i>=0 && set->ulongs[i] == HWLOC_SUBBITMAP_ZERO)
258       i--;
259   }
260 
261   while (i>=0 || accumed) {
262     /* Refill accumulator */
263     if (!accumed) {
264       accum = set->ulongs[i--];
265       accumed = HWLOC_BITS_PER_LONG;
266     }
267 
268     if (accum & accum_mask) {
269       /* print the whole subset if not empty */
270         res = hwloc_snprintf(tmp, size, needcomma ? ",0x" HWLOC_PRIxSUBBITMAP : "0x" HWLOC_PRIxSUBBITMAP,
271                      (accum & accum_mask) >> (HWLOC_BITS_PER_LONG - HWLOC_BITMAP_SUBSTRING_SIZE));
272       needcomma = 1;
273     } else if (i == -1 && accumed == HWLOC_BITMAP_SUBSTRING_SIZE) {
274       /* print a single 0 to mark the last subset */
275       res = hwloc_snprintf(tmp, size, needcomma ? ",0x0" : "0x0");
276     } else if (needcomma) {
277       res = hwloc_snprintf(tmp, size, ",");
278     } else {
279       res = 0;
280     }
281     if (res < 0)
282       return -1;
283     ret += res;
284 
285 #if HWLOC_BITS_PER_LONG == HWLOC_BITMAP_SUBSTRING_SIZE
286     accum = 0;
287     accumed = 0;
288 #else
289     accum <<= HWLOC_BITMAP_SUBSTRING_SIZE;
290     accumed -= HWLOC_BITMAP_SUBSTRING_SIZE;
291 #endif
292 
293     if (res >= size)
294       res = size>0 ? (int)size - 1 : 0;
295 
296     tmp += res;
297     size -= res;
298   }
299 
300   /* if didn't display anything, display 0x0 */
301   if (!ret) {
302     res = hwloc_snprintf(tmp, size, "0x0");
303     if (res < 0)
304       return -1;
305     ret += res;
306   }
307 
308   return ret;
309 }
310 
hwloc_bitmap_asprintf(char ** strp,const struct hwloc_bitmap_s * __hwloc_restrict set)311 int hwloc_bitmap_asprintf(char ** strp, const struct hwloc_bitmap_s * __hwloc_restrict set)
312 {
313   int len;
314   char *buf;
315 
316   HWLOC__BITMAP_CHECK(set);
317 
318   len = hwloc_bitmap_snprintf(NULL, 0, set);
319   buf = malloc(len+1);
320   *strp = buf;
321   return hwloc_bitmap_snprintf(buf, len+1, set);
322 }
323 
hwloc_bitmap_sscanf(struct hwloc_bitmap_s * set,const char * __hwloc_restrict string)324 int hwloc_bitmap_sscanf(struct hwloc_bitmap_s *set, const char * __hwloc_restrict string)
325 {
326   const char * current = string;
327   unsigned long accum = 0;
328   int count=0;
329   int infinite = 0;
330 
331   /* count how many substrings there are */
332   count++;
333   while ((current = strchr(current+1, ',')) != NULL)
334     count++;
335 
336   current = string;
337   if (!strncmp("0xf...f", current, 7)) {
338     current += 7;
339     if (*current != ',') {
340       /* special case for infinite/full bitmap */
341       hwloc_bitmap_fill(set);
342       return 0;
343     }
344     current++;
345     infinite = 1;
346     count--;
347   }
348 
349   hwloc_bitmap_reset_by_ulongs(set, (count + HWLOC_BITMAP_STRING_PER_LONG - 1) / HWLOC_BITMAP_STRING_PER_LONG);
350   set->infinite = 0;
351 
352   while (*current != '\0') {
353     unsigned long val;
354     char *next;
355     val = strtoul(current, &next, 16);
356 
357     assert(count > 0);
358     count--;
359 
360     accum |= (val << ((count * HWLOC_BITMAP_SUBSTRING_SIZE) % HWLOC_BITS_PER_LONG));
361     if (!(count % HWLOC_BITMAP_STRING_PER_LONG)) {
362       set->ulongs[count / HWLOC_BITMAP_STRING_PER_LONG] = accum;
363       accum = 0;
364     }
365 
366     if (*next != ',') {
367       if (*next || count > 0)
368         goto failed;
369       else
370         break;
371     }
372     current = (const char*) next+1;
373   }
374 
375   set->infinite = infinite; /* set at the end, to avoid spurious realloc with filled new ulongs */
376 
377   return 0;
378 
379  failed:
380   /* failure to parse */
381   hwloc_bitmap_zero(set);
382   return -1;
383 }
384 
hwloc_bitmap_list_snprintf(char * __hwloc_restrict buf,size_t buflen,const struct hwloc_bitmap_s * __hwloc_restrict set)385 int hwloc_bitmap_list_snprintf(char * __hwloc_restrict buf, size_t buflen, const struct hwloc_bitmap_s * __hwloc_restrict set)
386 {
387   int prev = -1;
388   hwloc_bitmap_t reverse;
389   ssize_t size = buflen;
390   char *tmp = buf;
391   int res, ret = 0;
392   int needcomma = 0;
393 
394   HWLOC__BITMAP_CHECK(set);
395 
396   reverse = hwloc_bitmap_alloc(); /* FIXME: add hwloc_bitmap_alloc_size() + hwloc_bitmap_init_allocated() to avoid malloc? */
397   hwloc_bitmap_not(reverse, set);
398 
399   /* mark the end in case we do nothing later */
400   if (buflen > 0)
401     tmp[0] = '\0';
402 
403   while (1) {
404     int begin, end;
405 
406     begin = hwloc_bitmap_next(set, prev);
407     if (begin == -1)
408       break;
409     end = hwloc_bitmap_next(reverse, begin);
410 
411     if (end == begin+1) {
412       res = hwloc_snprintf(tmp, size, needcomma ? ",%d" : "%d", begin);
413     } else if (end == -1) {
414       res = hwloc_snprintf(tmp, size, needcomma ? ",%d-" : "%d-", begin);
415     } else {
416       res = hwloc_snprintf(tmp, size, needcomma ? ",%d-%d" : "%d-%d", begin, end-1);
417     }
418     if (res < 0) {
419       hwloc_bitmap_free(reverse);
420       return -1;
421     }
422     ret += res;
423 
424     if (res >= size)
425       res = size>0 ? (int)size - 1 : 0;
426 
427     tmp += res;
428     size -= res;
429     needcomma = 1;
430 
431     if (end == -1)
432       break;
433     else
434       prev = end - 1;
435   }
436 
437   hwloc_bitmap_free(reverse);
438 
439   return ret;
440 }
441 
hwloc_bitmap_list_asprintf(char ** strp,const struct hwloc_bitmap_s * __hwloc_restrict set)442 int hwloc_bitmap_list_asprintf(char ** strp, const struct hwloc_bitmap_s * __hwloc_restrict set)
443 {
444   int len;
445   char *buf;
446 
447   HWLOC__BITMAP_CHECK(set);
448 
449   len = hwloc_bitmap_list_snprintf(NULL, 0, set);
450   buf = malloc(len+1);
451   *strp = buf;
452   return hwloc_bitmap_list_snprintf(buf, len+1, set);
453 }
454 
hwloc_bitmap_list_sscanf(struct hwloc_bitmap_s * set,const char * __hwloc_restrict string)455 int hwloc_bitmap_list_sscanf(struct hwloc_bitmap_s *set, const char * __hwloc_restrict string)
456 {
457   const char * current = string;
458   char *next;
459   long begin = -1, val;
460 
461   hwloc_bitmap_zero(set);
462 
463   while (*current != '\0') {
464 
465     /* ignore empty ranges */
466     while (*current == ',')
467       current++;
468 
469     val = strtoul(current, &next, 0);
470     /* make sure we got at least one digit */
471     if (next == current)
472       goto failed;
473 
474     if (begin != -1) {
475       /* finishing a range */
476       hwloc_bitmap_set_range(set, begin, val);
477       begin = -1;
478 
479     } else if (*next == '-') {
480       /* starting a new range */
481       if (*(next+1) == '\0') {
482         /* infinite range */
483         hwloc_bitmap_set_range(set, val, -1);
484         break;
485       } else {
486         /* normal range */
487         begin = val;
488       }
489 
490     } else if (*next == ',' || *next == '\0') {
491       /* single digit */
492       hwloc_bitmap_set(set, val);
493     }
494 
495     if (*next == '\0')
496       break;
497     current = next+1;
498   }
499 
500   return 0;
501 
502  failed:
503   /* failure to parse */
504   hwloc_bitmap_zero(set);
505   return -1;
506 }
507 
hwloc_bitmap_taskset_snprintf(char * __hwloc_restrict buf,size_t buflen,const struct hwloc_bitmap_s * __hwloc_restrict set)508 int hwloc_bitmap_taskset_snprintf(char * __hwloc_restrict buf, size_t buflen, const struct hwloc_bitmap_s * __hwloc_restrict set)
509 {
510   ssize_t size = buflen;
511   char *tmp = buf;
512   int res, ret = 0;
513   int started = 0;
514   int i;
515 
516   HWLOC__BITMAP_CHECK(set);
517 
518   /* mark the end in case we do nothing later */
519   if (buflen > 0)
520     tmp[0] = '\0';
521 
522   if (set->infinite) {
523     res = hwloc_snprintf(tmp, size, "0xf...f");
524     started = 1;
525     if (res < 0)
526       return -1;
527     ret += res;
528     if (res >= size)
529       res = size>0 ? (int)size - 1 : 0;
530     tmp += res;
531     size -= res;
532   }
533 
534   i=set->ulongs_count-1;
535 
536   if (set->infinite) {
537     /* ignore starting FULL since we have 0xf...f already */
538     while (i>=0 && set->ulongs[i] == HWLOC_SUBBITMAP_FULL)
539       i--;
540   } else {
541     /* ignore starting ZERO except the last one */
542     while (i>=1 && set->ulongs[i] == HWLOC_SUBBITMAP_ZERO)
543       i--;
544   }
545 
546   while (i>=0) {
547     unsigned long val = set->ulongs[i--];
548     if (started) {
549       /* print the whole subset */
550 #if HWLOC_BITS_PER_LONG == 64
551       res = hwloc_snprintf(tmp, size, "%016lx", val);
552 #else
553       res = hwloc_snprintf(tmp, size, "%08lx", val);
554 #endif
555     } else if (val || i == -1) {
556       res = hwloc_snprintf(tmp, size, "0x%lx", val);
557       started = 1;
558     } else {
559       res = 0;
560     }
561     if (res < 0)
562       return -1;
563     ret += res;
564     if (res >= size)
565       res = size>0 ? (int)size - 1 : 0;
566     tmp += res;
567     size -= res;
568   }
569 
570   /* if didn't display anything, display 0x0 */
571   if (!ret) {
572     res = hwloc_snprintf(tmp, size, "0x0");
573     if (res < 0)
574       return -1;
575     ret += res;
576   }
577 
578   return ret;
579 }
580 
hwloc_bitmap_taskset_asprintf(char ** strp,const struct hwloc_bitmap_s * __hwloc_restrict set)581 int hwloc_bitmap_taskset_asprintf(char ** strp, const struct hwloc_bitmap_s * __hwloc_restrict set)
582 {
583   int len;
584   char *buf;
585 
586   HWLOC__BITMAP_CHECK(set);
587 
588   len = hwloc_bitmap_taskset_snprintf(NULL, 0, set);
589   buf = malloc(len+1);
590   *strp = buf;
591   return hwloc_bitmap_taskset_snprintf(buf, len+1, set);
592 }
593 
hwloc_bitmap_taskset_sscanf(struct hwloc_bitmap_s * set,const char * __hwloc_restrict string)594 int hwloc_bitmap_taskset_sscanf(struct hwloc_bitmap_s *set, const char * __hwloc_restrict string)
595 {
596   const char * current = string;
597   int chars;
598   int count;
599   int infinite = 0;
600 
601   if (!strncmp("0xf...f", current, 7)) {
602     /* infinite bitmap */
603     infinite = 1;
604     current += 7;
605     if (*current == '\0') {
606       /* special case for infinite/full bitmap */
607       hwloc_bitmap_fill(set);
608       return 0;
609     }
610   } else {
611     /* finite bitmap */
612     if (!strncmp("0x", current, 2))
613       current += 2;
614     if (*current == '\0') {
615       /* special case for empty bitmap */
616       hwloc_bitmap_zero(set);
617       return 0;
618     }
619   }
620   /* we know there are other characters now */
621 
622   chars = (int)strlen(current);
623   count = (chars * 4 + HWLOC_BITS_PER_LONG - 1) / HWLOC_BITS_PER_LONG;
624 
625   hwloc_bitmap_reset_by_ulongs(set, count);
626   set->infinite = 0;
627 
628   while (*current != '\0') {
629     int tmpchars;
630     char ustr[17];
631     unsigned long val;
632     char *next;
633 
634     tmpchars = chars % (HWLOC_BITS_PER_LONG/4);
635     if (!tmpchars)
636       tmpchars = (HWLOC_BITS_PER_LONG/4);
637 
638     memcpy(ustr, current, tmpchars);
639     ustr[tmpchars] = '\0';
640     val = strtoul(ustr, &next, 16);
641     if (*next != '\0')
642       goto failed;
643 
644     set->ulongs[count-1] = val;
645 
646     current += tmpchars;
647     chars -= tmpchars;
648     count--;
649   }
650 
651   set->infinite = infinite; /* set at the end, to avoid spurious realloc with filled new ulongs */
652 
653   return 0;
654 
655  failed:
656   /* failure to parse */
657   hwloc_bitmap_zero(set);
658   return -1;
659 }
660 
hwloc_bitmap__zero(struct hwloc_bitmap_s * set)661 static void hwloc_bitmap__zero(struct hwloc_bitmap_s *set)
662 {
663         unsigned i;
664         for(i=0; i<set->ulongs_count; i++)
665                 set->ulongs[i] = HWLOC_SUBBITMAP_ZERO;
666         set->infinite = 0;
667 }
668 
hwloc_bitmap_zero(struct hwloc_bitmap_s * set)669 void hwloc_bitmap_zero(struct hwloc_bitmap_s * set)
670 {
671         HWLOC__BITMAP_CHECK(set);
672 
673         hwloc_bitmap_reset_by_ulongs(set, 1);
674         hwloc_bitmap__zero(set);
675 }
676 
hwloc_bitmap__fill(struct hwloc_bitmap_s * set)677 static void hwloc_bitmap__fill(struct hwloc_bitmap_s * set)
678 {
679         unsigned i;
680         for(i=0; i<set->ulongs_count; i++)
681                 set->ulongs[i] = HWLOC_SUBBITMAP_FULL;
682         set->infinite = 1;
683 }
684 
hwloc_bitmap_fill(struct hwloc_bitmap_s * set)685 void hwloc_bitmap_fill(struct hwloc_bitmap_s * set)
686 {
687         HWLOC__BITMAP_CHECK(set);
688 
689         hwloc_bitmap_reset_by_ulongs(set, 1);
690         hwloc_bitmap__fill(set);
691 }
692 
hwloc_bitmap_from_ulong(struct hwloc_bitmap_s * set,unsigned long mask)693 void hwloc_bitmap_from_ulong(struct hwloc_bitmap_s *set, unsigned long mask)
694 {
695         HWLOC__BITMAP_CHECK(set);
696 
697         hwloc_bitmap_reset_by_ulongs(set, 1);
698         set->ulongs[0] = mask; /* there's always at least one ulong allocated */
699         set->infinite = 0;
700 }
701 
hwloc_bitmap_from_ith_ulong(struct hwloc_bitmap_s * set,unsigned i,unsigned long mask)702 void hwloc_bitmap_from_ith_ulong(struct hwloc_bitmap_s *set, unsigned i, unsigned long mask)
703 {
704         unsigned j;
705 
706         HWLOC__BITMAP_CHECK(set);
707 
708         hwloc_bitmap_reset_by_ulongs(set, i+1);
709         set->ulongs[i] = mask;
710         for(j=0; j<i; j++)
711                 set->ulongs[j] = HWLOC_SUBBITMAP_ZERO;
712         set->infinite = 0;
713 }
714 
hwloc_bitmap_to_ulong(const struct hwloc_bitmap_s * set)715 unsigned long hwloc_bitmap_to_ulong(const struct hwloc_bitmap_s *set)
716 {
717         HWLOC__BITMAP_CHECK(set);
718 
719         return set->ulongs[0]; /* there's always at least one ulong allocated */
720 }
721 
hwloc_bitmap_to_ith_ulong(const struct hwloc_bitmap_s * set,unsigned i)722 unsigned long hwloc_bitmap_to_ith_ulong(const struct hwloc_bitmap_s *set, unsigned i)
723 {
724         HWLOC__BITMAP_CHECK(set);
725 
726         return HWLOC_SUBBITMAP_READULONG(set, i);
727 }
728 
hwloc_bitmap_only(struct hwloc_bitmap_s * set,unsigned cpu)729 void hwloc_bitmap_only(struct hwloc_bitmap_s * set, unsigned cpu)
730 {
731         unsigned index_ = HWLOC_SUBBITMAP_INDEX(cpu);
732 
733         HWLOC__BITMAP_CHECK(set);
734 
735         hwloc_bitmap_reset_by_cpu_index(set, cpu);
736         hwloc_bitmap__zero(set);
737         set->ulongs[index_] |= HWLOC_SUBBITMAP_CPU(cpu);
738 }
739 
hwloc_bitmap_allbut(struct hwloc_bitmap_s * set,unsigned cpu)740 void hwloc_bitmap_allbut(struct hwloc_bitmap_s * set, unsigned cpu)
741 {
742         unsigned index_ = HWLOC_SUBBITMAP_INDEX(cpu);
743 
744         HWLOC__BITMAP_CHECK(set);
745 
746         hwloc_bitmap_reset_by_cpu_index(set, cpu);
747         hwloc_bitmap__fill(set);
748         set->ulongs[index_] &= ~HWLOC_SUBBITMAP_CPU(cpu);
749 }
750 
hwloc_bitmap_set(struct hwloc_bitmap_s * set,unsigned cpu)751 void hwloc_bitmap_set(struct hwloc_bitmap_s * set, unsigned cpu)
752 {
753         unsigned index_ = HWLOC_SUBBITMAP_INDEX(cpu);
754 
755         HWLOC__BITMAP_CHECK(set);
756 
757         /* nothing to do if setting inside the infinite part of the bitmap */
758         if (set->infinite && cpu >= set->ulongs_count * HWLOC_BITS_PER_LONG)
759                 return;
760 
761         hwloc_bitmap_realloc_by_cpu_index(set, cpu);
762         set->ulongs[index_] |= HWLOC_SUBBITMAP_CPU(cpu);
763 }
764 
hwloc_bitmap_set_range(struct hwloc_bitmap_s * set,unsigned begincpu,int _endcpu)765 void hwloc_bitmap_set_range(struct hwloc_bitmap_s * set, unsigned begincpu, int _endcpu)
766 {
767         unsigned i;
768         unsigned beginset,endset;
769         unsigned endcpu = (unsigned) _endcpu;
770 
771         HWLOC__BITMAP_CHECK(set);
772 
773         if (endcpu < begincpu)
774                 return;
775         if (set->infinite && begincpu >= set->ulongs_count * HWLOC_BITS_PER_LONG)
776                 /* setting only in the already-set infinite part, nothing to do */
777                 return;
778 
779         if (_endcpu == -1) {
780                 /* infinite range */
781 
782                 /* make sure we can play with the ulong that contains begincpu */
783                 hwloc_bitmap_realloc_by_cpu_index(set, begincpu);
784                 /* update the ulong that contains begincpu */
785                 beginset = HWLOC_SUBBITMAP_INDEX(begincpu);
786                 set->ulongs[beginset] |= HWLOC_SUBBITMAP_ULBIT_FROM(HWLOC_SUBBITMAP_CPU_ULBIT(begincpu));
787                 /* set ulongs after begincpu if any already allocated */
788                 for(i=beginset+1; i<set->ulongs_count; i++)
789                         set->ulongs[i] = HWLOC_SUBBITMAP_FULL;
790                 /* mark the infinity as set */
791                 set->infinite = 1;
792         } else {
793                 /* finite range */
794 
795                 /* ignore the part of the range that overlaps with the already-set infinite part */
796                 if (set->infinite && endcpu >= set->ulongs_count * HWLOC_BITS_PER_LONG)
797                         endcpu = set->ulongs_count * HWLOC_BITS_PER_LONG - 1;
798                 /* make sure we can play with the ulongs that contain begincpu and endcpu */
799                 hwloc_bitmap_realloc_by_cpu_index(set, endcpu);
800                 /* update first and last ulongs */
801                 beginset = HWLOC_SUBBITMAP_INDEX(begincpu);
802                 endset = HWLOC_SUBBITMAP_INDEX(endcpu);
803                 if (beginset == endset) {
804                         set->ulongs[beginset] |= HWLOC_SUBBITMAP_ULBIT_FROMTO(HWLOC_SUBBITMAP_CPU_ULBIT(begincpu), HWLOC_SUBBITMAP_CPU_ULBIT(endcpu));
805                 } else {
806                         set->ulongs[beginset] |= HWLOC_SUBBITMAP_ULBIT_FROM(HWLOC_SUBBITMAP_CPU_ULBIT(begincpu));
807                         set->ulongs[endset] |= HWLOC_SUBBITMAP_ULBIT_TO(HWLOC_SUBBITMAP_CPU_ULBIT(endcpu));
808                 }
809                 /* set ulongs in the middle of the range */
810                 for(i=beginset+1; i<endset; i++)
811                         set->ulongs[i] = HWLOC_SUBBITMAP_FULL;
812         }
813 }
814 
hwloc_bitmap_set_ith_ulong(struct hwloc_bitmap_s * set,unsigned i,unsigned long mask)815 void hwloc_bitmap_set_ith_ulong(struct hwloc_bitmap_s *set, unsigned i, unsigned long mask)
816 {
817         HWLOC__BITMAP_CHECK(set);
818 
819         hwloc_bitmap_realloc_by_ulongs(set, i+1);
820         set->ulongs[i] = mask;
821 }
822 
hwloc_bitmap_clr(struct hwloc_bitmap_s * set,unsigned cpu)823 void hwloc_bitmap_clr(struct hwloc_bitmap_s * set, unsigned cpu)
824 {
825         unsigned index_ = HWLOC_SUBBITMAP_INDEX(cpu);
826 
827         HWLOC__BITMAP_CHECK(set);
828 
829         /* nothing to do if clearing inside the infinitely-unset part of the bitmap */
830         if (!set->infinite && cpu >= set->ulongs_count * HWLOC_BITS_PER_LONG)
831                 return;
832 
833         hwloc_bitmap_realloc_by_cpu_index(set, cpu);
834         set->ulongs[index_] &= ~HWLOC_SUBBITMAP_CPU(cpu);
835 }
836 
hwloc_bitmap_clr_range(struct hwloc_bitmap_s * set,unsigned begincpu,int _endcpu)837 void hwloc_bitmap_clr_range(struct hwloc_bitmap_s * set, unsigned begincpu, int _endcpu)
838 {
839         unsigned i;
840         unsigned beginset,endset;
841         unsigned endcpu = (unsigned) _endcpu;
842 
843         HWLOC__BITMAP_CHECK(set);
844 
845         if (endcpu < begincpu)
846                 return;
847 
848         if (!set->infinite && begincpu >= set->ulongs_count * HWLOC_BITS_PER_LONG)
849                 /* clearing only in the already-unset infinite part, nothing to do */
850                 return;
851 
852         if (_endcpu == -1) {
853                 /* infinite range */
854 
855                 /* make sure we can play with the ulong that contains begincpu */
856                 hwloc_bitmap_realloc_by_cpu_index(set, begincpu);
857                 /* update the ulong that contains begincpu */
858                 beginset = HWLOC_SUBBITMAP_INDEX(begincpu);
859                 set->ulongs[beginset] &= ~HWLOC_SUBBITMAP_ULBIT_FROM(HWLOC_SUBBITMAP_CPU_ULBIT(begincpu));
860                 /* clear ulong after begincpu if any already allocated */
861                 for(i=beginset+1; i<set->ulongs_count; i++)
862                         set->ulongs[i] = HWLOC_SUBBITMAP_ZERO;
863                 /* mark the infinity as unset */
864                 set->infinite = 0;
865         } else {
866                 /* finite range */
867 
868                 /* ignore the part of the range that overlaps with the already-unset infinite part */
869                 if (!set->infinite && endcpu >= set->ulongs_count * HWLOC_BITS_PER_LONG)
870                         endcpu = set->ulongs_count * HWLOC_BITS_PER_LONG - 1;
871                 /* make sure we can play with the ulongs that contain begincpu and endcpu */
872                 hwloc_bitmap_realloc_by_cpu_index(set, endcpu);
873                 /* update first and last ulongs */
874                 beginset = HWLOC_SUBBITMAP_INDEX(begincpu);
875                 endset = HWLOC_SUBBITMAP_INDEX(endcpu);
876                 if (beginset == endset) {
877                         set->ulongs[beginset] &= ~HWLOC_SUBBITMAP_ULBIT_FROMTO(HWLOC_SUBBITMAP_CPU_ULBIT(begincpu), HWLOC_SUBBITMAP_CPU_ULBIT(endcpu));
878                 } else {
879                         set->ulongs[beginset] &= ~HWLOC_SUBBITMAP_ULBIT_FROM(HWLOC_SUBBITMAP_CPU_ULBIT(begincpu));
880                         set->ulongs[endset] &= ~HWLOC_SUBBITMAP_ULBIT_TO(HWLOC_SUBBITMAP_CPU_ULBIT(endcpu));
881                 }
882                 /* clear ulongs in the middle of the range */
883                 for(i=beginset+1; i<endset; i++)
884                         set->ulongs[i] = HWLOC_SUBBITMAP_ZERO;
885         }
886 }
887 
hwloc_bitmap_isset(const struct hwloc_bitmap_s * set,unsigned cpu)888 int hwloc_bitmap_isset(const struct hwloc_bitmap_s * set, unsigned cpu)
889 {
890         unsigned index_ = HWLOC_SUBBITMAP_INDEX(cpu);
891 
892         HWLOC__BITMAP_CHECK(set);
893 
894         return (HWLOC_SUBBITMAP_READULONG(set, index_) & HWLOC_SUBBITMAP_CPU(cpu)) != 0;
895 }
896 
hwloc_bitmap_iszero(const struct hwloc_bitmap_s * set)897 int hwloc_bitmap_iszero(const struct hwloc_bitmap_s *set)
898 {
899         unsigned i;
900 
901         HWLOC__BITMAP_CHECK(set);
902 
903         if (set->infinite)
904                 return 0;
905         for(i=0; i<set->ulongs_count; i++)
906                 if (set->ulongs[i] != HWLOC_SUBBITMAP_ZERO)
907                         return 0;
908         return 1;
909 }
910 
hwloc_bitmap_isfull(const struct hwloc_bitmap_s * set)911 int hwloc_bitmap_isfull(const struct hwloc_bitmap_s *set)
912 {
913         unsigned i;
914 
915         HWLOC__BITMAP_CHECK(set);
916 
917         if (!set->infinite)
918                 return 0;
919         for(i=0; i<set->ulongs_count; i++)
920                 if (set->ulongs[i] != HWLOC_SUBBITMAP_FULL)
921                         return 0;
922         return 1;
923 }
924 
hwloc_bitmap_isequal(const struct hwloc_bitmap_s * set1,const struct hwloc_bitmap_s * set2)925 int hwloc_bitmap_isequal (const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2)
926 {
927         unsigned count1 = set1->ulongs_count;
928         unsigned count2 = set2->ulongs_count;
929         unsigned min_count = count1 < count2 ? count1 : count2;
930         unsigned i;
931 
932         HWLOC__BITMAP_CHECK(set1);
933         HWLOC__BITMAP_CHECK(set2);
934 
935         for(i=0; i<min_count; i++)
936                 if (set1->ulongs[i] != set2->ulongs[i])
937                         return 0;
938 
939         if (count1 != count2) {
940                 unsigned long w1 = set1->infinite ? HWLOC_SUBBITMAP_FULL : HWLOC_SUBBITMAP_ZERO;
941                 unsigned long w2 = set2->infinite ? HWLOC_SUBBITMAP_FULL : HWLOC_SUBBITMAP_ZERO;
942                 for(i=min_count; i<count1; i++) {
943                         if (set1->ulongs[i] != w2)
944                                 return 0;
945                 }
946                 for(i=min_count; i<count2; i++) {
947                         if (set2->ulongs[i] != w1)
948                                 return 0;
949                 }
950         }
951 
952         if (set1->infinite != set2->infinite)
953                 return 0;
954 
955         return 1;
956 }
957 
hwloc_bitmap_intersects(const struct hwloc_bitmap_s * set1,const struct hwloc_bitmap_s * set2)958 int hwloc_bitmap_intersects (const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2)
959 {
960         unsigned count1 = set1->ulongs_count;
961         unsigned count2 = set2->ulongs_count;
962         unsigned min_count = count1 < count2 ? count1 : count2;
963         unsigned i;
964 
965         HWLOC__BITMAP_CHECK(set1);
966         HWLOC__BITMAP_CHECK(set2);
967 
968         for(i=0; i<min_count; i++)
969                 if (set1->ulongs[i] & set2->ulongs[i])
970                         return 1;
971 
972         if (count1 != count2) {
973                 if (set2->infinite) {
974                         for(i=min_count; i<set1->ulongs_count; i++)
975                                 if (set1->ulongs[i])
976                                         return 1;
977                 }
978                 if (set1->infinite) {
979                         for(i=min_count; i<set2->ulongs_count; i++)
980                                 if (set2->ulongs[i])
981                                         return 1;
982                 }
983         }
984 
985         if (set1->infinite && set2->infinite)
986                 return 1;
987 
988         return 0;
989 }
990 
hwloc_bitmap_isincluded(const struct hwloc_bitmap_s * sub_set,const struct hwloc_bitmap_s * super_set)991 int hwloc_bitmap_isincluded (const struct hwloc_bitmap_s *sub_set, const struct hwloc_bitmap_s *super_set)
992 {
993         unsigned super_count = super_set->ulongs_count;
994         unsigned sub_count = sub_set->ulongs_count;
995         unsigned min_count = super_count < sub_count ? super_count : sub_count;
996         unsigned i;
997 
998         HWLOC__BITMAP_CHECK(sub_set);
999         HWLOC__BITMAP_CHECK(super_set);
1000 
1001         for(i=0; i<min_count; i++)
1002                 if (super_set->ulongs[i] != (super_set->ulongs[i] | sub_set->ulongs[i]))
1003                         return 0;
1004 
1005         if (super_count != sub_count) {
1006                 if (!super_set->infinite)
1007                         for(i=min_count; i<sub_count; i++)
1008                                 if (sub_set->ulongs[i])
1009                                         return 0;
1010                 if (sub_set->infinite)
1011                         for(i=min_count; i<super_count; i++)
1012                                 if (super_set->ulongs[i] != HWLOC_SUBBITMAP_FULL)
1013                                         return 0;
1014         }
1015 
1016         if (sub_set->infinite && !super_set->infinite)
1017                 return 0;
1018 
1019         return 1;
1020 }
1021 
hwloc_bitmap_or(struct hwloc_bitmap_s * res,const struct hwloc_bitmap_s * set1,const struct hwloc_bitmap_s * set2)1022 void hwloc_bitmap_or (struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2)
1023 {
1024         /* cache counts so that we can reset res even if it's also set1 or set2 */
1025         unsigned count1 = set1->ulongs_count;
1026         unsigned count2 = set2->ulongs_count;
1027         unsigned max_count = count1 > count2 ? count1 : count2;
1028         unsigned min_count = count1 + count2 - max_count;
1029         unsigned i;
1030 
1031         HWLOC__BITMAP_CHECK(res);
1032         HWLOC__BITMAP_CHECK(set1);
1033         HWLOC__BITMAP_CHECK(set2);
1034 
1035         hwloc_bitmap_reset_by_ulongs(res, max_count);
1036 
1037         for(i=0; i<min_count; i++)
1038                 res->ulongs[i] = set1->ulongs[i] | set2->ulongs[i];
1039 
1040         if (count1 != count2) {
1041                 if (min_count < count1) {
1042                         if (set2->infinite) {
1043                                 res->ulongs_count = min_count;
1044                         } else {
1045                                 for(i=min_count; i<max_count; i++)
1046                                         res->ulongs[i] = set1->ulongs[i];
1047                         }
1048                 } else {
1049                         if (set1->infinite) {
1050                                 res->ulongs_count = min_count;
1051                         } else {
1052                                 for(i=min_count; i<max_count; i++)
1053                                         res->ulongs[i] = set2->ulongs[i];
1054                         }
1055                 }
1056         }
1057 
1058         res->infinite = set1->infinite || set2->infinite;
1059 }
1060 
hwloc_bitmap_and(struct hwloc_bitmap_s * res,const struct hwloc_bitmap_s * set1,const struct hwloc_bitmap_s * set2)1061 void hwloc_bitmap_and (struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2)
1062 {
1063         /* cache counts so that we can reset res even if it's also set1 or set2 */
1064         unsigned count1 = set1->ulongs_count;
1065         unsigned count2 = set2->ulongs_count;
1066         unsigned max_count = count1 > count2 ? count1 : count2;
1067         unsigned min_count = count1 + count2 - max_count;
1068         unsigned i;
1069 
1070         HWLOC__BITMAP_CHECK(res);
1071         HWLOC__BITMAP_CHECK(set1);
1072         HWLOC__BITMAP_CHECK(set2);
1073 
1074         hwloc_bitmap_reset_by_ulongs(res, max_count);
1075 
1076         for(i=0; i<min_count; i++)
1077                 res->ulongs[i] = set1->ulongs[i] & set2->ulongs[i];
1078 
1079         if (count1 != count2) {
1080                 if (min_count < count1) {
1081                         if (set2->infinite) {
1082                                 for(i=min_count; i<max_count; i++)
1083                                         res->ulongs[i] = set1->ulongs[i];
1084                         } else {
1085                                 res->ulongs_count = min_count;
1086                         }
1087                 } else {
1088                         if (set1->infinite) {
1089                                 for(i=min_count; i<max_count; i++)
1090                                         res->ulongs[i] = set2->ulongs[i];
1091                         } else {
1092                                 res->ulongs_count = min_count;
1093                         }
1094                 }
1095         }
1096 
1097         res->infinite = set1->infinite && set2->infinite;
1098 }
1099 
hwloc_bitmap_andnot(struct hwloc_bitmap_s * res,const struct hwloc_bitmap_s * set1,const struct hwloc_bitmap_s * set2)1100 void hwloc_bitmap_andnot (struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2)
1101 {
1102         /* cache counts so that we can reset res even if it's also set1 or set2 */
1103         unsigned count1 = set1->ulongs_count;
1104         unsigned count2 = set2->ulongs_count;
1105         unsigned max_count = count1 > count2 ? count1 : count2;
1106         unsigned min_count = count1 + count2 - max_count;
1107         unsigned i;
1108 
1109         HWLOC__BITMAP_CHECK(res);
1110         HWLOC__BITMAP_CHECK(set1);
1111         HWLOC__BITMAP_CHECK(set2);
1112 
1113         hwloc_bitmap_reset_by_ulongs(res, max_count);
1114 
1115         for(i=0; i<min_count; i++)
1116                 res->ulongs[i] = set1->ulongs[i] & ~set2->ulongs[i];
1117 
1118         if (count1 != count2) {
1119                 if (min_count < count1) {
1120                         if (!set2->infinite) {
1121                                 for(i=min_count; i<max_count; i++)
1122                                         res->ulongs[i] = set1->ulongs[i];
1123                         } else {
1124                                 res->ulongs_count = min_count;
1125                         }
1126                 } else {
1127                         if (set1->infinite) {
1128                                 for(i=min_count; i<max_count; i++)
1129                                         res->ulongs[i] = ~set2->ulongs[i];
1130                         } else {
1131                                 res->ulongs_count = min_count;
1132                         }
1133                 }
1134         }
1135 
1136         res->infinite = set1->infinite && !set2->infinite;
1137 }
1138 
hwloc_bitmap_xor(struct hwloc_bitmap_s * res,const struct hwloc_bitmap_s * set1,const struct hwloc_bitmap_s * set2)1139 void hwloc_bitmap_xor (struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2)
1140 {
1141         /* cache counts so that we can reset res even if it's also set1 or set2 */
1142         unsigned count1 = set1->ulongs_count;
1143         unsigned count2 = set2->ulongs_count;
1144         unsigned max_count = count1 > count2 ? count1 : count2;
1145         unsigned min_count = count1 + count2 - max_count;
1146         unsigned i;
1147 
1148         HWLOC__BITMAP_CHECK(res);
1149         HWLOC__BITMAP_CHECK(set1);
1150         HWLOC__BITMAP_CHECK(set2);
1151 
1152         hwloc_bitmap_reset_by_ulongs(res, max_count);
1153 
1154         for(i=0; i<min_count; i++)
1155                 res->ulongs[i] = set1->ulongs[i] ^ set2->ulongs[i];
1156 
1157         if (count1 != count2) {
1158                 if (min_count < count1) {
1159                         unsigned long w2 = set2->infinite ? HWLOC_SUBBITMAP_FULL : HWLOC_SUBBITMAP_ZERO;
1160                         for(i=min_count; i<max_count; i++)
1161                                 res->ulongs[i] = set1->ulongs[i] ^ w2;
1162                 } else {
1163                         unsigned long w1 = set1->infinite ? HWLOC_SUBBITMAP_FULL : HWLOC_SUBBITMAP_ZERO;
1164                         for(i=min_count; i<max_count; i++)
1165                                 res->ulongs[i] = set2->ulongs[i] ^ w1;
1166                 }
1167         }
1168 
1169         res->infinite = (!set1->infinite) != (!set2->infinite);
1170 }
1171 
hwloc_bitmap_not(struct hwloc_bitmap_s * res,const struct hwloc_bitmap_s * set)1172 void hwloc_bitmap_not (struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set)
1173 {
1174         unsigned count = set->ulongs_count;
1175         unsigned i;
1176 
1177         HWLOC__BITMAP_CHECK(res);
1178         HWLOC__BITMAP_CHECK(set);
1179 
1180         hwloc_bitmap_reset_by_ulongs(res, count);
1181 
1182         for(i=0; i<count; i++)
1183                 res->ulongs[i] = ~set->ulongs[i];
1184 
1185         res->infinite = !set->infinite;
1186 }
1187 
hwloc_bitmap_first(const struct hwloc_bitmap_s * set)1188 int hwloc_bitmap_first(const struct hwloc_bitmap_s * set)
1189 {
1190         unsigned i;
1191 
1192         HWLOC__BITMAP_CHECK(set);
1193 
1194         for(i=0; i<set->ulongs_count; i++) {
1195                 /* subsets are unsigned longs, use ffsl */
1196                 unsigned long w = set->ulongs[i];
1197                 if (w)
1198                         return hwloc_ffsl(w) - 1 + HWLOC_BITS_PER_LONG*i;
1199         }
1200 
1201         if (set->infinite)
1202                 return set->ulongs_count * HWLOC_BITS_PER_LONG;
1203 
1204         return -1;
1205 }
1206 
hwloc_bitmap_last(const struct hwloc_bitmap_s * set)1207 int hwloc_bitmap_last(const struct hwloc_bitmap_s * set)
1208 {
1209         int i;
1210 
1211         HWLOC__BITMAP_CHECK(set);
1212 
1213         if (set->infinite)
1214                 return -1;
1215 
1216         for(i=set->ulongs_count-1; i>=0; i--) {
1217                 /* subsets are unsigned longs, use flsl */
1218                 unsigned long w = set->ulongs[i];
1219                 if (w)
1220                         return hwloc_flsl(w) - 1 + HWLOC_BITS_PER_LONG*i;
1221         }
1222 
1223         return -1;
1224 }
1225 
hwloc_bitmap_next(const struct hwloc_bitmap_s * set,int prev_cpu)1226 int hwloc_bitmap_next(const struct hwloc_bitmap_s * set, int prev_cpu)
1227 {
1228         unsigned i = HWLOC_SUBBITMAP_INDEX(prev_cpu + 1);
1229 
1230         HWLOC__BITMAP_CHECK(set);
1231 
1232         if (i >= set->ulongs_count) {
1233                 if (set->infinite)
1234                         return prev_cpu + 1;
1235                 else
1236                         return -1;
1237         }
1238 
1239         for(; i<set->ulongs_count; i++) {
1240                 /* subsets are unsigned longs, use ffsl */
1241                 unsigned long w = set->ulongs[i];
1242 
1243                 /* if the prev cpu is in the same word as the possible next one,
1244                    we need to mask out previous cpus */
1245                 if (prev_cpu >= 0 && HWLOC_SUBBITMAP_INDEX((unsigned) prev_cpu) == i)
1246                         w &= ~HWLOC_SUBBITMAP_ULBIT_TO(HWLOC_SUBBITMAP_CPU_ULBIT(prev_cpu));
1247 
1248                 if (w)
1249                         return hwloc_ffsl(w) - 1 + HWLOC_BITS_PER_LONG*i;
1250         }
1251 
1252         if (set->infinite)
1253                 return set->ulongs_count * HWLOC_BITS_PER_LONG;
1254 
1255         return -1;
1256 }
1257 
hwloc_bitmap_singlify(struct hwloc_bitmap_s * set)1258 void hwloc_bitmap_singlify(struct hwloc_bitmap_s * set)
1259 {
1260         unsigned i;
1261         int found = 0;
1262 
1263         HWLOC__BITMAP_CHECK(set);
1264 
1265         for(i=0; i<set->ulongs_count; i++) {
1266                 if (found) {
1267                         set->ulongs[i] = HWLOC_SUBBITMAP_ZERO;
1268                         continue;
1269                 } else {
1270                         /* subsets are unsigned longs, use ffsl */
1271                         unsigned long w = set->ulongs[i];
1272                         if (w) {
1273                                 int _ffs = hwloc_ffsl(w);
1274                                 set->ulongs[i] = HWLOC_SUBBITMAP_CPU(_ffs-1);
1275                                 found = 1;
1276                         }
1277                 }
1278         }
1279 
1280         if (set->infinite) {
1281                 if (found) {
1282                         set->infinite = 0;
1283                 } else {
1284                         /* set the first non allocated bit */
1285                         unsigned first = set->ulongs_count * HWLOC_BITS_PER_LONG;
1286                         set->infinite = 0; /* do not let realloc fill the newly allocated sets */
1287                         hwloc_bitmap_set(set, first);
1288                 }
1289         }
1290 }
1291 
hwloc_bitmap_compare_first(const struct hwloc_bitmap_s * set1,const struct hwloc_bitmap_s * set2)1292 int hwloc_bitmap_compare_first(const struct hwloc_bitmap_s * set1, const struct hwloc_bitmap_s * set2)
1293 {
1294         unsigned count1 = set1->ulongs_count;
1295         unsigned count2 = set2->ulongs_count;
1296         unsigned max_count = count1 > count2 ? count1 : count2;
1297         unsigned min_count = count1 + count2 - max_count;
1298         unsigned i;
1299 
1300         HWLOC__BITMAP_CHECK(set1);
1301         HWLOC__BITMAP_CHECK(set2);
1302 
1303         for(i=0; i<min_count; i++) {
1304                 unsigned long w1 = set1->ulongs[i];
1305                 unsigned long w2 = set2->ulongs[i];
1306                 if (w1 || w2) {
1307                         int _ffs1 = hwloc_ffsl(w1);
1308                         int _ffs2 = hwloc_ffsl(w2);
1309                         /* if both have a bit set, compare for real */
1310                         if (_ffs1 && _ffs2)
1311                                 return _ffs1-_ffs2;
1312                         /* one is empty, and it is considered higher, so reverse-compare them */
1313                         return _ffs2-_ffs1;
1314                 }
1315         }
1316 
1317         if (count1 != count2) {
1318                 if (min_count < count2) {
1319                         for(i=min_count; i<count2; i++) {
1320                                 unsigned long w2 = set2->ulongs[i];
1321                                 if (set1->infinite)
1322                                         return -!(w2 & 1);
1323                                 else if (w2)
1324                                         return 1;
1325                         }
1326                 } else {
1327                         for(i=min_count; i<count1; i++) {
1328                                 unsigned long w1 = set1->ulongs[i];
1329                                 if (set2->infinite)
1330                                         return !(w1 & 1);
1331                                 else if (w1)
1332                                         return -1;
1333                         }
1334                 }
1335         }
1336 
1337         return !!set1->infinite - !!set2->infinite;
1338 }
1339 
hwloc_bitmap_compare(const struct hwloc_bitmap_s * set1,const struct hwloc_bitmap_s * set2)1340 int hwloc_bitmap_compare(const struct hwloc_bitmap_s * set1, const struct hwloc_bitmap_s * set2)
1341 {
1342         unsigned count1 = set1->ulongs_count;
1343         unsigned count2 = set2->ulongs_count;
1344         unsigned max_count = count1 > count2 ? count1 : count2;
1345         unsigned min_count = count1 + count2 - max_count;
1346         int i;
1347 
1348         HWLOC__BITMAP_CHECK(set1);
1349         HWLOC__BITMAP_CHECK(set2);
1350 
1351         if ((!set1->infinite) != (!set2->infinite))
1352                 return !!set1->infinite - !!set2->infinite;
1353 
1354         if (count1 != count2) {
1355                 if (min_count < count2) {
1356                         unsigned long val1 = set1->infinite ? HWLOC_SUBBITMAP_FULL :  HWLOC_SUBBITMAP_ZERO;
1357                         for(i=max_count-1; i>=(signed) min_count; i--) {
1358                                 unsigned long val2 = set2->ulongs[i];
1359                                 if (val1 == val2)
1360                                         continue;
1361                                 return val1 < val2 ? -1 : 1;
1362                         }
1363                 } else {
1364                         unsigned long val2 = set2->infinite ? HWLOC_SUBBITMAP_FULL :  HWLOC_SUBBITMAP_ZERO;
1365                         for(i=max_count-1; i>=(signed) min_count; i--) {
1366                                 unsigned long val1 = set1->ulongs[i];
1367                                 if (val1 == val2)
1368                                         continue;
1369                                 return val1 < val2 ? -1 : 1;
1370                         }
1371                 }
1372         }
1373 
1374         for(i=min_count-1; i>=0; i--) {
1375                 unsigned long val1 = set1->ulongs[i];
1376                 unsigned long val2 = set2->ulongs[i];
1377                 if (val1 == val2)
1378                         continue;
1379                 return val1 < val2 ? -1 : 1;
1380         }
1381 
1382         return 0;
1383 }
1384 
hwloc_bitmap_weight(const struct hwloc_bitmap_s * set)1385 int hwloc_bitmap_weight(const struct hwloc_bitmap_s * set)
1386 {
1387         int weight = 0;
1388         unsigned i;
1389 
1390         HWLOC__BITMAP_CHECK(set);
1391 
1392         if (set->infinite)
1393                 return -1;
1394 
1395         for(i=0; i<set->ulongs_count; i++)
1396                 weight += hwloc_weight_long(set->ulongs[i]);
1397         return weight;
1398 }
1399 
hwloc_bitmap_compare_inclusion(const struct hwloc_bitmap_s * set1,const struct hwloc_bitmap_s * set2)1400 int hwloc_bitmap_compare_inclusion(const struct hwloc_bitmap_s * set1, const struct hwloc_bitmap_s * set2)
1401 {
1402         unsigned max_count = set1->ulongs_count > set2->ulongs_count ? set1->ulongs_count : set2->ulongs_count;
1403         int result = HWLOC_BITMAP_EQUAL; /* means empty sets return equal */
1404         int empty1 = 1;
1405         int empty2 = 1;
1406         unsigned i;
1407 
1408         HWLOC__BITMAP_CHECK(set1);
1409         HWLOC__BITMAP_CHECK(set2);
1410 
1411         for(i=0; i<max_count; i++) {
1412           unsigned long val1 = HWLOC_SUBBITMAP_READULONG(set1, (unsigned) i);
1413           unsigned long val2 = HWLOC_SUBBITMAP_READULONG(set2, (unsigned) i);
1414 
1415           if (!val1) {
1416             if (!val2)
1417               /* both empty, no change */
1418               continue;
1419 
1420             /* val1 empty, val2 not */
1421             if (result == HWLOC_BITMAP_CONTAINS) {
1422               if (!empty2)
1423                 return HWLOC_BITMAP_INTERSECTS;
1424               result = HWLOC_BITMAP_DIFFERENT;
1425             } else if (result == HWLOC_BITMAP_EQUAL) {
1426               result = HWLOC_BITMAP_INCLUDED;
1427             }
1428             /* no change otherwise */
1429 
1430           } else if (!val2) {
1431             /* val2 empty, val1 not */
1432             if (result == HWLOC_BITMAP_INCLUDED) {
1433               if (!empty1)
1434                 return HWLOC_BITMAP_INTERSECTS;
1435               result = HWLOC_BITMAP_DIFFERENT;
1436             } else if (result == HWLOC_BITMAP_EQUAL) {
1437               result = HWLOC_BITMAP_CONTAINS;
1438             }
1439             /* no change otherwise */
1440 
1441           } else if (val1 == val2) {
1442             /* equal and not empty */
1443             if (result == HWLOC_BITMAP_DIFFERENT)
1444               return HWLOC_BITMAP_INTERSECTS;
1445             /* equal/contains/included unchanged */
1446 
1447           } else if ((val1 & val2) == val1) {
1448             /* included and not empty */
1449             if (result == HWLOC_BITMAP_CONTAINS || result == HWLOC_BITMAP_DIFFERENT)
1450               return HWLOC_BITMAP_INTERSECTS;
1451             /* equal/included unchanged */
1452             result = HWLOC_BITMAP_INCLUDED;
1453 
1454           } else if ((val1 & val2) == val2) {
1455             /* contains and not empty */
1456             if (result == HWLOC_BITMAP_INCLUDED || result == HWLOC_BITMAP_DIFFERENT)
1457               return HWLOC_BITMAP_INTERSECTS;
1458             /* equal/contains unchanged */
1459             result = HWLOC_BITMAP_CONTAINS;
1460 
1461           } else if ((val1 & val2) != 0) {
1462             /* intersects and not empty */
1463             return HWLOC_BITMAP_INTERSECTS;
1464 
1465           } else {
1466             /* different and not empty */
1467 
1468             /* equal/included/contains with non-empty sets means intersects */
1469             if (result == HWLOC_BITMAP_EQUAL && !empty1 /* implies !empty2 */)
1470               return HWLOC_BITMAP_INTERSECTS;
1471             if (result == HWLOC_BITMAP_INCLUDED && !empty1)
1472               return HWLOC_BITMAP_INTERSECTS;
1473             if (result == HWLOC_BITMAP_CONTAINS && !empty2)
1474               return HWLOC_BITMAP_INTERSECTS;
1475             /* otherwise means different */
1476             result = HWLOC_BITMAP_DIFFERENT;
1477           }
1478 
1479           empty1 &= !val1;
1480           empty2 &= !val2;
1481         }
1482 
1483         if (!set1->infinite) {
1484           if (set2->infinite) {
1485             /* set2 infinite only */
1486             if (result == HWLOC_BITMAP_CONTAINS) {
1487               if (!empty2)
1488                 return HWLOC_BITMAP_INTERSECTS;
1489               result = HWLOC_BITMAP_DIFFERENT;
1490             } else if (result == HWLOC_BITMAP_EQUAL) {
1491               result = HWLOC_BITMAP_INCLUDED;
1492             }
1493             /* no change otherwise */
1494           }
1495         } else if (!set2->infinite) {
1496           /* set1 infinite only */
1497           if (result == HWLOC_BITMAP_INCLUDED) {
1498             if (!empty1)
1499               return HWLOC_BITMAP_INTERSECTS;
1500             result = HWLOC_BITMAP_DIFFERENT;
1501           } else if (result == HWLOC_BITMAP_EQUAL) {
1502             result = HWLOC_BITMAP_CONTAINS;
1503           }
1504           /* no change otherwise */
1505         } else {
1506           /* both infinite */
1507           if (result == HWLOC_BITMAP_DIFFERENT)
1508             return HWLOC_BITMAP_INTERSECTS;
1509           /* equal/contains/included unchanged */
1510         }
1511 
1512         return result;
1513 }
1514