RosettaCodeData/Task/Bitwise-IO/Nim/bitwise-io.nim

95 lines
1.9 KiB
Nim

type
BitWriter * = tuple
file: File
bits: uint8
nRemain: int
BitReader * = tuple
file: File
bits: uint8
nRemain: int
nRead: int
proc newBitWriter * (file: File) : ref BitWriter =
result = new BitWriter
result.file = file
result.bits = 0
result.nRemain = 8
proc flushBits (stream : ref BitWriter) =
discard stream.file.writeBuffer(stream.bits.addr, 1)
stream.nRemain = 8
stream.bits = 0
proc write * (stream: ref BitWriter, bits: uint8, nBits: int) =
assert(nBits <= 8)
for ii in countdown((nBits - 1), 0) :
stream.bits = (stream.bits shl 1) or ((bits shr ii) and 1)
stream.nRemain.dec(1)
if stream.nRemain == 0:
stream.flushBits
proc flush * (stream: ref BitWriter) =
if stream.nRemain < 8:
stream.bits = stream.bits shl stream.nRemain
stream.flushBits
proc newBitReader * (file: File) : ref BitReader =
result = new BitReader
result.file = file
result.bits = 0
result.nRemain = 0
result.nRead = 0
proc read * (stream: ref BitReader, nBits: int) : uint8 =
assert(nBits <= 8)
result = 0
for ii in 0 .. < nBits :
if stream.nRemain == 0:
stream.nRead = stream.file.readBuffer(stream.bits.addr, 1)
if stream.nRead == 0:
break
stream.nRemain = 8
result = (result shl 1) or ((stream.bits shr 7) and 1)
stream.bits = stream.bits shl 1
stream.nRemain.dec(1)
when isMainModule:
var
file: File
writer: ref BitWriter
reader: ref BitReader
file = open("testfile.dat", fmWrite)
writer = newBitWriter(file)
for ii in 0 .. 255:
writer.write(ii.uint8, 7)
writer.flush
file.close
var dataCtr = 0
file = open("testfile.dat", fmRead)
reader = newBitReader(file)
while true:
let aByte = reader.read(7)
if reader.nRead == 0:
break
assert((dataCtr and 0x7f).uint8 == aByte)
assert(dataCtr == 256)
file.close
echo "OK"