Libraryless. Click here for Pure Java version (13163L/75K).
| 1 | sclass BitHead > ByteHead {
 | 
| 2 | gettable int align = 8; | 
| 3 | gettable int currentByte; | 
| 4 | settable bool debug; | 
| 5 | |
| 6 | replace SomethingIO with BitIO. | 
| 7 | replace print with if (debug) print. | 
| 8 | |
| 9 |   *() {}
 | 
| 10 |   *(InputStream inputStream) { super(inputStream); }
 | 
| 11 |   *(OutputStream outputStream) { super(outputStream); }
 | 
| 12 | |
| 13 |   bool writeArraysSlowly() { false; }
 | 
| 14 | |
| 15 | // choose fast or slow version depending on alignment | 
| 16 |   void write(byte[] data) {
 | 
| 17 | if (align == 0 && !writeArraysSlowly()) | 
| 18 | super.write(data); | 
| 19 | else | 
| 20 | for (b : data) write(b); | 
| 21 | } | 
| 22 | |
| 23 |   void writeByte(int i) {
 | 
| 24 | i &= 0xFF; | 
| 25 | |
| 26 |     print("writeByte: align=" + align + ", byteCounter=" + byteCounter + ", value=" + i);
 | 
| 27 | if (align == 0) | 
| 28 | super.writeByte(i); | 
| 29 |     else {
 | 
| 30 | currentByte |= i << align; | 
| 31 | super.writeByte(currentByte); | 
| 32 | currentByte = i >> (8-align); | 
| 33 | } | 
| 34 | } | 
| 35 | |
| 36 |   void writePartialByte(int i, int bits) {
 | 
| 37 |     for bit to bits: {
 | 
| 38 | writeBit(i); | 
| 39 | i >>>= 1; | 
| 40 | } | 
| 41 | } | 
| 42 | |
| 43 |   void writeBit(int i) {
 | 
| 44 | writeBit((i & 1) != 0); | 
| 45 | } | 
| 46 | |
| 47 |   void writeBit(bool b) {
 | 
| 48 | align &= 7; | 
| 49 | if (b) currentByte |= 1 << align; | 
| 50 |     if (align == 7) {
 | 
| 51 | super.writeByte(currentByte); | 
| 52 | currentByte = align = 0; | 
| 53 | } else | 
| 54 | ++align; | 
| 55 | } | 
| 56 | |
| 57 |   int readPartialByte(int bits) {
 | 
| 58 | int value = 0; | 
| 59 | for bit to bits: | 
| 60 | if (readBit()) value |= 1 << bit; | 
| 61 | ret isEOF() ? -1 : value; | 
| 62 | } | 
| 63 | |
| 64 |   int readByte() {
 | 
| 65 |     print("readByte: align=" + align + ", byteCounter=" + byteCounter);
 | 
| 66 | int value; | 
| 67 |     if (align == 0) {
 | 
| 68 | value = currentByte; | 
| 69 | align = 8; | 
| 70 | } else if (align == 8) | 
| 71 | value = super.readByte(); | 
| 72 |     else {
 | 
| 73 | value = currentByte >> align; | 
| 74 | int align = this.align; | 
| 75 | bufferNextByte(); | 
| 76 | if (isEOF()) ret -1; | 
| 77 | this.align = align; | 
| 78 | value |= (currentByte << (8-align)) & 0xFF; | 
| 79 | } | 
| 80 | |
| 81 |     print("value: " + value);
 | 
| 82 | ret value; | 
| 83 | } | 
| 84 | |
| 85 |   bool readBit() {
 | 
| 86 | bool bitSet = peekBit(); | 
| 87 | advanceBit(); | 
| 88 | ret bitSet; | 
| 89 | } | 
| 90 | |
| 91 |   bool peekBit() {
 | 
| 92 | if (currentByte < 0) | 
| 93 |       fail("eof");
 | 
| 94 | |
| 95 | if (align == 8) | 
| 96 | bufferNextByte(); | 
| 97 | ret (currentByte & (1 << align)) != 0; | 
| 98 | } | 
| 99 | |
| 100 |   void bufferNextByte {
 | 
| 101 | currentByte = super.readByte(); | 
| 102 | align = 0; | 
| 103 | } | 
| 104 | |
| 105 |   void advanceBit {
 | 
| 106 | if (currentByte < 0) ret; | 
| 107 | if (align == 8) | 
| 108 | bufferNextByte(); | 
| 109 | ++align; | 
| 110 | } | 
| 111 | |
| 112 |   bool byteAligned() {
 | 
| 113 | ret (align & 7) == 0; | 
| 114 | } | 
| 115 | |
| 116 |   void completeByte aka flushBits aka finishByte aka finish(bool padWithOnes default false) {
 | 
| 117 |     print("Finishing byte " + byteCounter + " (align " + align + ")");
 | 
| 118 | if (byteAligned()) ret; | 
| 119 | |
| 120 |     if (writeMode()) {
 | 
| 121 | if (padWithOnes) currentByte |= 0xFF << align; | 
| 122 | super.writeByte(currentByte); | 
| 123 | } | 
| 124 | currentByte = 0; | 
| 125 | align = readMode() ? 8 : 0; | 
| 126 | } | 
| 127 | |
| 128 | // TODO: switch to more compact version saving 5 bits on average | 
| 129 |   void writeTrailingBitCount aka trailingBitCount(bool padWithOnes default false) {
 | 
| 130 | if (!writeMode()) ret; | 
| 131 | |
| 132 | int bitCount = modRange_incl(align(), 1, 8); | 
| 133 | completeByte(padWithOnes); | 
| 134 | writeByte(bitCount); | 
| 135 | } | 
| 136 | |
| 137 |   void exchange(SomethingIO writable) {
 | 
| 138 | if (writable != null) writable.readWrite(this); | 
| 139 | } | 
| 140 | |
| 141 |   void exchangeBit(IF0<Bool> getter, IVF1<Bool> setter) {
 | 
| 142 | if (writeMode()) | 
| 143 | writeBit(getter!); | 
| 144 | |
| 145 | if (readMode()) | 
| 146 | setter.get(readBit()); | 
| 147 | } | 
| 148 | |
| 149 |   void exchangeBit(int i) { exchangeBit(odd(i)); }
 | 
| 150 |   void exchangeBit(bool i) {
 | 
| 151 | exchangeBit(-> i, j -> assertEquals(i, j)); | 
| 152 | } | 
| 153 | |
| 154 |   void exchange(BitIO getter, Runnable setter) {
 | 
| 155 | if (writeMode()) | 
| 156 | getter.readWrite(this); | 
| 157 | |
| 158 | if (readMode()) | 
| 159 | setter.run(); | 
| 160 | } | 
| 161 | |
| 162 |   bool isEOF() { ret currentByte < 0; }
 | 
| 163 | } | 
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: | 790 / 1065 | 
| Version history: | 55 change(s) | 
| Referenced in: | [show references] |