Task: Bitwise IO




Go: 
package bit

import (
    "bufio"
    "errors"
    "io"
)


type Order int

const (
    
    LSB Order = iota
    
    MSB
)



type writer interface {
    io.ByteWriter
    Flush() error
}


type Writer struct {
    w     writer
    order Order
    write func(uint32, uint) error 
    bits  uint32
    nBits uint
    err   error
}


func (w *Writer) writeLSB(c uint32, width uint) error {
    w.bits |= c << w.nBits
    w.nBits += width
    for w.nBits >= 8 {
        if err := w.w.WriteByte(uint8(w.bits)); err != nil {
            return err
        }
        w.bits >>= 8
        w.nBits -= 8
    }
    return nil
}


func (w *Writer) writeMSB(c uint32, width uint) error {
    w.bits |= c << (32 - width - w.nBits)
    w.nBits += width
    for w.nBits >= 8 {
        if err := w.w.WriteByte(uint8(w.bits >> 24)); err != nil {
            return err
        }
        w.bits <<= 8
        w.nBits -= 8
    }
    return nil
}




func (w *Writer) WriteBits(c uint16, width uint) error {
    if w.err == nil {
        w.err = w.write(uint32(c), width)
    }
    return w.err
}

var errClosed = errors.New("bit reader/writer is closed")



func (w *Writer) Close() error {
    if w.err != nil {
        if w.err == errClosed {
            return nil
        }
        return w.err
    }
    
    if w.nBits > 0 {
        if w.order == MSB {
            w.bits >>= 24
        }
        if w.err = w.w.WriteByte(uint8(w.bits)); w.err != nil {
            return w.err
        }
    }
    w.err = w.w.Flush()
    if w.err != nil {
        return w.err
    }

    
    w.err = errClosed
    return nil
}


func NewWriter(w io.Writer, order Order) *Writer {
    bw := &Writer{order: order}
    switch order {
    case LSB:
        bw.write = bw.writeLSB
    case MSB:
        bw.write = bw.writeMSB
    default:
        bw.err = errors.New("bit writer: unknown order")
        return bw
    }
    if byteWriter, ok := w.(writer); ok {
        bw.w = byteWriter
    } else {
        bw.w = bufio.NewWriter(w)
    }
    return bw
}




type Reader struct {
    r     io.ByteReader
    bits  uint32
    nBits uint
    read  func(width uint) (uint16, error) 
    err   error
}

func (r *Reader) readLSB(width uint) (uint16, error) {
    for r.nBits < width {
        x, err := r.r.ReadByte()
        if err != nil {
            return 0, err
        }
        r.bits |= uint32(x) << r.nBits
        r.nBits += 8
    }
    bits := uint16(r.bits & (1<<width - 1))
    r.bits >>= width
    r.nBits -= width
    return bits, nil
}

func (r *Reader) readMSB(width uint) (uint16, error) {
    for r.nBits < width {
        x, err := r.r.ReadByte()
        if err != nil {
            return 0, err
        }
        r.bits |= uint32(x) << (24 - r.nBits)
        r.nBits += 8
    }
    bits := uint16(r.bits >> (32 - width))
    r.bits <<= width
    r.nBits -= width
    return bits, nil
}


func (r *Reader) ReadBits(width uint) (uint16, error) {
    var bits uint16
    if r.err == nil {
        bits, r.err = r.read(width)
    }
    return bits, r.err
}



func (r *Reader) Close() error {
    if r.err != nil && r.err != errClosed {
        return r.err
    }
    r.err = errClosed
    return nil
}


func NewReader(r io.Reader, order Order) *Reader {
    br := new(Reader)
    switch order {
    case LSB:
        br.read = br.readLSB
    case MSB:
        br.read = br.readMSB
    default:
        br.err = errors.New("bit writer: unknown order")
        return br
    }
    if byteReader, ok := r.(io.ByteReader); ok {
        br.r = byteReader
    } else {
        br.r = bufio.NewReader(r)
    }
    return br
}




Python: class BitWriter(object):
    def __init__(self, f):
        self.accumulator = 0
        self.bcount = 0
        self.out = f

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.flush()

    def __del__(self):
        try:
            self.flush()
        except ValueError:   
            pass

    def _writebit(self, bit):
        if self.bcount == 8:
            self.flush()
        if bit > 0:
            self.accumulator |= 1 << 7-self.bcount
        self.bcount += 1

    def writebits(self, bits, n):
        while n > 0:
            self._writebit(bits & 1 << n-1)
            n -= 1

    def flush(self):
        self.out.write(bytearray([self.accumulator]))
        self.accumulator = 0
        self.bcount = 0


class BitReader(object):
    def __init__(self, f):
        self.input = f
        self.accumulator = 0
        self.bcount = 0
        self.read = 0

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        pass

    def _readbit(self):
        if not self.bcount:
            a = self.input.read(1)
            if a:
                self.accumulator = ord(a)
            self.bcount = 8
            self.read = len(a)
        rv = (self.accumulator & (1 << self.bcount-1)) >> self.bcount-1
        self.bcount -= 1
        return rv

    def readbits(self, n):
        v = 0
        while n > 0:
            v = (v << 1) | self._readbit()
            n -= 1
        return v

if __name__ == '__main__':
    import os
    import sys
    
    module_name = os.path.splitext(os.path.basename(__file__))[0]
    bitio = __import__(module_name)

    with open('bitio_test.dat', 'wb') as outfile:
        with bitio.BitWriter(outfile) as writer:
            chars = '12345abcde'
            for ch in chars:
                writer.writebits(ord(ch), 7)

    with open('bitio_test.dat', 'rb') as infile:
        with bitio.BitReader(infile) as reader:
            chars = []
            while True:
                x = reader.readbits(7)
                if not reader.read:  
                    break
                chars.append(chr(x))
            print(''.join(chars))