Task: Bitwise IO



C#: using System;
using System.IO;

public class BitReader
{
    uint readData = 0;
    int startPosition = 0;
    int endPosition = 0;

    public int InBuffer
    {
        get { return endPosition - startPosition; }
    }

    private Stream stream;

    public Stream BaseStream
    {
        get { return stream; }
    }

    public BitReader(Stream stream)
    {
        this.stream = stream;
    }

    void EnsureData(int bitCount)
    {
        int readBits = bitCount - InBuffer;
        while (readBits > 0)
        {
            int b = BaseStream.ReadByte();

            if (b < 0) throw new InvalidOperationException("Unexpected end of stream");

            readData |= checked((uint)b << endPosition);
            endPosition += 8;
            readBits -= 8;
        }
    }

    public bool ReadBit()
    {
        return Read(1) > 0;
    }

    public int Read(int bitCount)
    {
        EnsureData(bitCount);

        int result = (int)(readData >> startPosition) & ((1 << bitCount) - 1);
        startPosition += bitCount;
        if (endPosition == startPosition)
        {
            endPosition = startPosition = 0;
            readData = 0;
        }
        else if (startPosition >= 8)
        {
            readData >>= startPosition;
            endPosition -= startPosition;
            startPosition = 0;
        }

        return result;
    }

    public void Align()
    {
        endPosition = startPosition = 0;
        readData = 0;
    }
}

public class BitWriter
{
    uint data = 0;
    int dataLength = 0;
    Stream stream;

    public Stream BaseStream
    {
        get { return stream; }
    }

    public int BitsToAligment
    {
        get { return (32 - dataLength) % 8; }
    }

    public BitWriter(Stream stream)
    {
        this.stream = stream;
    }

    public void WriteBit(bool value)
    {
        Write(value ? 1 : 0, 1);
    }

    public void Write(int value, int length)
    {
        uint currentData = data | checked((uint)value << dataLength);
        int currentLength = dataLength + length;
        while (currentLength >= 8)
        {
            BaseStream.WriteByte((byte)currentData);
            currentData >>= 8;
            currentLength -= 8;
        }
        data = currentData;
        dataLength = currentLength;
    }

    public void Align()
    {
        if (dataLength > 0)
        {
            BaseStream.WriteByte((byte)data);

            data = 0;
            dataLength = 0;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        MemoryStream ms = new MemoryStream();
        BitWriter writer = new BitWriter(ms);
        writer.WriteBit(true);
        writer.Write(5, 3);
        writer.Write(0x0155, 11);
        writer.Align();

        ms.Position = 0;
        BitReader reader = new BitReader(ms);
        Console.WriteLine(reader.ReadBit());
        Console.WriteLine(reader.Read(3));
        Console.WriteLine(reader.Read(11).ToString("x4"));
        reader.Align();
    }
}


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
}