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