Skip to content

Commit 1dad6e9

Browse files
committed
BAOS, BAIS
1 parent 2eb8487 commit 1dad6e9

File tree

8 files changed

+2924
-1
lines changed

8 files changed

+2924
-1
lines changed

build.gradle

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ dependencies {
7878

7979
api('it.unimi.dsi:fastutil:latest.release')
8080
compileOnly('org.jctools:jctools-core:latest.release')
81-
compileOnly('org.jspecify:jspecify:latest.release')
81+
implementation('org.jspecify:jspecify:latest.release')
82+
// https://javadoc.io/doc/com.google.errorprone/error_prone_annotations/latest/index.html E.g: @CanIgnoreReturnValue
83+
compileOnly("com.google.errorprone:error_prone_annotations:latest.release")
8284
compileOnly('jakarta.validation:jakarta.validation-api:latest.release')
8385

8486
// TEST
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
package com.trivago.fastutilconcurrentwrapper.io;
2+
3+
import it.unimi.dsi.fastutil.io.MeasurableStream;
4+
import it.unimi.dsi.fastutil.io.RepositionableStream;
5+
import jakarta.validation.constraints.PositiveOrZero;
6+
import lombok.val;
7+
import org.jspecify.annotations.Nullable;
8+
9+
import java.io.ByteArrayInputStream;
10+
import java.io.DataInputStream;
11+
import java.io.IOException;
12+
import java.io.ObjectInput;
13+
import java.io.ObjectInputStream;
14+
import java.io.UTFDataFormatException;
15+
import java.util.UUID;
16+
17+
/**
18+
@see java.io.ByteArrayInputStream
19+
20+
@see it.unimi.dsi.fastutil.io.FastByteArrayInputStream
21+
22+
@see it.unimi.dsi.fastutil.io.FastMultiByteArrayInputStream
23+
@see it.unimi.dsi.fastutil.io.FastBufferedInputStream
24+
25+
@author Andrej Fink [https://magicprinc.github.io]
26+
*/
27+
@SuppressWarnings({"NonSynchronizedMethodOverridesSynchronizedMethod", "ResultOfMethodCallIgnored"})
28+
public class BAIS extends ByteArrayInputStream implements ObjectInput, MeasurableStream, RepositionableStream, SafeCloseable {
29+
protected int offset;
30+
31+
public BAIS (byte[] array, @PositiveOrZero int offset, @PositiveOrZero int maxLength) {
32+
super(array, offset, maxLength);
33+
this.offset = offset;
34+
pos = mark = 0;
35+
count = Math.min(maxLength, array.length - offset);// offset|0..pos..length|...array.length
36+
}//new
37+
38+
public BAIS (byte[] array){ super(array); }//new
39+
40+
public BAIS (BAOS baos) {
41+
super(baos.array(), 0, baos.size());
42+
}//new
43+
44+
/// The array backing the input stream. capacity = array().length
45+
public byte[] array (){ return buf; }
46+
public void array (byte[] array, @PositiveOrZero int offset, @PositiveOrZero int maxLength){
47+
buf = array;
48+
this.offset = offset;
49+
pos = mark = 0;
50+
count = Math.min(maxLength, array.length - offset);
51+
}
52+
53+
/** The first valid entry. aka {@link #position()} */
54+
public @PositiveOrZero int offset (){ return offset; }
55+
public void offset (@PositiveOrZero int newOffset){ offset = newOffset; }
56+
57+
/** The current position as a distance from {@link #offset}. */
58+
@Override public long position (){ return pos; }
59+
public int readerIndex (){ return pos; }
60+
61+
public int markIndex (){ return mark; }
62+
63+
@Override
64+
public void position (long newPosition) {
65+
pos = (int)Math.min(newPosition, limit());
66+
}
67+
public void readerIndex (int newReaderIndex) {
68+
pos = Math.min(newReaderIndex, limit());
69+
}
70+
71+
/** The number of valid bytes in {@link #array} starting from {@link #offset}. */
72+
@Override public @PositiveOrZero long length (){ return count; }
73+
public @PositiveOrZero int limit (){ return count; }
74+
75+
public void limit (@PositiveOrZero int maxLength){ count = Math.min(maxLength, array().length - offset); }
76+
77+
/** Closing a fast byte array input stream has no effect. */
78+
@Override public void close (){}
79+
80+
@Override public int available (){ return count - pos; }// length - position
81+
82+
@Override
83+
public long skip (@PositiveOrZero long n) {
84+
int avail = count - pos;
85+
if (n <= avail){
86+
pos += (int)n;
87+
return n;
88+
}
89+
n = avail;
90+
pos = count;// position = length
91+
return n;
92+
}
93+
94+
@Override
95+
public int read () {
96+
if (count <= pos) return -1;// EOF
97+
return buf[offset + pos++] & 0xFF;
98+
}
99+
100+
/**
101+
Reads bytes from this byte-array input stream as specified in {@link java.io.InputStream#read(byte[], int, int)}.
102+
103+
Note! The implementation given in {@link java.io.ByteArrayInputStream#read(byte[], int, int)} will return -1
104+
on a 0-length read at EOF, contrarily to the specification. We won't.
105+
*/
106+
@Override
107+
public int read (byte[] b, @PositiveOrZero int fromOffset, @PositiveOrZero int length) {
108+
if (this.count <= this.pos) return length == 0 ? 0 : -1;
109+
int n = Math.min(length, this.count - this.pos);
110+
System.arraycopy(buf, this.offset + this.pos, b, fromOffset, n);
111+
pos += n;
112+
return n;
113+
}
114+
115+
@Override
116+
public byte[] readAllBytes () {
117+
return readNBytes(available());
118+
}
119+
120+
@Override
121+
public int read (byte[] b) {
122+
return read(b, 0, b.length);
123+
}
124+
125+
@Override
126+
public byte[] readNBytes (int len) {
127+
int n = Math.min(len, available());
128+
val result = new byte[n];
129+
read(result);
130+
return result;
131+
}
132+
133+
@Override public void skipNBytes (long n){ skip(n); }
134+
135+
// read next byte without shifting readerIndex
136+
public int peek () {
137+
if (count <= pos) return -1;
138+
return buf[offset + pos] & 0xFF;
139+
}
140+
141+
@Override public void readFully (byte[] b){ read(b); }
142+
143+
@Override
144+
public void readFully (byte[] b, int off, int len) {
145+
read(b, off, len);
146+
}
147+
148+
@Override public int skipBytes (@PositiveOrZero int n){ return (int) skip(n); }//DataInput#skipBytes
149+
150+
@Override
151+
public boolean readBoolean () {
152+
return read() != 0;
153+
}
154+
155+
@Override public byte readByte (){ return (byte) read(); }
156+
157+
@Override public int readUnsignedByte (){ return read() & 0xFF; }
158+
159+
/// @see DataInputStream#readShort
160+
/// (short)((read() << 8)|(read() & 0xFF))
161+
@Override
162+
public short readShort() {
163+
return (short)((read() << 8)|(read() & 0xFF));
164+
}
165+
166+
@Override
167+
public int readUnsignedShort() {
168+
return ((read() & 0xFF) << 8)|(read() & 0xFF);
169+
}
170+
171+
@Override
172+
public char readChar() {
173+
return (char)(((read() & 0xFF) << 8)|(read() & 0xFF));
174+
}
175+
176+
@Override
177+
public int readInt() {
178+
return read() << 24 | ((read() & 0xFF) << 16) | ((read() & 0xFF) << 8) | (read() & 0xFF);
179+
}
180+
181+
public int readMedium () {
182+
return ((read() & 0xFF) << 16) | ((read() & 0xFF) << 8) | (read() & 0xFF);
183+
}
184+
185+
/// @see UUID#UUID(long, long)
186+
/// @see UUID#fromString(String)
187+
public UUID readUUID () {
188+
//val bb = ByteBuffer.wrap(bytes); long mostSigBits = bb.getLong(); long leastSigBits = bb.getLong(); быстрее за счёт VarHandle
189+
long mostSigBits = readLong();// 0..7
190+
long leastSigBits = readLong();// 8..15
191+
return new UUID(mostSigBits, leastSigBits);
192+
}
193+
194+
@Override
195+
public long readLong () {
196+
return (long) readInt() << 32 | (readInt() & 0xFFFF_FFFFL);
197+
}
198+
199+
@Override
200+
public float readFloat () {
201+
return Float.intBitsToFloat(readInt());
202+
}
203+
204+
@Override
205+
public double readDouble () {
206+
return Double.longBitsToDouble(readLong());
207+
}
208+
209+
@Override @Deprecated
210+
public String readLine () {
211+
val sb = new StringBuilder(160);
212+
loop:
213+
for (int c;;){
214+
switch (c = read()){
215+
case -1:
216+
break loop;// eof
217+
218+
case '\n':
219+
return sb.toString();
220+
case '\r':
221+
if (peek() == '\n') // CR LF
222+
read();
223+
return sb.toString();
224+
225+
default:
226+
sb.append((char) c);
227+
}
228+
}
229+
return sb.isEmpty() ? null : sb.toString();
230+
}
231+
232+
@Override
233+
public @Nullable String readUTF () throws UTFDataFormatException {
234+
try {
235+
return available() > 2 ? DataInputStream.readUTF(this) : null;
236+
} catch (UTFDataFormatException badBinaryFormatting){
237+
throw badBinaryFormatting;
238+
} catch (IOException e){
239+
val t = new UTFDataFormatException("IOException: readUTF @ "+ this);
240+
t.initCause(e);
241+
throw t;
242+
}
243+
}
244+
245+
/// not efficient! Only added to support custom {@link java.io.Externalizable}
246+
/// todo size instead of magic prefix; see io.netty.handler.codec.serialization.CompactObjectInputStream
247+
@Override
248+
public Object readObject () throws ClassNotFoundException, IOException {
249+
try (val ois = new ObjectInputStream(this)){
250+
return ois.readObject();
251+
}
252+
}
253+
254+
/// @see BAOS#writeBytes(String)
255+
/// @see java.nio.charset.StandardCharsets#ISO_8859_1
256+
public String readLatin1String (@PositiveOrZero int strLen) {
257+
String s = new String(buf, 0, pos, strLen);
258+
pos += strLen;
259+
return s;
260+
}
261+
}

0 commit comments

Comments
 (0)