Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 0c912c4

Browse files
authored
Merge pull request #1602 from schveiguy/fixcycles
Fix issue 16211 - Cyclic dependencies broken again
2 parents ac56312 + 50a40f7 commit 0c912c4

File tree

2 files changed

+534
-167
lines changed

2 files changed

+534
-167
lines changed

src/core/bitop.d

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)