Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

163
LINES

< > BotCompany Repo | #1035655 // BitHead - ByteHead that can write individual bits (and non-byte-aligned bytes and partial bytes)

JavaX fragment (include) [tags: use-pretranspiled]

Libraryless. Click here for Pure Java version (13163L/75K).

sclass BitHead > ByteHead {
  gettable int align = 8;
  gettable int currentByte;
  settable bool debug;

  replace SomethingIO with BitIO.
  replace print with if (debug) print.
  
  *() {}
  *(InputStream inputStream) { super(inputStream); }
  *(OutputStream outputStream) { super(outputStream); }
  
  bool writeArraysSlowly() { false; }

  // choose fast or slow version depending on alignment
  void write(byte[] data) {
    if (align == 0 && !writeArraysSlowly())
      super.write(data);
    else
      for (b : data) write(b);
  }
  
  void writeByte(int i) {
    i &= 0xFF;
    
    print("writeByte: align=" + align + ", byteCounter=" + byteCounter + ", value=" + i);
    if (align == 0)
      super.writeByte(i);
    else {
      currentByte |= i << align;
      super.writeByte(currentByte);
      currentByte = i >> (8-align);
    }
  }

  void writePartialByte(int i, int bits) {
    for bit to bits: {
      writeBit(i);
      i >>>= 1;
    }
  }
  
  void writeBit(int i) {
    writeBit((i & 1) != 0);
  }
  
  void writeBit(bool b) {
    align &= 7;
    if (b) currentByte |= 1 << align;
    if (align == 7) {
      super.writeByte(currentByte);
      currentByte = align = 0;
    } else
      ++align;
  }
  
  int readPartialByte(int bits) {
    int value = 0;
    for bit to bits:
      if (readBit()) value |= 1 << bit;
    ret isEOF() ? -1 : value;
  }
  
  int readByte() {
    print("readByte: align=" + align + ", byteCounter=" + byteCounter);
    int value;
    if (align == 0) {
      value = currentByte;
      align = 8;
    } else if (align == 8)
      value = super.readByte();
    else {
      value = currentByte >> align;
      int align = this.align;
      bufferNextByte();
      if (isEOF()) ret -1;
      this.align = align;
      value |= (currentByte << (8-align)) & 0xFF;
    }
    
    print("value: " + value);
    ret value;
  }
  
  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 {
    currentByte = super.readByte();
    align = 0;
  }
  
  void advanceBit {
    if (currentByte < 0) ret;
    if (align == 8)
      bufferNextByte();
    ++align;
  }
  
  bool byteAligned() {
    ret (align & 7) == 0;
  }
  
  void completeByte aka flushBits aka finishByte aka finish(bool padWithOnes default false) {
    print("Finishing byte " + byteCounter + " (align " + align + ")");
    if (byteAligned()) ret;
    
    if (writeMode()) {
      if (padWithOnes) currentByte |= 0xFF << align;
      super.writeByte(currentByte);
    }
    currentByte = 0;
    align = readMode() ? 8 : 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<Bool> getter, IVF1<Bool> 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())
      getter.readWrite(this);
    
    if (readMode())
      setter.run();
  }
  
  bool isEOF() { ret currentByte < 0; }
}

Author comment

Began life as a copy of #1035632

download  show line numbers  debug dex  old transpilations   

Travelled to 2 computer(s): elmgxqgtpvxh, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1035655
Snippet name: BitHead - ByteHead that can write individual bits (and non-byte-aligned bytes and partial bytes)
Eternal ID of this version: #1035655/56
Text MD5: 6c7a0725aa50d99764dff38fe513fa4d
Transpilation MD5: 9f070c46881096d3bf677774469803ae
Author: stefan
Category: javax / io
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-07-15 20:59:06
Source code size: 3802 bytes / 163 lines
Pitched / IR pitched: No / No
Views / Downloads: 298 / 522
Version history: 55 change(s)
Referenced in: [show references]