@@ -355,6 +355,143 @@ int bts(size_t* p, size_t bitnum) pure @system;
355355 assert (array[1 ] == 0x100 );
356356}
357357
358+ /**
359+ * Range over bit set. Each element is the bit number that is set.
360+ *
361+ * This is more efficient than testing each bit in a sparsely populated bit
362+ * set. Note that the first bit in the bit set would be bit 0.
363+ */
364+ struct BitRange
365+ {
366+ // / Number of bits in each size_t
367+ enum bitsPerWord = size_t .sizeof * 8 ;
368+
369+ private
370+ {
371+ const (size_t )* bits; // points at next word of bits to check
372+ size_t cur; // needed to allow searching bits using bsf
373+ size_t idx; // index of current set bit
374+ size_t len; // number of bits in the bit set.
375+ }
376+ @nogc nothrow pure :
377+
378+ /**
379+ * Construct a BitRange.
380+ *
381+ * Params:
382+ * bitarr - The array of bits to iterate over
383+ * numBits - The total number of valid bits in the given bit array
384+ */
385+ this (const (size_t )* bitarr, size_t numBits) @system
386+ {
387+ bits = bitarr;
388+ len = numBits;
389+ if (len)
390+ {
391+ // prime the first bit
392+ cur = * bits++ ^ 1 ;
393+ popFront();
394+ }
395+ }
396+
397+ // / Range functions
398+ size_t front ()
399+ {
400+ assert (! empty);
401+ return idx;
402+ }
403+
404+ // / ditto
405+ bool empty () const
406+ {
407+ return idx >= len;
408+ }
409+
410+ // / ditto
411+ void popFront () @system
412+ {
413+ // clear the current bit
414+ auto curbit = idx % bitsPerWord;
415+ cur ^= size_t (1 ) << curbit;
416+ if (! cur)
417+ {
418+ // find next size_t with set bit
419+ idx -= curbit;
420+ while (! cur)
421+ {
422+ if ((idx += bitsPerWord) >= len)
423+ // now empty
424+ return ;
425+ cur = * bits++ ;
426+ }
427+ idx += bsf(cur);
428+ }
429+ else
430+ {
431+ idx += bsf(cur) - curbit;
432+ }
433+ }
434+ }
435+
436+ // /
437+ @system unittest
438+ {
439+ import core.stdc.stdlib : malloc, free;
440+ import core.stdc.string : memset;
441+
442+ // initialize a bit array
443+ enum nBytes = (100 + BitRange.bitsPerWord - 1 ) / 8 ;
444+ size_t * bitArr = cast (size_t * )malloc(nBytes);
445+ scope (exit) free (bitArr);
446+ memset(bitArr, 0 , nBytes);
447+
448+ // set some bits
449+ bts(bitArr, 48 );
450+ bts(bitArr, 24 );
451+ bts(bitArr, 95 );
452+ bts(bitArr, 78 );
453+
454+ enum sum = 48 + 24 + 95 + 78 ;
455+
456+ // iterate
457+ size_t testSum;
458+ size_t nBits;
459+ foreach (b; BitRange (bitArr, 100 ))
460+ {
461+ testSum += b;
462+ ++ nBits;
463+ }
464+
465+ assert (testSum == sum);
466+ assert (nBits == 4 );
467+ }
468+
469+ @system unittest
470+ {
471+ void testIt (size_t numBits, size_t [] bitsToTest... )
472+ {
473+ import core.stdc.stdlib : malloc, free;
474+ import core.stdc.string : memset;
475+ immutable numBytes = (numBits + size_t .sizeof * 8 - 1 ) / 8 ;
476+ size_t * bitArr = cast (size_t * )malloc(numBytes);
477+ scope (exit) free (bitArr);
478+ memset(bitArr, 0 , numBytes);
479+ foreach (b; bitsToTest)
480+ bts(bitArr, b);
481+ auto br = BitRange(bitArr, numBits);
482+ foreach (b; bitsToTest)
483+ {
484+ assert (! br.empty);
485+ assert (b == br.front);
486+ br.popFront();
487+ }
488+ assert (br.empty);
489+ }
490+
491+ testIt(100 , 0 , 1 , 31 , 63 , 85 );
492+ testIt(100 , 6 , 45 , 89 , 92 , 99 );
493+ }
494+
358495/**
359496 * Swaps bytes in a 4 byte uint end-to-end, i.e. byte 0 becomes
360497 * byte 3, byte 1 becomes byte 2, byte 2 becomes byte 1, byte 3
0 commit comments