From 8af38da097b8358cb273baa37c748120461c718e Mon Sep 17 00:00:00 2001 From: pacien Date: Fri, 30 Nov 2018 16:57:32 +0100 Subject: isolate bit IO --- src/bitio/bitwriter.nim | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/bitio/bitwriter.nim (limited to 'src/bitio/bitwriter.nim') diff --git a/src/bitio/bitwriter.nim b/src/bitio/bitwriter.nim new file mode 100644 index 0000000..f1b44ca --- /dev/null +++ b/src/bitio/bitwriter.nim @@ -0,0 +1,59 @@ +# gzip-like LZSS compressor +# Copyright (C) 2018 Pacien TRAN-GIRARD +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import streams +import ../integers + +type BitWriter* = ref object + stream: Stream + bitOffset: int + writeBuffer: uint8 + +proc bitWriter*(stream: Stream): BitWriter = + BitWriter(stream: stream, bitOffset: 0, writeBuffer: 0) + +proc flush*(bitWriter: BitWriter) = + if bitWriter.bitOffset == 0: return + bitWriter.stream.write(bitWriter.writeBuffer) + bitWriter.stream.flush() + (bitWriter.bitOffset, bitWriter.writeBuffer) = (0, 0'u8) + +proc atEnd*(bitWriter: BitWriter): bool = + bitWriter.stream.atEnd() + +proc writeBits*(bitWriter: BitWriter, bits: int, value: SomeUnsignedInt) = + let valueContainerBitLength = sizeof(value) * wordBitLength + if bits < 0 or bits > valueContainerBitLength: + raise newException(RangeError, "invalid bit length") + var bitsToWrite = bits + if bitsToWrite + bitWriter.bitOffset >= wordBitLength: + bitWriter.stream.write(truncateToUint8(value shl bitWriter.bitOffset) or bitWriter.writeBuffer) + bitsToWrite -= wordBitLength - bitWriter.bitOffset + (bitWriter.bitOffset, bitWriter.writeBuffer) = (0, 0'u8) + while bitsToWrite >= wordBitLength: + bitWriter.stream.write(truncateToUint8(value shr (bits - bitsToWrite))) + bitsToWrite -= wordBitLength + if bitsToWrite > 0: + let left = truncateToUint8((value shl (valueContainerBitLength - bits)) shr (valueContainerBitLength - bitsToWrite)) + bitWriter.writeBuffer = (left shl bitWriter.bitOffset) or bitWriter.writeBuffer + bitWriter.bitOffset = (bitWriter.bitOffset + bitsToWrite) mod wordBitLength + +proc writeBool*(bitWriter: BitWriter, value: bool) = + bitWriter.writeBits(1, value.uint8) + +proc writeSeq*[T: SomeUnsignedInt](bitWriter: BitWriter, bitLength: int, data: seq[T]) = + for i, chunkBitLength in chunks(bitLength, T): + bitWriter.writeBits(chunkBitLength, data[i]) -- cgit v1.2.3