From d9768cd0315b0415d20818de9c897c6168c95b78 Mon Sep 17 00:00:00 2001
From: pacien
Date: Fri, 23 Nov 2018 12:57:00 +0100
Subject: Split bitstream into bitreader and bitwriter
---
src/bitreader.nim | 72 ++++++++++++++++++++++++++++
src/bitstream.nim | 112 -------------------------------------------
src/bitwriter.nim | 59 +++++++++++++++++++++++
src/integers.nim | 7 +++
src/lzssblock.nim | 10 ++--
src/rawblock.nim | 22 ++++-----
src/streamblock.nim | 37 ++++++++-------
tests/tbitreader.nim | 61 ++++++++++++++++++++++++
tests/tbitstream.nim | 131 ---------------------------------------------------
tests/tbitwriter.nim | 85 +++++++++++++++++++++++++++++++++
tests/tintegers.nim | 6 ++-
tests/trawblock.nim | 22 ++++-----
12 files changed, 335 insertions(+), 289 deletions(-)
create mode 100644 src/bitreader.nim
delete mode 100644 src/bitstream.nim
create mode 100644 src/bitwriter.nim
create mode 100644 tests/tbitreader.nim
delete mode 100644 tests/tbitstream.nim
create mode 100644 tests/tbitwriter.nim
diff --git a/src/bitreader.nim b/src/bitreader.nim
new file mode 100644
index 0000000..35e9d57
--- /dev/null
+++ b/src/bitreader.nim
@@ -0,0 +1,72 @@
+# "à-la-gzip" 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
+
+# Stream functions
+
+proc newEIO(msg: string): ref IOError =
+ new(result)
+ result.msg = msg
+
+proc read[T](s: Stream, t: typedesc[T]): T =
+ if readData(s, addr(result), sizeof(T)) != sizeof(T):
+ raise newEIO("cannot read from stream")
+
+proc peek[T](s: Stream, t: typedesc[T]): T =
+ if peekData(s, addr(result), sizeof(T)) != sizeof(T):
+ raise newEIO("cannot read from stream")
+
+# BitReader
+
+type BitReader* = ref object
+ stream: Stream
+ bitOffset: int
+
+proc bitReader*(stream: Stream): BitReader =
+ BitReader(stream: stream, bitOffset: 0)
+
+proc atEnd*(bitReader: BitReader): bool =
+ bitReader.stream.atEnd()
+
+proc readBits*[T: SomeUnsignedInt](bitReader: BitReader, bits: int, to: typedesc[T]): T =
+ let targetBitLength = sizeof(T) * wordBitLength
+ if bits < 0 or bits > targetBitLength:
+ raise newException(RangeError, "invalid bit length")
+ elif bits == 0:
+ result = 0
+ elif bits < targetBitLength - bitReader.bitOffset:
+ result = bitReader.stream.peek(T) shl (targetBitLength - bits - bitReader.bitOffset) shr (targetBitLength - bits)
+ elif bits == targetBitLength - bitReader.bitOffset:
+ result = bitReader.stream.read(T) shl (targetBitLength - bits - bitReader.bitOffset) shr (targetBitLength - bits)
+ else:
+ let rightBits = targetBitLength - bitReader.bitOffset
+ let leftBits = bits - rightBits
+ let right = bitReader.stream.read(T) shr bitReader.bitOffset
+ let left = bitReader.stream.peek(T) shl (targetBitLength - leftBits) shr (targetBitLength - bits)
+ result = left or right
+ bitReader.bitOffset = (bitReader.bitOffset + bits) mod wordBitLength
+
+proc readBool*(bitReader: BitReader): bool =
+ bitReader.readBits(1, uint8) != 0
+
+proc readSeq*[T: SomeUnsignedInt](bitReader: BitReader, bitLength: int, to: typedesc[T]): tuple[bitLength: int, data: seq[T]] =
+ result = (0, newSeqOfCap[T](bitLength /^ (sizeof(T) * wordBitLength)))
+ for _, chunkBitLength in chunks(bitLength, T):
+ if bitReader.atEnd(): return
+ result.bitLength += chunkBitLength
+ result.data.add(bitReader.readBits(chunkBitLength, T))
diff --git a/src/bitstream.nim b/src/bitstream.nim
deleted file mode 100644
index 81401ce..0000000
--- a/src/bitstream.nim
+++ /dev/null
@@ -1,112 +0,0 @@
-# "à-la-gzip" 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
-
-# Stream functions
-
-proc newEIO(msg: string): ref IOError =
- new(result)
- result.msg = msg
-
-proc read[T](s: Stream, t: typedesc[T]): T =
- if readData(s, addr(result), sizeof(T)) != sizeof(T):
- raise newEIO("cannot read from stream")
-
-proc peek[T](s: Stream, t: typedesc[T]): T =
- if peekData(s, addr(result), sizeof(T)) != sizeof(T):
- raise newEIO("cannot read from stream")
-
-# Utils
-
-iterator chunks*(totalBitLength: int, chunkType: typedesc[SomeInteger]): tuple[index: int, chunkBitLength: int] =
- let chunkBitLength = sizeof(chunkType) * wordBitLength
- let wordCount = totalBitLength div chunkBitLength
- for i in 0..<(wordCount): yield (i, chunkBitLength)
- let remainder = totalBitLength mod chunkBitLength
- if remainder > 0: yield (wordCount, remainder)
-
-# BitStream
-
-type BitStream* = ref object
- stream: Stream
- bitOffset: int
- writeBuffer: uint8
-
-proc bitStream*(stream: Stream): BitStream =
- BitStream(stream: stream, bitOffset: 0, writeBuffer: 0)
-
-proc flush*(bitStream: BitStream) =
- if bitStream.bitOffset == 0: return
- bitStream.stream.write(bitStream.writeBuffer)
- bitStream.stream.flush()
- (bitStream.bitOffset, bitStream.writeBuffer) = (0, 0'u8)
-
-proc atEnd*(bitStream: BitStream): bool =
- bitStream.stream.atEnd()
-
-proc readBits*[T: SomeUnsignedInt](bitStream: BitStream, bits: int, to: typedesc[T]): T =
- let targetBitLength = sizeof(T) * wordBitLength
- if bits < 0 or bits > targetBitLength:
- raise newException(RangeError, "invalid bit length")
- elif bits == 0:
- result = 0
- elif bits < targetBitLength - bitStream.bitOffset:
- result = bitStream.stream.peek(T) shl (targetBitLength - bits - bitStream.bitOffset) shr (targetBitLength - bits)
- elif bits == targetBitLength - bitStream.bitOffset:
- result = bitStream.stream.read(T) shl (targetBitLength - bits - bitStream.bitOffset) shr (targetBitLength - bits)
- else:
- let rightBits = targetBitLength - bitStream.bitOffset
- let leftBits = bits - rightBits
- let right = bitStream.stream.read(T) shr bitStream.bitOffset
- let left = bitStream.stream.peek(T) shl (targetBitLength - leftBits) shr (targetBitLength - bits)
- result = left or right
- bitStream.bitOffset = (bitStream.bitOffset + bits) mod wordBitLength
-
-proc readBool*(bitStream: BitStream): bool =
- bitStream.readBits(1, uint8) != 0
-
-proc readSeq*[T: SomeUnsignedInt](bitStream: BitStream, bitLength: int, to: typedesc[T]): tuple[bitLength: int, data: seq[T]] =
- result = (0, newSeqOfCap[T](bitLength /^ (sizeof(T) * wordBitLength)))
- for _, chunkBitLength in chunks(bitLength, T):
- if bitStream.atEnd(): return
- result.bitLength += chunkBitLength
- result.data.add(bitStream.readBits(chunkBitLength, T))
-
-proc writeBits*(bitStream: BitStream, 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 + bitStream.bitOffset >= wordBitLength:
- bitStream.stream.write(truncateToUint8(value shl bitStream.bitOffset) or bitStream.writeBuffer)
- bitsToWrite -= wordBitLength - bitStream.bitOffset
- (bitStream.bitOffset, bitStream.writeBuffer) = (0, 0'u8)
- while bitsToWrite >= wordBitLength:
- bitStream.stream.write(truncateToUint8(value shr (bits - bitsToWrite)))
- bitsToWrite -= wordBitLength
- if bitsToWrite > 0:
- let left = truncateToUint8((value shl (valueContainerBitLength - bits)) shr (valueContainerBitLength - bitsToWrite))
- bitStream.writeBuffer = (left shl bitStream.bitOffset) or bitStream.writeBuffer
- bitStream.bitOffset = (bitStream.bitOffset + bitsToWrite) mod wordBitLength
-
-proc writeBool*(bitStream: BitStream, value: bool) =
- bitStream.writeBits(1, value.uint8)
-
-proc writeSeq*[T: SomeUnsignedInt](bitStream: BitStream, bitLength: int, data: seq[T]) =
- for i, chunkBitLength in chunks(bitLength, T):
- bitStream.writeBits(chunkBitLength, data[i])
diff --git a/src/bitwriter.nim b/src/bitwriter.nim
new file mode 100644
index 0000000..aac96f9
--- /dev/null
+++ b/src/bitwriter.nim
@@ -0,0 +1,59 @@
+# "à-la-gzip" 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])
diff --git a/src/integers.nim b/src/integers.nim
index 1b9121c..1f83488 100644
--- a/src/integers.nim
+++ b/src/integers.nim
@@ -22,3 +22,10 @@ proc `/^`*[T: Natural](x, y: T): T =
proc truncateToUint8*(x: SomeUnsignedInt): uint8 =
(x and wordBitMask).uint8
+
+iterator chunks*(totalBitLength: int, chunkType: typedesc[SomeInteger]): tuple[index: int, chunkBitLength: int] =
+ let chunkBitLength = sizeof(chunkType) * wordBitLength
+ let wordCount = totalBitLength div chunkBitLength
+ for i in 0..<(wordCount): yield (i, chunkBitLength)
+ let remainder = totalBitLength mod chunkBitLength
+ if remainder > 0: yield (wordCount, remainder)
diff --git a/src/lzssblock.nim b/src/lzssblock.nim
index 87b62a0..959ad09 100644
--- a/src/lzssblock.nim
+++ b/src/lzssblock.nim
@@ -14,19 +14,19 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-import bitstream
+import bitreader, bitwriter
type LzssBlock* = object
discard
-proc readSerialised*(bitStream: BitStream): LzssBlock =
+proc readSerialised*(bitReader: BitReader): LzssBlock =
discard
-proc writeSerialisedTo*(lzssBlock: LzssBlock, bitStream: BitStream) =
+proc writeSerialisedTo*(lzssBlock: LzssBlock, bitWriter: BitWriter) =
discard
-proc readRaw*(bitStream: BitStream): LzssBlock =
+proc readRaw*(bitReader: BitReader): LzssBlock =
discard
-proc writeRawTo*(lzssBlock: LzssBlock, bitStream: BitStream) =
+proc writeRawTo*(lzssBlock: LzssBlock, bitWriter: BitWriter) =
discard
diff --git a/src/rawblock.nim b/src/rawblock.nim
index bdbfc71..aa3e7ae 100644
--- a/src/rawblock.nim
+++ b/src/rawblock.nim
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-import integers, bitstream
+import integers, bitreader, bitwriter
const maxDataBitLength = 100_000_000 * wordBitLength # 100MB
const bitLengthFieldBitLength = 2 * wordBitLength
@@ -23,18 +23,18 @@ type RawBlock* = object
bitLength: int
data: seq[uint8]
-proc readSerialised*(bitStream: BitStream): RawBlock =
- let bitLength = bitStream.readBits(bitLengthFieldBitLength, uint16).int
- let data = readSeq(bitStream, bitLength, uint8)
+proc readSerialised*(bitReader: BitReader): RawBlock =
+ let bitLength = bitReader.readBits(bitLengthFieldBitLength, uint16).int
+ let data = readSeq(bitReader, bitLength, uint8)
RawBlock(bitLength: bitLength, data: data.data)
-proc writeSerialisedTo*(rawBlock: RawBlock, bitStream: BitStream) =
- bitStream.writeBits(bitLengthFieldBitLength, rawBlock.bitLength.uint16)
- writeSeq(bitStream, rawBlock.bitLength, rawBlock.data)
+proc writeSerialisedTo*(rawBlock: RawBlock, bitWriter: BitWriter) =
+ bitWriter.writeBits(bitLengthFieldBitLength, rawBlock.bitLength.uint16)
+ bitWriter.writeSeq(rawBlock.bitLength, rawBlock.data)
-proc readRaw*(bitStream: BitStream, bits: int = maxDataBitLength): RawBlock =
- let data = readSeq(bitStream, bits, uint8)
+proc readRaw*(bitReader: BitReader, bits: int = maxDataBitLength): RawBlock =
+ let data = readSeq(bitReader, bits, uint8)
RawBlock(bitLength: data.bitLength, data: data.data)
-proc writeRawTo*(rawBlock: RawBlock, bitStream: BitStream) =
- writeSeq(bitStream, rawBlock.bitLength, rawBlock.data)
+proc writeRawTo*(rawBlock: RawBlock, bitWriter: BitWriter) =
+ bitWriter.writeSeq(rawBlock.bitLength, rawBlock.data)
diff --git a/src/streamblock.nim b/src/streamblock.nim
index 8d2b4b1..eef916f 100644
--- a/src/streamblock.nim
+++ b/src/streamblock.nim
@@ -15,7 +15,8 @@
# along with this program. If not, see .
import sequtils
-import integers, bitstream, rawblock, lzssblock
+import integers, bitreader, bitwriter
+import rawblock, lzssblock
type BlockKind* = enum
uncompressed = 0b00'u8,
@@ -33,32 +34,32 @@ type StreamBlock* = object
else:
discard
-proc readSerialised*(bitStream: BitStream): StreamBlock =
- result.last = bitStream.readBool()
- result.kind = bitStream.readBits(2, uint8).BlockKind
+proc readSerialised*(bitReader: BitReader): StreamBlock =
+ result.last = bitReader.readBool()
+ result.kind = bitReader.readBits(2, uint8).BlockKind
case result.kind:
- of uncompressed: result.rawBlock = rawblock.readRaw(bitStream)
- of lzss: result.lzssBlock = lzssblock.readRaw(bitStream)
+ of uncompressed: result.rawBlock = rawblock.readRaw(bitReader)
+ of lzss: result.lzssBlock = lzssblock.readRaw(bitReader)
else: raise newException(ValueError, "unhandled block type")
-proc writeSerialisedTo*(streamBlock: StreamBlock, bitStream: BitStream) =
- bitStream.writeBool(streamBlock.last)
- bitStream.writeBits(2, streamBlock.kind.uint8)
+proc writeSerialisedTo*(streamBlock: StreamBlock, bitWriter: BitWriter) =
+ bitWriter.writeBool(streamBlock.last)
+ bitWriter.writeBits(2, streamBlock.kind.uint8)
case streamBlock.kind:
- of uncompressed: streamBlock.rawBlock.writeSerialisedTo(bitStream)
- of lzss: streamBlock.lzssBlock.writeSerialisedTo(bitStream)
+ of uncompressed: streamBlock.rawBlock.writeSerialisedTo(bitWriter)
+ of lzss: streamBlock.lzssBlock.writeSerialisedTo(bitWriter)
else: raise newException(ValueError, "unhandled block type")
-proc readRaw*(bitStream: BitStream, kind: BlockKind = uncompressed): StreamBlock =
+proc readRaw*(bitReader: BitReader, kind: BlockKind = uncompressed): StreamBlock =
result.kind = kind
case kind:
- of uncompressed: result.rawBlock = rawblock.readRaw(bitStream)
- of lzss: result.lzssBlock = lzssblock.readRaw(bitStream)
+ of uncompressed: result.rawBlock = rawblock.readRaw(bitReader)
+ of lzss: result.lzssBlock = lzssblock.readRaw(bitReader)
else: raise newException(ValueError, "unhandled block type")
- result.last = bitStream.atEnd()
+ result.last = bitReader.atEnd()
-proc writeRawTo*(streamBlock: StreamBlock, bitStream: BitStream) =
+proc writeRawTo*(streamBlock: StreamBlock, bitWriter: BitWriter) =
case streamBlock.kind:
- of uncompressed: streamBlock.rawBlock.writeRawTo(bitStream)
- of lzss: streamBlock.lzssBlock.writeRawTo(bitStream)
+ of uncompressed: streamBlock.rawBlock.writeRawTo(bitWriter)
+ of lzss: streamBlock.lzssBlock.writeRawTo(bitWriter)
else: raise newException(ValueError, "unhandled block type")
diff --git a/tests/tbitreader.nim b/tests/tbitreader.nim
new file mode 100644
index 0000000..6b3be2b
--- /dev/null
+++ b/tests/tbitreader.nim
@@ -0,0 +1,61 @@
+# "à-la-gzip" 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 unittest, streams, sugar, sequtils
+import integers, bitreader
+
+suite "bitreader":
+ test "readBool":
+ let stream = newStringStream()
+ defer: stream.close()
+ stream.write(0b1001_1111'u8)
+ stream.write(0b0110_0000'u8)
+ stream.setPosition(0)
+
+ let bitReader = stream.bitReader()
+ check lc[bitReader.readBool() | (_ <- 0..<16), bool] == @[
+ true, true, true, true, true, false, false, true,
+ false, false, false, false, false, true, true, false]
+
+ expect IOError: discard bitReader.readBool()
+ check bitReader.atEnd()
+
+ test "readBits":
+ let stream = newStringStream()
+ defer: stream.close()
+ stream.write(0xF00F'u16)
+ stream.write(0x0FFF'u16)
+ stream.setPosition(0)
+
+ let bitReader = stream.bitReader()
+ check bitReader.readBits(8, uint8) == 0x0F'u8
+ check bitReader.readBits(16, uint16) == 0xFFF0'u16
+ check bitReader.readBits(8, uint8) == 0x0F'u8
+
+ expect RangeError: discard bitReader.readBits(9, uint8)
+ expect IOError: discard bitReader.readBits(16, uint16)
+ check bitReader.atEnd()
+
+ test "readSeq":
+ let stream = newStringStream()
+ defer: stream.close()
+ stream.write(0x0F00_F0FF_F0F0_F0F0'u64)
+ stream.setPosition(0)
+
+ let bitReader = stream.bitReader()
+ check bitReader.readSeq(32, uint16) == (32, @[0xF0F0'u16, 0xF0F0])
+ check bitReader.readSeq(40, uint8) == (32, @[0xFF'u8, 0xF0, 0x00, 0x0F])
+ check bitReader.atEnd()
diff --git a/tests/tbitstream.nim b/tests/tbitstream.nim
deleted file mode 100644
index 2292049..0000000
--- a/tests/tbitstream.nim
+++ /dev/null
@@ -1,131 +0,0 @@
-# "à-la-gzip" 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 unittest, streams, sugar, sequtils
-import integers, bitstream
-
-suite "bitstream":
- test "chunks iterator":
- check toSeq(chunks(70, uint32)) == @[(0, 32), (1, 32), (2, 6)]
- check toSeq(chunks(32, uint16)) == @[(0, 16), (1, 16)]
-
- test "flush":
- let stream = newStringStream()
- defer: stream.close()
- let bitStream = stream.bitStream()
-
- bitStream.writeBool(true)
- stream.setPosition(0)
- expect IOError: discard stream.peekUint8()
-
- bitStream.flush()
- stream.setPosition(0)
- check stream.readUint8() == 0x01'u8
- check stream.atEnd()
-
- bitStream.flush()
- check stream.atEnd()
-
- test "readBool":
- let stream = newStringStream()
- defer: stream.close()
- stream.write(0b1001_1111'u8)
- stream.write(0b0110_0000'u8)
- stream.setPosition(0)
-
- let bitStream = stream.bitStream()
- check lc[bitStream.readBool() | (_ <- 0..<16), bool] == @[
- true, true, true, true, true, false, false, true,
- false, false, false, false, false, true, true, false]
-
- expect IOError: discard bitStream.readBool()
- check bitStream.atEnd()
-
- test "readBits":
- let stream = newStringStream()
- defer: stream.close()
- stream.write(0xF00F'u16)
- stream.write(0x0FFF'u16)
- stream.setPosition(0)
-
- let bitStream = stream.bitStream()
- check bitStream.readBits(8, uint8) == 0x0F'u8
- check bitStream.readBits(16, uint16) == 0xFFF0'u16
- check bitStream.readBits(8, uint8) == 0x0F'u8
-
- expect RangeError: discard bitStream.readBits(9, uint8)
- expect IOError: discard bitStream.readBits(16, uint16)
- check bitStream.atEnd()
-
- test "readSeq":
- let stream = newStringStream()
- defer: stream.close()
- stream.write(0x0F00_F0FF_F0F0_F0F0'u64)
- stream.setPosition(0)
-
- let bitStream = stream.bitStream()
- check bitStream.readSeq(32, uint16) == (32, @[0xF0F0'u16, 0xF0F0])
- check bitStream.readSeq(40, uint8) == (32, @[0xFF'u8, 0xF0, 0x00, 0x0F])
- check bitStream.atEnd()
-
- test "writeBool":
- let stream = newStringStream()
- defer: stream.close()
-
- let bitStream = stream.bitStream()
- let booleanValues = @[
- true, true, true, true, true, false, false, true,
- false, false, false, false, false, true, true, false,
- true, true, false, true]
- for b in booleanValues: bitStream.writeBool(b)
- bitStream.flush()
-
- stream.setPosition(0)
- check stream.readUint8() == 0b1001_1111'u8
- check stream.readUint8() == 0b0110_0000'u8
- check stream.readUint8() == 0b0000_1011'u8
- expect IOError: discard stream.readUint8()
- check stream.atEnd()
-
- test "writeBits":
- let stream = newStringStream()
- defer: stream.close()
-
- let bitStream = stream.bitStream()
- bitStream.writeBits(4, 0xF00F'u16)
- bitStream.writeBits(16, 0xF00F'u16)
- bitStream.writeBits(16, 0xFFFF'u16)
- bitStream.flush()
-
- stream.setPosition(0)
- check stream.readUint16() == 0x00FF'u16
- check stream.readUint16() == 0xFFFF'u16
- check stream.readUint8() == 0x0F'u8
- expect IOError: discard stream.readUint8()
- check stream.atEnd()
-
- test "writeSeq":
- let stream = newStringStream()
- defer: stream.close()
-
- let bitStream = stream.bitStream()
- bitStream.writeSeq(32, @[0xF0F0'u16, 0xF0F0])
- bitStream.writeSeq(28, @[0xFF'u8, 0xF0, 0x00, 0xFF])
- bitStream.flush()
-
- stream.setPosition(0)
- check stream.readUint64() == 0x0F00_F0FF_F0F0_F0F0'u64
- check stream.atEnd()
diff --git a/tests/tbitwriter.nim b/tests/tbitwriter.nim
new file mode 100644
index 0000000..cc7fdc5
--- /dev/null
+++ b/tests/tbitwriter.nim
@@ -0,0 +1,85 @@
+# "à-la-gzip" 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 unittest, streams
+import integers, bitwriter
+
+suite "bitwriter":
+ test "flush":
+ let stream = newStringStream()
+ defer: stream.close()
+ let bitWriter = stream.bitWriter()
+
+ bitWriter.writeBool(true)
+ stream.setPosition(0)
+ expect IOError: discard stream.peekUint8()
+
+ bitWriter.flush()
+ stream.setPosition(0)
+ check stream.readUint8() == 0x01'u8
+ check stream.atEnd()
+
+ bitWriter.flush()
+ check stream.atEnd()
+
+ test "writeBool":
+ let stream = newStringStream()
+ defer: stream.close()
+
+ let bitWriter = stream.bitWriter()
+ let booleanValues = @[
+ true, true, true, true, true, false, false, true,
+ false, false, false, false, false, true, true, false,
+ true, true, false, true]
+ for b in booleanValues: bitWriter.writeBool(b)
+ bitWriter.flush()
+
+ stream.setPosition(0)
+ check stream.readUint8() == 0b1001_1111'u8
+ check stream.readUint8() == 0b0110_0000'u8
+ check stream.readUint8() == 0b0000_1011'u8
+ expect IOError: discard stream.readUint8()
+ check stream.atEnd()
+
+ test "writeBits":
+ let stream = newStringStream()
+ defer: stream.close()
+
+ let bitWriter = stream.bitWriter()
+ bitWriter.writeBits(4, 0xF00F'u16)
+ bitWriter.writeBits(16, 0xF00F'u16)
+ bitWriter.writeBits(16, 0xFFFF'u16)
+ bitWriter.flush()
+
+ stream.setPosition(0)
+ check stream.readUint16() == 0x00FF'u16
+ check stream.readUint16() == 0xFFFF'u16
+ check stream.readUint8() == 0x0F'u8
+ expect IOError: discard stream.readUint8()
+ check stream.atEnd()
+
+ test "writeSeq":
+ let stream = newStringStream()
+ defer: stream.close()
+
+ let bitWriter = stream.bitWriter()
+ bitWriter.writeSeq(32, @[0xF0F0'u16, 0xF0F0])
+ bitWriter.writeSeq(28, @[0xFF'u8, 0xF0, 0x00, 0xFF])
+ bitWriter.flush()
+
+ stream.setPosition(0)
+ check stream.readUint64() == 0x0F00_F0FF_F0F0_F0F0'u64
+ check stream.atEnd()
diff --git a/tests/tintegers.nim b/tests/tintegers.nim
index 720677e..de43c09 100644
--- a/tests/tintegers.nim
+++ b/tests/tintegers.nim
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-import unittest
+import unittest, sequtils
import integers
suite "integers":
@@ -26,3 +26,7 @@ suite "integers":
check truncateToUint8(0xFA'u8) == 0xFA'u8
check truncateToUint8(0x00FA'u16) == 0xFA'u8
check truncateToUint8(0xFFFA'u16) == 0xFA'u8
+
+ test "chunks iterator":
+ check toSeq(chunks(70, uint32)) == @[(0, 32), (1, 32), (2, 6)]
+ check toSeq(chunks(32, uint16)) == @[(0, 16), (1, 16)]
diff --git a/tests/trawblock.nim b/tests/trawblock.nim
index 1e92c60..e789b4b 100644
--- a/tests/trawblock.nim
+++ b/tests/trawblock.nim
@@ -15,7 +15,7 @@
# along with this program. If not, see .
import unittest, streams
-import bitstream, rawblock
+import bitreader, bitwriter, rawblock
suite "rawblock":
test "serialise":
@@ -23,14 +23,14 @@ suite "rawblock":
defer: rawStream.close()
rawStream.write(0xFEDC_BA98_7654_3210'u64)
rawStream.setPosition(0)
- let rawBitStream = rawStream.bitStream()
- let rawBlock = rawblock.readRaw(rawBitStream)
+ let rawBitReader = rawStream.bitReader()
+ let rawBlock = rawblock.readRaw(rawBitReader)
let outputStream = newStringStream()
defer: outputStream.close()
- let outputBitStream = outputStream.bitStream()
- rawBlock.writeSerialisedTo(outputBitStream)
- outputBitStream.flush()
+ let outputBitWriter = outputStream.bitWriter()
+ rawBlock.writeSerialisedTo(outputBitWriter)
+ outputBitWriter.flush()
outputStream.setPosition(0)
check outputStream.readUint16() == 64
@@ -43,14 +43,14 @@ suite "rawblock":
serialisedStream.write(60'u16)
serialisedStream.write(0xFEDC_BA98_7654_3210'u64)
serialisedStream.setPosition(0)
- let serialisedBitStream = serialisedStream.bitStream()
- let rawBlock = rawBlock.readSerialised(serialisedBitStream)
+ let serialisedBitReader = serialisedStream.bitReader()
+ let rawBlock = rawBlock.readSerialised(serialisedBitReader)
let outputStream = newStringStream()
defer: outputStream.close()
- let outputBitStream = outputStream.bitStream()
- rawBlock.writeRawTo(outputBitStream)
- outputBitStream.flush()
+ let outputBitWriter = outputStream.bitWriter()
+ rawBlock.writeRawTo(outputBitWriter)
+ outputBitWriter.flush()
outputStream.setPosition(0)
check outputStream.readUint64 == 0x0EDC_BA98_7654_3210'u64
--
cgit v1.2.3