diff --git a/packages/stdlib/src/bits/vector/index.test.ts b/packages/stdlib/src/bits/vector/index.test.ts new file mode 100644 index 0000000..7940e71 --- /dev/null +++ b/packages/stdlib/src/bits/vector/index.test.ts @@ -0,0 +1,57 @@ +import { describe, it, expect } from 'vitest'; +import { BitVector } from '.'; + +describe('BitVector', () => { + it('should initialize with the correct size', () => { + const size = 16; + const expectedSize = Math.ceil(size / 8); + const bitVector = new BitVector(size); + + expect(bitVector.length).toBe(expectedSize); + }); + + it('should set and get bits correctly', () => { + const bitVector = new BitVector(16); + bitVector.setBit(5); + + expect(bitVector.getBit(5)).toBe(true); + expect(bitVector.getBit(4)).toBe(false); + }); + + it('should clear bits correctly', () => { + const bitVector = new BitVector(16); + bitVector.setBit(5); + + expect(bitVector.getBit(5)).toBe(true); + + bitVector.clearBit(5); + + expect(bitVector.getBit(5)).toBe(false); + }); + + it('should find the previous bit correctly', () => { + const bitVector = new BitVector(100); + const indices = [99, 88, 66, 65, 64, 63, 15, 14, 1, 0]; + const result = []; + indices.forEach(index => bitVector.setBit(index)); + + for (let i = bitVector.previousBit(100); i !== -1; i = bitVector.previousBit(i)) { + result.push(i); + } + + expect(result).toEqual(indices); + }); + + it('should return -1 when no previous bit is found', () => { + const bitVector = new BitVector(16); + + expect(bitVector.previousBit(0)).toBe(-1); + }); + + it('should throw RangeError when previousBit is called with an unreachable value', () => { + const bitVector = new BitVector(16); + bitVector.setBit(5); + + expect(() => bitVector.previousBit(24)).toThrow(new RangeError('Unreachable value')); + }); +}); \ No newline at end of file diff --git a/packages/stdlib/src/bits/vector/index.ts b/packages/stdlib/src/bits/vector/index.ts new file mode 100644 index 0000000..aa1c745 --- /dev/null +++ b/packages/stdlib/src/bits/vector/index.ts @@ -0,0 +1,61 @@ +export interface BitVector { + getBit(index: number): boolean; + setBit(index: number): void; + clearBit(index: number): void; + previousBit(index: number): number; +} + +/** + * @name BitVector + * @category Bits + * @description A bit vector is a vector of bits that can be used to store a collection of bits + * + * @since 0.0.3 + */ +export class BitVector extends Uint8Array implements BitVector { + constructor(size: number) { + super(Math.ceil(size / 8)); + } + + getBit(index: number) { + const value = this[index >> 3]! & (1 << (index & 7)); + return value !== 0; + } + + setBit(index: number) { + this[index >> 3]! |= 1 << (index & 7); + } + + clearBit(index: number): void { + this[index >> 3]! &= ~(1 << (index & 7)); + } + + previousBit(index: number): number { + while (index !== ((index >> 3) << 3)) { + --index; + + if (this.getBit(index)) { + return index; + } + } + + let byteIndex = (index >> 3) - 1; + + while (byteIndex >= 0 && this[byteIndex] === 0) + --byteIndex; + + if (byteIndex < 0) + return -1; + + index = (byteIndex << 3) + 7; + + while (index >= (byteIndex << 3)) { + if (this.getBit(index)) + return index; + + --index; + } + + throw new RangeError('Unreachable value'); + } +} \ No newline at end of file