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