/** * This module contains a collection of bit-level operations. * * Copyright: Copyright Don Clugston 2005 - 2013. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Don Clugston, Sean Kelly, Walter Bright, Alex Rønne Petersen, Thomas Stuart Bockman * Source: $(DRUNTIMESRC core/_bitop.d) */ module core.bitop; nothrow:@safe:@nogc: version (D_InlineAsm_X86_64) version = AsmX86;else version (D_InlineAsm_X86) version = AsmX86; version (X86_64) version = AnyX86;else version (X86) version = AnyX86; // Use to implement 64-bit bitops on 32-bit arch.private union Split64{ ulong u64; struct { version (LittleEndian) { uint lo; uint hi; } else { uint hi; uint lo; } } pragma(inline, true) this(ulong u64) @safe pure nothrow @nogc { if (__ctfe) { lo = cast(uint) u64; hi = cast(uint) (u64 >>> 32); } else this.u64 = u64; }} unittest{ const rt = Split64(1); assert((rt.lo == 1) && (rt.hi == 0)); enum ct = Split64(1); assert((ct.lo == rt.lo) && (ct.hi == rt.hi));} /** * Scans the bits in v starting with bit 0, looking * for the first set bit. * Returns: * The bit number of the first bit set. * The return value is undefined if v is zero. */int bsf(uint v) pure{ pragma(inline, false); // so intrinsic detection will work return softBsf!uint(v);} /// dittoint bsf(ulong v) pure{ static if (size_t.sizeof == ulong.sizeof) // 64 bit code gen { pragma(inline, false); // so intrinsic detection will work return softBsf!ulong(v); } else { /* intrinsic not available for 32 bit code, * make do with 32 bit bsf */ const sv = Split64(v); return (sv.lo == 0)? bsf(sv.hi) + 32 : bsf(sv.lo); }} ///unittest{ assert(bsf(0x21) == 0); assert(bsf(ulong.max << 39) == 39);} unittest{ // Make sure bsf() is available at CTFE enum test_ctfe = bsf(ulong.max); assert(test_ctfe == 0);} /** * Scans the bits in v from the most significant bit * to the least significant bit, looking * for the first set bit. * Returns: * The bit number of the first bit set. * The return value is undefined if v is zero. */int bsr(uint v) pure{ pragma(inline, false); // so intrinsic detection will work return softBsr!uint(v);} /// dittoint bsr(ulong v) pure{ static if (size_t.sizeof == ulong.sizeof) // 64 bit code gen { pragma(inline, false); // so intrinsic detection will work return softBsr!ulong(v); } else { /* intrinsic not available for 32 bit code, * make do with 32 bit bsr */ const sv = Split64(v); return (sv.hi == 0)? bsr(sv.lo) : bsr(sv.hi) + 32; }} ///unittest{ assert(bsr(0x21) == 5); assert(bsr((ulong.max >> 15) - 1) == 48);} unittest{ // Make sure bsr() is available at CTFE enum test_ctfe = bsr(ulong.max); assert(test_ctfe == 63);} private alias softBsf(N) = softScan!(N, true);private alias softBsr(N) = softScan!(N, false); /* Shared software fallback implementation for bit scan foward and reverse. If forward is true, bsf is computed (the index of the first set bit).If forward is false, bsr is computed (the index of the last set bit). -1 is returned if no bits are set (v == 0).*/private int softScan(N, bool forward)(N v) pure if (is(N == uint) || is(N == ulong)){ // bsf() and bsr() are officially undefined for v == 0. if (!v) return -1; // This is essentially an unrolled binary search: enum mask(ulong lo) = forward ? cast(N) lo : cast(N)~lo; enum inc(int up) = forward ? up : -up; N x; int ret; static if (is(N == ulong)) { x = v & mask!0x0000_0000_FFFF_FFFFL; if (x) { v = x; ret = forward ? 0 : 63; } else ret = forward ? 32 : 31; x = v & mask!0x0000_FFFF_0000_FFFFL; if (x) v = x; else ret += inc!16; } else static if (is(N == uint)) { x = v & mask!0x0000_FFFF; if (x) { v = x; ret = forward ? 0 : 31; } else ret = forward ? 16 : 15; } else static assert(false); x = v & mask!0x00FF_00FF_00FF_00FFL; if (x) v = x; else ret += inc!8; x = v & mask!0x0F0F_0F0F_0F0F_0F0FL; if (x) v = x; else ret += inc!4; x = v & mask!0x3333_3333_3333_3333L; if (x) v = x; else ret += inc!2; x = v & mask!0x5555_5555_5555_5555L; if (!x) ret += inc!1; return ret;} unittest{ assert(softBsf!uint(0u) == -1); assert(softBsr!uint(0u) == -1); assert(softBsf!ulong(0uL) == -1); assert(softBsr!ulong(0uL) == -1); assert(softBsf!uint(0x0031_A000) == 13); assert(softBsr!uint(0x0031_A000) == 21); assert(softBsf!ulong(0x0000_0001_8000_0000L) == 31); assert(softBsr!ulong(0x0000_0001_8000_0000L) == 32); foreach (b; 0 .. 64) { if (b < 32) { assert(softBsf!uint(1u << b) == b); assert(softBsr!uint(1u << b) == b); } assert(softBsf!ulong(1uL << b) == b); assert(softBsr!ulong(1uL << b) == b); }} /** * Tests the bit. * (No longer an intrisic - the compiler recognizes the patterns * in the body.) */int bt(const scope size_t* p, size_t bitnum) pure @system{ static if (size_t.sizeof == 8) return ((p[bitnum >> 6] & (1L << (bitnum & 63)))) != 0; else static if (size_t.sizeof == 4) return ((p[bitnum >> 5] & (1 << (bitnum & 31)))) != 0; else static assert(0);}///@system pure unittest{ size_t[2] array; array[0] = 2; array[1] = 0x100; assert(bt(array.ptr, 1)); assert(array[0] == 2); assert(array[1] == 0x100);} /** * Tests and complements the bit. */int btc(size_t* p, size_t bitnum) pure @system{ static if (size_t.sizeof == 8) { int result = ((p[bitnum >> 6] & (1L << (bitnum & 63)))) != 0; p[bitnum >> 6] ^= (1L << (bitnum & 63)); return result; } else static if (size_t.sizeof == 4) { int result = ((p[bitnum >> 5] & (1L << (bitnum & 31)))) != 0; p[bitnum >> 5] ^= (1L << (bitnum & 31)); return result; } else static assert(0);} /** * Tests and resets (sets to 0) the bit. */int btr(size_t* p, size_t bitnum) pure @system{ static if (size_t.sizeof == 8) { int result = ((p[bitnum >> 6] & (1L << (bitnum & 63)))) != 0; p[bitnum >> 6] &= ~(1L << (bitnum & 63)); return result; } else static if (size_t.sizeof == 4) { int result = ((p[bitnum >> 5] & (1L << (bitnum & 31)))) != 0; p[bitnum >> 5] &= ~(1L << (bitnum & 31)); return result; } else static assert(0);} /** * Tests and sets the bit. * Params: * p = a non-NULL pointer to an array of size_ts. * bitnum = a bit number, starting with bit 0 of p[0], * and progressing. It addresses bits like the expression:---p[index / (size_t.sizeof*8)] & (1 << (index & ((size_t.sizeof*8) - 1)))--- * Returns: * A non-zero value if the bit was set, and a zero * if it was clear. */int bts(size_t* p, size_t bitnum) pure @system{ static if (size_t.sizeof == 8) { int result = ((p[bitnum >> 6] & (1L << (bitnum & 63)))) != 0; p[bitnum >> 6] |= (1L << (bitnum & 63)); return result; } else static if (size_t.sizeof == 4) { int result = ((p[bitnum >> 5] & (1L << (bitnum & 31)))) != 0; p[bitnum >> 5] |= (1L << (bitnum & 31)); return result; } else static assert(0);} ///@system pure unittest{ size_t[2] array; array[0] = 2; array[1] = 0x100; assert(btc(array.ptr, 35) == 0); if (size_t.sizeof == 8) { assert(array[0] == 0x8_0000_0002); assert(array[1] == 0x100); } else { assert(array[0] == 2); assert(array[1] == 0x108); } assert(btc(array.ptr, 35)); assert(array[0] == 2); assert(array[1] == 0x100); assert(bts(array.ptr, 35) == 0); if (size_t.sizeof == 8) { assert(array[0] == 0x8_0000_0002); assert(array[1] == 0x100); } else { assert(array[0] == 2); assert(array[1] == 0x108); } assert(btr(array.ptr, 35)); assert(array[0] == 2); assert(array[1] == 0x100);} /** * Range over bit set. Each element is the bit number that is set. * * This is more efficient than testing each bit in a sparsely populated bit * set. Note that the first bit in the bit set would be bit 0. */struct BitRange{ /// Number of bits in each size_t enum bitsPerWord = size_t.sizeof * 8; private { const(size_t)*bits; // points at next word of bits to check size_t cur; // needed to allow searching bits using bsf size_t idx; // index of current set bit size_t len; // number of bits in the bit set. } @nogc nothrow pure: /** * Construct a BitRange. * * Params: * bitarr = The array of bits to iterate over * numBits = The total number of valid bits in the given bit array */ this(const(size_t)* bitarr, size_t numBits) @system { bits = bitarr; len = numBits; if (len) { // prime the first bit cur = *bits++ ^ 1; popFront(); } } /// Range functions size_t front() { assert(!empty); return idx; } /// ditto bool empty() const { return idx >= len; } /// ditto void popFront() @system { // clear the current bit auto curbit = idx % bitsPerWord; cur ^= size_t(1) << curbit; if (!cur) { // find next size_t with set bit idx -= curbit; while (!cur) { if ((idx += bitsPerWord) >= len) // now empty return; cur = *bits++; } idx += bsf(cur); } else { idx += bsf(cur) - curbit; } }} ///@system unittest{ import core.stdc.stdlib : malloc, free; import core.stdc.string : memset; // initialize a bit array enum nBytes = (100 + BitRange.bitsPerWord - 1) / 8; size_t *bitArr = cast(size_t *)malloc(nBytes); scope(exit) free(bitArr); memset(bitArr, 0, nBytes); // set some bits bts(bitArr, 48); bts(bitArr, 24); bts(bitArr, 95);Lines 1–500 of 1055. Load more
/** * This module contains a collection of bit-level operations. * * Copyright: Copyright Don Clugston 2005 - 2013. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Don Clugston, Sean Kelly, Walter Bright, Alex Rønne Petersen, Thomas Stuart Bockman * Source: $(DRUNTIMESRC core/_bitop.d) */ module core.bitop; nothrow: @safe: @nogc: version (D_InlineAsm_X86_64) version = AsmX86; else version (D_InlineAsm_X86) version = AsmX86; version (X86_64) version = AnyX86; else version (X86) version = AnyX86; // Use to implement 64-bit bitops on 32-bit arch. private union Split64 { ulong u64; struct { version (LittleEndian) { uint lo; uint hi; } else { uint hi; uint lo; } } pragma(inline, true) this(ulong u64) @safe pure nothrow @nogc { if (__ctfe) { lo = cast(uint) u64; hi = cast(uint) (u64 >>> 32); } else this.u64 = u64; } } unittest { const rt = Split64(1); assert((rt.lo == 1) && (rt.hi == 0)); enum ct = Split64(1); assert((ct.lo == rt.lo) && (ct.hi == rt.hi)); } /** * Scans the bits in v starting with bit 0, looking * for the first set bit. * Returns: * The bit number of the first bit set. * The return value is undefined if v is zero. */ int bsf(uint v) pure { pragma(inline, false); // so intrinsic detection will work return softBsf!uint(v); } /// ditto int bsf(ulong v) pure { static if (size_t.sizeof == ulong.sizeof) // 64 bit code gen { pragma(inline, false); // so intrinsic detection will work return softBsf!ulong(v); } else { /* intrinsic not available for 32 bit code, * make do with 32 bit bsf */ const sv = Split64(v); return (sv.lo == 0)? bsf(sv.hi) + 32 : bsf(sv.lo); } } /// unittest { assert(bsf(0x21) == 0); assert(bsf(ulong.max << 39) == 39); } unittest { // Make sure bsf() is available at CTFE enum test_ctfe = bsf(ulong.max); assert(test_ctfe == 0); } /** * Scans the bits in v from the most significant bit * to the least significant bit, looking * for the first set bit. * Returns: * The bit number of the first bit set. * The return value is undefined if v is zero. */ int bsr(uint v) pure { pragma(inline, false); // so intrinsic detection will work return softBsr!uint(v); } /// ditto int bsr(ulong v) pure { static if (size_t.sizeof == ulong.sizeof) // 64 bit code gen { pragma(inline, false); // so intrinsic detection will work return softBsr!ulong(v); } else { /* intrinsic not available for 32 bit code, * make do with 32 bit bsr */ const sv = Split64(v); return (sv.hi == 0)? bsr(sv.lo) : bsr(sv.hi) + 32; } } /// unittest { assert(bsr(0x21) == 5); assert(bsr((ulong.max >> 15) - 1) == 48); } unittest { // Make sure bsr() is available at CTFE enum test_ctfe = bsr(ulong.max); assert(test_ctfe == 63); } private alias softBsf(N) = softScan!(N, true); private alias softBsr(N) = softScan!(N, false); /* Shared software fallback implementation for bit scan foward and reverse. If forward is true, bsf is computed (the index of the first set bit). If forward is false, bsr is computed (the index of the last set bit). -1 is returned if no bits are set (v == 0). */ private int softScan(N, bool forward)(N v) pure if (is(N == uint) || is(N == ulong)) { // bsf() and bsr() are officially undefined for v == 0. if (!v) return -1; // This is essentially an unrolled binary search: enum mask(ulong lo) = forward ? cast(N) lo : cast(N)~lo; enum inc(int up) = forward ? up : -up; N x; int ret; static if (is(N == ulong)) { x = v & mask!0x0000_0000_FFFF_FFFFL; if (x) { v = x; ret = forward ? 0 : 63; } else ret = forward ? 32 : 31; x = v & mask!0x0000_FFFF_0000_FFFFL; if (x) v = x; else ret += inc!16; } else static if (is(N == uint)) { x = v & mask!0x0000_FFFF; if (x) { v = x; ret = forward ? 0 : 31; } else ret = forward ? 16 : 15; } else static assert(false); x = v & mask!0x00FF_00FF_00FF_00FFL; if (x) v = x; else ret += inc!8; x = v & mask!0x0F0F_0F0F_0F0F_0F0FL; if (x) v = x; else ret += inc!4; x = v & mask!0x3333_3333_3333_3333L; if (x) v = x; else ret += inc!2; x = v & mask!0x5555_5555_5555_5555L; if (!x) ret += inc!1; return ret; } unittest { assert(softBsf!uint(0u) == -1); assert(softBsr!uint(0u) == -1); assert(softBsf!ulong(0uL) == -1); assert(softBsr!ulong(0uL) == -1); assert(softBsf!uint(0x0031_A000) == 13); assert(softBsr!uint(0x0031_A000) == 21); assert(softBsf!ulong(0x0000_0001_8000_0000L) == 31); assert(softBsr!ulong(0x0000_0001_8000_0000L) == 32); foreach (b; 0 .. 64) { if (b < 32) { assert(softBsf!uint(1u << b) == b); assert(softBsr!uint(1u << b) == b); } assert(softBsf!ulong(1uL << b) == b); assert(softBsr!ulong(1uL << b) == b); } } /** * Tests the bit. * (No longer an intrisic - the compiler recognizes the patterns * in the body.) */ int bt(const scope size_t* p, size_t bitnum) pure @system { static if (size_t.sizeof == 8) return ((p[bitnum >> 6] & (1L << (bitnum & 63)))) != 0; else static if (size_t.sizeof == 4) return ((p[bitnum >> 5] & (1 << (bitnum & 31)))) != 0; else static assert(0); } /// @system pure unittest { size_t[2] array; array[0] = 2; array[1] = 0x100; assert(bt(array.ptr, 1)); assert(array[0] == 2); assert(array[1] == 0x100); } /** * Tests and complements the bit. */ int btc(size_t* p, size_t bitnum) pure @system { static if (size_t.sizeof == 8) { int result = ((p[bitnum >> 6] & (1L << (bitnum & 63)))) != 0; p[bitnum >> 6] ^= (1L << (bitnum & 63)); return result; } else static if (size_t.sizeof == 4) { int result = ((p[bitnum >> 5] & (1L << (bitnum & 31)))) != 0; p[bitnum >> 5] ^= (1L << (bitnum & 31)); return result; } else static assert(0); } /** * Tests and resets (sets to 0) the bit. */ int btr(size_t* p, size_t bitnum) pure @system { static if (size_t.sizeof == 8) { int result = ((p[bitnum >> 6] & (1L << (bitnum & 63)))) != 0; p[bitnum >> 6] &= ~(1L << (bitnum & 63)); return result; } else static if (size_t.sizeof == 4) { int result = ((p[bitnum >> 5] & (1L << (bitnum & 31)))) != 0; p[bitnum >> 5] &= ~(1L << (bitnum & 31)); return result; } else static assert(0); } /** * Tests and sets the bit. * Params: * p = a non-NULL pointer to an array of size_ts. * bitnum = a bit number, starting with bit 0 of p[0], * and progressing. It addresses bits like the expression: --- p[index / (size_t.sizeof*8)] & (1 << (index & ((size_t.sizeof*8) - 1))) --- * Returns: * A non-zero value if the bit was set, and a zero * if it was clear. */ int bts(size_t* p, size_t bitnum) pure @system { static if (size_t.sizeof == 8) { int result = ((p[bitnum >> 6] & (1L << (bitnum & 63)))) != 0; p[bitnum >> 6] |= (1L << (bitnum & 63)); return result; } else static if (size_t.sizeof == 4) { int result = ((p[bitnum >> 5] & (1L << (bitnum & 31)))) != 0; p[bitnum >> 5] |= (1L << (bitnum & 31)); return result; } else static assert(0); } /// @system pure unittest { size_t[2] array; array[0] = 2; array[1] = 0x100; assert(btc(array.ptr, 35) == 0); if (size_t.sizeof == 8) { assert(array[0] == 0x8_0000_0002); assert(array[1] == 0x100); } else { assert(array[0] == 2); assert(array[1] == 0x108); } assert(btc(array.ptr, 35)); assert(array[0] == 2); assert(array[1] == 0x100); assert(bts(array.ptr, 35) == 0); if (size_t.sizeof == 8) { assert(array[0] == 0x8_0000_0002); assert(array[1] == 0x100); } else { assert(array[0] == 2); assert(array[1] == 0x108); } assert(btr(array.ptr, 35)); assert(array[0] == 2); assert(array[1] == 0x100); } /** * Range over bit set. Each element is the bit number that is set. * * This is more efficient than testing each bit in a sparsely populated bit * set. Note that the first bit in the bit set would be bit 0. */ struct BitRange { /// Number of bits in each size_t enum bitsPerWord = size_t.sizeof * 8; private { const(size_t)*bits; // points at next word of bits to check size_t cur; // needed to allow searching bits using bsf size_t idx; // index of current set bit size_t len; // number of bits in the bit set. } @nogc nothrow pure: /** * Construct a BitRange. * * Params: * bitarr = The array of bits to iterate over * numBits = The total number of valid bits in the given bit array */ this(const(size_t)* bitarr, size_t numBits) @system { bits = bitarr; len = numBits; if (len) { // prime the first bit cur = *bits++ ^ 1; popFront(); } } /// Range functions size_t front() { assert(!empty); return idx; } /// ditto bool empty() const { return idx >= len; } /// ditto void popFront() @system { // clear the current bit auto curbit = idx % bitsPerWord; cur ^= size_t(1) << curbit; if (!cur) { // find next size_t with set bit idx -= curbit; while (!cur) { if ((idx += bitsPerWord) >= len) // now empty return; cur = *bits++; } idx += bsf(cur); } else { idx += bsf(cur) - curbit; } } } /// @system unittest { import core.stdc.stdlib : malloc, free; import core.stdc.string : memset; // initialize a bit array enum nBytes = (100 + BitRange.bitsPerWord - 1) / 8; size_t *bitArr = cast(size_t *)malloc(nBytes); scope(exit) free(bitArr); memset(bitArr, 0, nBytes); // set some bits bts(bitArr, 48); bts(bitArr, 24); bts(bitArr, 95);