| /** | |
| * Implementation of a bit array. | |
| * | |
| * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved | |
| * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) | |
| * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | |
| * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/bitarray.d, root/_bitarray.d) | |
| * Documentation: https://dlang.org/phobos/dmd_root_array.html | |
| * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/bitarray.d | |
| */ | |
| module dmd.root.bitarray; | |
| import core.stdc.stdio; | |
| import core.stdc.string; | |
| import dmd.root.rmem; | |
| struct BitArray | |
| { | |
| alias Chunk_t = size_t; | |
| enum ChunkSize = Chunk_t.sizeof; | |
| enum BitsPerChunk = ChunkSize * 8; | |
| size_t length() const @nogc nothrow pure @safe | |
| { | |
| return len; | |
| } | |
| void length(size_t nlen) nothrow pure | |
| { | |
| immutable ochunks = chunks(len); | |
| immutable nchunks = chunks(nlen); | |
| if (ochunks != nchunks) | |
| { | |
| ptr = cast(size_t*)mem.xrealloc_noscan(ptr, nchunks * ChunkSize); | |
| } | |
| if (nchunks > ochunks) | |
| ptr[ochunks .. nchunks] = 0; | |
| if (nlen & (BitsPerChunk - 1)) | |
| ptr[nchunks - 1] &= (cast(Chunk_t)1 << (nlen & (BitsPerChunk - 1))) - 1; | |
| len = nlen; | |
| } | |
| void opAssign(const ref BitArray b) nothrow pure | |
| { | |
| if (!len) | |
| length(b.len); | |
| assert(len == b.len); | |
| memcpy(ptr, b.ptr, bytes(len)); | |
| } | |
| bool opIndex(size_t idx) const @nogc nothrow pure | |
| { | |
| import core.bitop : bt; | |
| assert(idx < len); | |
| return !!bt(ptr, idx); | |
| } | |
| void opIndexAssign(bool val, size_t idx) @nogc nothrow pure | |
| { | |
| import core.bitop : btc, bts; | |
| assert(idx < len); | |
| if (val) | |
| bts(ptr, idx); | |
| else | |
| btc(ptr, idx); | |
| } | |
| bool opEquals(const ref BitArray b) const @nogc nothrow pure | |
| { | |
| return len == b.len && memcmp(ptr, b.ptr, bytes(len)) == 0; | |
| } | |
| void zero() @nogc nothrow pure | |
| { | |
| memset(ptr, 0, bytes(len)); | |
| } | |
| /****** | |
| * Returns: | |
| * true if no bits are set | |
| */ | |
| bool isZero() @nogc nothrow pure | |
| { | |
| const nchunks = chunks(len); | |
| foreach (i; 0 .. nchunks) | |
| { | |
| if (ptr[i]) | |
| return false; | |
| } | |
| return true; | |
| } | |
| void or(const ref BitArray b) @nogc nothrow pure | |
| { | |
| assert(len == b.len); | |
| const nchunks = chunks(len); | |
| foreach (i; 0 .. nchunks) | |
| ptr[i] |= b.ptr[i]; | |
| } | |
| /* Swap contents of `this` with `b` | |
| */ | |
| void swap(ref BitArray b) @nogc nothrow pure | |
| { | |
| assert(len == b.len); | |
| const nchunks = chunks(len); | |
| foreach (i; 0 .. nchunks) | |
| { | |
| const chunk = ptr[i]; | |
| ptr[i] = b.ptr[i]; | |
| b.ptr[i] = chunk; | |
| } | |
| } | |
| ~this() nothrow pure | |
| { | |
| debug | |
| { | |
| // Stomp the allocated memory | |
| const nchunks = chunks(len); | |
| foreach (i; 0 .. nchunks) | |
| { | |
| ptr[i] = cast(Chunk_t)0xFEFEFEFE_FEFEFEFE; | |
| } | |
| } | |
| mem.xfree(ptr); | |
| debug | |
| { | |
| // Set to implausible values | |
| len = cast(size_t)0xFEFEFEFE_FEFEFEFE; | |
| ptr = cast(size_t*)cast(size_t)0xFEFEFEFE_FEFEFEFE; | |
| } | |
| } | |
| private: | |
| size_t len; // length in bits | |
| size_t *ptr; | |
| /// Returns: The amount of chunks used to store len bits | |
| static size_t chunks(const size_t len) @nogc nothrow pure @safe | |
| { | |
| return (len + BitsPerChunk - 1) / BitsPerChunk; | |
| } | |
| /// Returns: The amount of bytes used to store len bits | |
| static size_t bytes(const size_t len) @nogc nothrow pure @safe | |
| { | |
| return chunks(len) * ChunkSize; | |
| } | |
| } | |
| nothrow pure unittest | |
| { | |
| BitArray array; | |
| array.length = 20; | |
| assert(array[19] == 0); | |
| array[10] = 1; | |
| assert(array[10] == 1); | |
| array[10] = 0; | |
| assert(array[10] == 0); | |
| assert(array.length == 20); | |
| BitArray a,b; | |
| assert(a != array); | |
| a.length = 200; | |
| assert(a != array); | |
| assert(a.isZero()); | |
| a[100] = true; | |
| b.length = 200; | |
| b[100] = true; | |
| assert(a == b); | |
| a.length = 300; | |
| b.length = 300; | |
| assert(a == b); | |
| b[299] = true; | |
| assert(a != b); | |
| assert(!a.isZero()); | |
| a.swap(b); | |
| assert(a[299] == true); | |
| assert(b[299] == false); | |
| a = b; | |
| assert(a == b); | |
| } |