import std/[bitops, strformat] type # Bit string described by a length and a sequence of bytes. BitString = object len: Natural data: seq[byte] # Position composed of a byte number and # a bit number in the byte (starting from the left). Position = tuple[bytenum, bitnum: int] func toPosition(n: Natural): Position = ## Convert an index to a Position. (n div 8, 7 - n mod 8) proc newBitString*(len: Natural): BitString = ## Create a bit string of length "len". result.len = len result.data = newSeq[byte]((len + 7) div 8) func checkIndex(bits: BitString; n: Natural) = ## Check that the index "n" is not out of bounds. if n >= bits.len: raise newException(RangeDefect, &"index out of range: {n}.") proc `[]`*(bits: BitString; n: Natural): bool = ## Return the bit at index "n" (as a boolean). bits.checkIndex(n) let pos = n.toPosition result = bits.data[pos.bytenum].testBit(pos.bitnum) func setBit*(bits: var BitString; n: Natural) = ## Set the bit at index "n". bits.checkIndex(n) let pos = n.toPosition bits.data[pos.bytenum].setBit(pos.bitnum) func clearBit*(bits: var BitString; n: Natural) = ## Clear the bit at index "n". ## Not used but provided for consistency. bits.checkIndex(n) let pos = n.toPosition bits.data[pos.bytenum].clearBit(pos.bitnum) iterator items*(bits: BitString): bool = ## Yield the successive bits of the bit string. for n in 0..