ビット単位のストリーム入出力

# BitStream
```c#:BitStream.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace System.IO
{
    public class BitStream : Stream
    {
        Stream stream;

        public enum Access
        {
            Read,
            Write,
        }

        Access access;

        public BitStream(Stream stream, Access access)
        {
            if (stream == null)
            {
                throw new ArgumentNullException();
            }

            this.stream = stream;

            this.access = access;

            read_buffer = 0;
            read_buffer_bit_length = 0;

            write_buffer = 0;
            write_buffer_bit_length = 0;
        }

        public override bool CanRead
        {
            get
            {
                return (access == Access.Read) && stream.CanRead;
            }
        }

        public override bool CanWrite
        {
            get
            {
                return (access == Access.Write) && stream.CanWrite;
            }
        }

        public override bool CanSeek => false;

        public override long Length => throw new InvalidOperationException();

        public override long Position
        {
            get => throw new InvalidOperationException();
            set => throw new InvalidOperationException();
        }

        public override long Seek(long offset, SeekOrigin origin) => throw new InvalidOperationException();

        public override void SetLength(long value) => throw new InvalidOperationException();

        public override int Read(byte[] buffer, int offset, int count)
        {
            return (ReadBit(buffer, offset, count * 8) + 7) / 8;
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            WriteBit(buffer, offset, count * 8);
        }

        byte[] byte_buffer = new byte[1];

        int read_buffer;

        int read_buffer_bit_length;

        public int ReadBit(byte[] buffer, int offset, int bit_count)
        {
            if (access != Access.Read)
            {
                throw new InvalidOperationException();
            }

            if (bit_count <= 0)
            {
                if (bit_count == 0)
                {
                    return 0;
                }

                throw new ArgumentOutOfRangeException();
            }

            int byte_count = bit_count / 8;

            if (read_buffer_bit_length == 0)
            {
                if (byte_count > 0)
                {
                    int read_count = stream.Read(buffer, offset, byte_count);

                    if (read_count < byte_count)
                    {
                        return 8 * read_count;
                    }
                }
            }
            else
            {
                for (int i = 0; i < byte_count; i++)
                {
                    while (read_buffer_bit_length < 8)
                    {
                        if (stream.Read(byte_buffer, 0, 1) < 1)
                        {
                            int read_count = 8 * i;

                            if (read_buffer_bit_length > 0)
                            {
                                read_count += read_buffer_bit_length;

                                buffer[offset + i] = (byte)read_buffer;

                                read_buffer = 0;

                                read_buffer_bit_length = 0;
                            }

                            return read_count;
                        }

                        read_buffer |= ((int)byte_buffer[0]) << read_buffer_bit_length;

                        read_buffer_bit_length += 8;
                    }

                    buffer[offset + i] = (byte)read_buffer;

                    read_buffer >>= 8;

                    read_buffer_bit_length -= 8;
                }
            }

            int remain = bit_count % 8;

            if (remain != 0)
            {
                while (read_buffer_bit_length < remain)
                {
                    if (stream.Read(byte_buffer, 0, 1) < 1)
                    {
                        int read_count = 8 * byte_count;

                        if (read_buffer_bit_length > 0)
                        {
                            read_count += read_buffer_bit_length;

                            buffer[offset + byte_count] = (byte)read_buffer;

                            read_buffer = 0;

                            read_buffer_bit_length = 0;
                        }

                        return read_count;
                    }

                    read_buffer |= ((int)byte_buffer[0]) << read_buffer_bit_length;

                    read_buffer_bit_length += 8;
                }

                buffer[offset + byte_count] = (byte)(read_buffer & ((1 << remain) - 1));

                read_buffer >>= remain;

                read_buffer_bit_length -= remain;
            }

            return bit_count;
        }

        int write_buffer;

        int write_buffer_bit_length;

        public void WriteBit(byte[] buffer, int offset, int bit_count)
        {
            if (access != Access.Write)
            {
                throw new InvalidOperationException();
            }

            if (bit_count <= 0)
            {
                if (bit_count == 0)
                {
                    return;
                }

                throw new ArgumentOutOfRangeException();
            }

            int byte_count = bit_count / 8;

            if (write_buffer_bit_length == 0)
            {
                if (byte_count > 0)
                {
                    stream.Write(buffer, offset, byte_count);
                }
            }
            else
            {
                for (int i = 0; i < byte_count; i++)
                {
                    write_buffer |= buffer[offset + i] << write_buffer_bit_length;

                    write_buffer_bit_length += 8;

                    while (write_buffer_bit_length >= 8)
                    {
                        byte_buffer[0] = (byte)write_buffer;

                        stream.Write(byte_buffer, 0, 1);

                        write_buffer >>= 8;

                        write_buffer_bit_length -= 8;
                    }
                }
            }

            int remain = bit_count % 8;

            if (remain != 0)
            {
                write_buffer |= buffer[offset + byte_count] << write_buffer_bit_length;

                write_buffer_bit_length += remain;

                while (write_buffer_bit_length >= 8)
                {
                    byte_buffer[0] = (byte)write_buffer;

                    stream.Write(byte_buffer, 0, 1);

                    write_buffer >>= 8;

                    write_buffer_bit_length -= 8;
                }
            }
        }

        public override void Flush()
        {
            if (access == Access.Write)
            {
                if (write_buffer_bit_length > 0)
                {
                    while (write_buffer_bit_length >= 8)
                    {
                        byte_buffer[0] = (byte)write_buffer;

                        stream.Write(byte_buffer, 0, 1);

                        write_buffer >>= 8;

                        write_buffer_bit_length -= 8;
                    }

                    if (write_buffer_bit_length > 0)
                    {
                        byte_buffer[0] = (byte)write_buffer;

                        stream.Write(byte_buffer, 0, 1);

                        write_buffer = 0;

                        write_buffer_bit_length = 0;
                    }
                }
            }
        }

        public override void Close()
        {
            if (access == Access.Write)
            {
                Flush();
            }

            base.Close();
        }

        public static int GetNecessaryBitLength(int value)
        {
            if (value <= 0)
            {
                if (value == 0)
                {
                    return 1;
                }

                return 32;
            }

            int i = 31;

            int bit = 0x40000000;

            while (true)
            {
                if ((value & bit) != 0)
                {
                    return i;
                }

                bit >>= 1;

                i--;
            }
        }

        public static int GetNecessaryBitLength(Int64 value)
        {
            if (value <= 0)
            {
                if (value == 0)
                {
                    return 1;
                }

                return 64;
            }

            int i = 63;

            Int64 bit = 0x4000000000000000L;

            while (true)
            {
                if ((value & bit) != 0)
                {
                    return i;
                }

                bit >>= 1;

                i--;
            }
        }

        public static int RestrictBitLength(int value, int bit_length)
        {
            if (bit_length <= 0 || bit_length >= 32)
            {
                if (bit_length == 0)
                {
                    return 0;
                }

                if (bit_length == 32)
                {
                    return value;
                }

                throw new ArgumentOutOfRangeException();
            }

            return value & ((1 << bit_length) - 1);
        }

        public static Int64 RestrictBitLength(Int64 value, int bit_length)
        {
            if (bit_length <= 0 || bit_length >= 64)
            {
                if (bit_length == 0)
                {
                    return 0;
                }

                if (bit_length == 64)
                {
                    return value;
                }

                throw new ArgumentOutOfRangeException();
            }

            return value & ((1L << bit_length) - 1);
        }
    }
}