sclass BitHead > ByteHead { gettable int align = 8; gettable int currentByte; int eofBits; int nextByte; replace SomethingIO with BitIO. *() {} *(InputStream inputStream) { super(inputStream); } *(OutputStream outputStream) { super(outputStream); } // choose fast or slow version depending on alignment void write(byte[] data) { if (align == 0) super.write(data); else for (b : data) write(b); } void writeByte(int i) { if (align == 0) super.writeByte(i); else { currentByte |= i << align; super.writeByte(currentByte); currentByte = i >> (8-align); } } void writeBit(int i) { writeBit((i & 1) != 0); } void writeBit(bool b) { if (b) currentByte |= 1 << align; if (align == 7) { super.writeByte(currentByte); currentByte = align = 0; } else ++align; } bool readBit() { bool bitSet = peekBit(); advanceBit(); ret bitSet; } bool peekBit() { if (currentByte < 0) fail("eof"); if (align == 8) bufferNextByte(); ret (currentByte & (1 << align)) != 0; } void bufferNextByte { if (align == 8) { // first read ever currentByte = read(); align = 0; if (currentByte < 0) ret; // EOF nextByte = read(); } else { currentByte = nextByte; if (currentByte >= 0) nextByte = read(); } } bool isEOF() { } void advanceBit { if (currentByte < 0) ret; if (align == 7) bufferNextByte(); else ++align; } bool byteAligned() { ret align == 0; } void completeByte aka flushBits aka finish(bool padWithOnes default false) { if (byteAligned()) ret; if (padWithOnes) currentByte |= 0xFF << align; super.writeByte(currentByte); currentByte = align = 0; } // TODO: switch to more compact version saving 5 bits on average void writeTrailingBitCount aka trailingBitCount(bool padWithOnes default false) { if (!writeMode()) ret; int bitCount = modRange_incl(align(), 1, 8); completeByte(padWithOnes); writeByte(bitCount); } void exchange(SomethingIO writable) { if (writable != null) writable.readWrite(this); } void exchangeBit(IF0 getter, IVF1 setter) { if (writeMode()) writeBit(getter!); if (readMode()) setter.get(readBit()); } void exchangeBit(int i) { exchangeBit(odd(i)); } void exchangeBit(bool i) { exchangeBit(-> i, j -> assertEquals(i, j)); } void exchange(BitIO getter, Runnable setter) { if (writeMode()) setter.run(); if (readMode()) getter.readWrite(this); } }