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: | 847 / 1129 |
| Version history: | 55 change(s) |
| Referenced in: | [show references] |