1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.nio;
19
20import libcore.io.SizeOf;
21import libcore.io.Memory;
22
23/**
24 * ByteArrayBuffer implements byte[]-backed ByteBuffers.
25 */
26final class ByteArrayBuffer extends ByteBuffer {
27
28  /**
29   * These fields are non-private for NioUtils.unsafeArray.
30   */
31  final byte[] backingArray;
32  final int arrayOffset;
33
34  private final boolean isReadOnly;
35
36  ByteArrayBuffer(byte[] backingArray) {
37    this(backingArray.length, backingArray, 0, false);
38  }
39
40  private ByteArrayBuffer(int capacity, byte[] backingArray, int arrayOffset, boolean isReadOnly) {
41    super(capacity, 0);
42    this.backingArray = backingArray;
43    this.arrayOffset = arrayOffset;
44    this.isReadOnly = isReadOnly;
45    if (arrayOffset + capacity > backingArray.length) {
46      throw new IndexOutOfBoundsException("backingArray.length=" + backingArray.length +
47                                              ", capacity=" + capacity + ", arrayOffset=" + arrayOffset);
48    }
49  }
50
51  private static ByteArrayBuffer copy(ByteArrayBuffer other, int markOfOther, boolean isReadOnly) {
52    ByteArrayBuffer buf = new ByteArrayBuffer(other.capacity(), other.backingArray, other.arrayOffset, isReadOnly);
53    buf.limit = other.limit;
54    buf.position = other.position();
55    buf.mark = markOfOther;
56    return buf;
57  }
58
59  @Override public ByteBuffer asReadOnlyBuffer() {
60    return copy(this, mark, true);
61  }
62
63  @Override public ByteBuffer compact() {
64    if (isReadOnly) {
65      throw new ReadOnlyBufferException();
66    }
67    System.arraycopy(backingArray, position + arrayOffset, backingArray, arrayOffset, remaining());
68    position = limit - position;
69    limit = capacity;
70    mark = UNSET_MARK;
71    return this;
72  }
73
74  @Override public ByteBuffer duplicate() {
75    return copy(this, mark, isReadOnly);
76  }
77
78  @Override public ByteBuffer slice() {
79    return new ByteArrayBuffer(remaining(), backingArray, arrayOffset + position, isReadOnly);
80  }
81
82  @Override public boolean isReadOnly() {
83    return isReadOnly;
84  }
85
86  @Override byte[] protectedArray() {
87    if (isReadOnly) {
88      throw new ReadOnlyBufferException();
89    }
90    return backingArray;
91  }
92
93  @Override int protectedArrayOffset() {
94    if (isReadOnly) {
95      throw new ReadOnlyBufferException();
96    }
97    return arrayOffset;
98  }
99
100  @Override boolean protectedHasArray() {
101    if (isReadOnly) {
102      return false;
103    }
104    return true;
105  }
106
107  @Override public final ByteBuffer get(byte[] dst, int dstOffset, int byteCount) {
108    checkGetBounds(1, dst.length, dstOffset, byteCount);
109    System.arraycopy(backingArray, arrayOffset + position, dst, dstOffset, byteCount);
110    position += byteCount;
111    return this;
112  }
113
114  final void get(char[] dst, int dstOffset, int charCount) {
115    int byteCount = checkGetBounds(SizeOf.CHAR, dst.length, dstOffset, charCount);
116    Memory.unsafeBulkGet(dst, dstOffset, byteCount, backingArray, arrayOffset + position, SizeOf.CHAR, order.needsSwap);
117    position += byteCount;
118  }
119
120  final void get(double[] dst, int dstOffset, int doubleCount) {
121    int byteCount = checkGetBounds(SizeOf.DOUBLE, dst.length, dstOffset, doubleCount);
122    Memory.unsafeBulkGet(dst, dstOffset, byteCount, backingArray, arrayOffset + position, SizeOf.DOUBLE, order.needsSwap);
123    position += byteCount;
124  }
125
126  final void get(float[] dst, int dstOffset, int floatCount) {
127    int byteCount = checkGetBounds(SizeOf.FLOAT, dst.length, dstOffset, floatCount);
128    Memory.unsafeBulkGet(dst, dstOffset, byteCount, backingArray, arrayOffset + position, SizeOf.FLOAT, order.needsSwap);
129    position += byteCount;
130  }
131
132  final void get(int[] dst, int dstOffset, int intCount) {
133    int byteCount = checkGetBounds(SizeOf.INT, dst.length, dstOffset, intCount);
134    Memory.unsafeBulkGet(dst, dstOffset, byteCount, backingArray, arrayOffset + position, SizeOf.INT, order.needsSwap);
135    position += byteCount;
136  }
137
138  final void get(long[] dst, int dstOffset, int longCount) {
139    int byteCount = checkGetBounds(SizeOf.LONG, dst.length, dstOffset, longCount);
140    Memory.unsafeBulkGet(dst, dstOffset, byteCount, backingArray, arrayOffset + position, SizeOf.LONG, order.needsSwap);
141    position += byteCount;
142  }
143
144  final void get(short[] dst, int dstOffset, int shortCount) {
145    int byteCount = checkGetBounds(SizeOf.SHORT, dst.length, dstOffset, shortCount);
146    Memory.unsafeBulkGet(dst, dstOffset, byteCount, backingArray, arrayOffset + position, SizeOf.SHORT, order.needsSwap);
147    position += byteCount;
148  }
149
150  @Override public final byte get() {
151    if (position == limit) {
152      throw new BufferUnderflowException();
153    }
154    return backingArray[arrayOffset + position++];
155  }
156
157  @Override public final byte get(int index) {
158    checkIndex(index);
159    return backingArray[arrayOffset + index];
160  }
161
162  @Override public final char getChar() {
163    int newPosition = position + SizeOf.CHAR;
164    if (newPosition > limit) {
165      throw new BufferUnderflowException();
166    }
167    char result = (char) Memory.peekShort(backingArray, arrayOffset + position, order);
168    position = newPosition;
169    return result;
170  }
171
172  @Override public final char getChar(int index) {
173    checkIndex(index, SizeOf.CHAR);
174    return (char) Memory.peekShort(backingArray, arrayOffset + index, order);
175  }
176
177  @Override public final double getDouble() {
178    return Double.longBitsToDouble(getLong());
179  }
180
181  @Override public final double getDouble(int index) {
182    return Double.longBitsToDouble(getLong(index));
183  }
184
185  @Override public final float getFloat() {
186    return Float.intBitsToFloat(getInt());
187  }
188
189  @Override public final float getFloat(int index) {
190    return Float.intBitsToFloat(getInt(index));
191  }
192
193  @Override public final int getInt() {
194    int newPosition = position + SizeOf.INT;
195    if (newPosition > limit) {
196      throw new BufferUnderflowException();
197    }
198    int result = Memory.peekInt(backingArray, arrayOffset + position, order);
199    position = newPosition;
200    return result;
201  }
202
203  @Override public final int getInt(int index) {
204    checkIndex(index, SizeOf.INT);
205    return Memory.peekInt(backingArray, arrayOffset + index, order);
206  }
207
208  @Override public final long getLong() {
209    int newPosition = position + SizeOf.LONG;
210    if (newPosition > limit) {
211      throw new BufferUnderflowException();
212    }
213    long result = Memory.peekLong(backingArray, arrayOffset + position, order);
214    position = newPosition;
215    return result;
216  }
217
218  @Override public final long getLong(int index) {
219    checkIndex(index, SizeOf.LONG);
220    return Memory.peekLong(backingArray, arrayOffset + index, order);
221  }
222
223  @Override public final short getShort() {
224    int newPosition = position + SizeOf.SHORT;
225    if (newPosition > limit) {
226      throw new BufferUnderflowException();
227    }
228    short result = Memory.peekShort(backingArray, arrayOffset + position, order);
229    position = newPosition;
230    return result;
231  }
232
233  @Override public final short getShort(int index) {
234    checkIndex(index, SizeOf.SHORT);
235    return Memory.peekShort(backingArray, arrayOffset + index, order);
236  }
237
238  @Override public final boolean isDirect() {
239    return false;
240  }
241
242  @Override public ByteBuffer put(byte b) {
243    if (isReadOnly) {
244      throw new ReadOnlyBufferException();
245    }
246    if (position == limit) {
247      throw new BufferOverflowException();
248    }
249    backingArray[arrayOffset + position++] = b;
250    return this;
251  }
252
253  @Override public ByteBuffer put(int index, byte b) {
254    if (isReadOnly) {
255      throw new ReadOnlyBufferException();
256    }
257    checkIndex(index);
258    backingArray[arrayOffset + index] = b;
259    return this;
260  }
261
262  @Override public ByteBuffer put(byte[] src, int srcOffset, int byteCount) {
263    if (isReadOnly) {
264      throw new ReadOnlyBufferException();
265    }
266    checkPutBounds(1, src.length, srcOffset, byteCount);
267    System.arraycopy(src, srcOffset, backingArray, arrayOffset + position, byteCount);
268    position += byteCount;
269    return this;
270  }
271
272  final void put(char[] src, int srcOffset, int charCount) {
273    int byteCount = checkPutBounds(SizeOf.CHAR, src.length, srcOffset, charCount);
274    Memory.unsafeBulkPut(backingArray, arrayOffset + position, byteCount, src, srcOffset, SizeOf.CHAR, order.needsSwap);
275    position += byteCount;
276  }
277
278  final void put(double[] src, int srcOffset, int doubleCount) {
279    int byteCount = checkPutBounds(SizeOf.DOUBLE, src.length, srcOffset, doubleCount);
280    Memory.unsafeBulkPut(backingArray, arrayOffset + position, byteCount, src, srcOffset, SizeOf.DOUBLE, order.needsSwap);
281    position += byteCount;
282  }
283
284  final void put(float[] src, int srcOffset, int floatCount) {
285    int byteCount = checkPutBounds(SizeOf.FLOAT, src.length, srcOffset, floatCount);
286    Memory.unsafeBulkPut(backingArray, arrayOffset + position, byteCount, src, srcOffset, SizeOf.FLOAT, order.needsSwap);
287    position += byteCount;
288  }
289
290  final void put(int[] src, int srcOffset, int intCount) {
291    int byteCount = checkPutBounds(SizeOf.INT, src.length, srcOffset, intCount);
292    Memory.unsafeBulkPut(backingArray, arrayOffset + position, byteCount, src, srcOffset, SizeOf.INT, order.needsSwap);
293    position += byteCount;
294  }
295
296  final void put(long[] src, int srcOffset, int longCount) {
297    int byteCount = checkPutBounds(SizeOf.LONG, src.length, srcOffset, longCount);
298    Memory.unsafeBulkPut(backingArray, arrayOffset + position, byteCount, src, srcOffset, SizeOf.LONG, order.needsSwap);
299    position += byteCount;
300  }
301
302  final void put(short[] src, int srcOffset, int shortCount) {
303    int byteCount = checkPutBounds(SizeOf.SHORT, src.length, srcOffset, shortCount);
304    Memory.unsafeBulkPut(backingArray, arrayOffset + position, byteCount, src, srcOffset, SizeOf.SHORT, order.needsSwap);
305    position += byteCount;
306  }
307
308  @Override public ByteBuffer putChar(int index, char value) {
309    if (isReadOnly) {
310      throw new ReadOnlyBufferException();
311    }
312    checkIndex(index, SizeOf.CHAR);
313    Memory.pokeShort(backingArray, arrayOffset + index, (short) value, order);
314    return this;
315  }
316
317  @Override public ByteBuffer putChar(char value) {
318    if (isReadOnly) {
319      throw new ReadOnlyBufferException();
320    }
321    int newPosition = position + SizeOf.CHAR;
322    if (newPosition > limit) {
323      throw new BufferOverflowException();
324    }
325    Memory.pokeShort(backingArray, arrayOffset + position, (short) value, order);
326    position = newPosition;
327    return this;
328  }
329
330  @Override public ByteBuffer putDouble(double value) {
331    return putLong(Double.doubleToRawLongBits(value));
332  }
333
334  @Override public ByteBuffer putDouble(int index, double value) {
335    return putLong(index, Double.doubleToRawLongBits(value));
336  }
337
338  @Override public ByteBuffer putFloat(float value) {
339    return putInt(Float.floatToRawIntBits(value));
340  }
341
342  @Override public ByteBuffer putFloat(int index, float value) {
343    return putInt(index, Float.floatToRawIntBits(value));
344  }
345
346  @Override public ByteBuffer putInt(int value) {
347    if (isReadOnly) {
348      throw new ReadOnlyBufferException();
349    }
350    int newPosition = position + SizeOf.INT;
351    if (newPosition > limit) {
352      throw new BufferOverflowException();
353    }
354    Memory.pokeInt(backingArray, arrayOffset + position, value, order);
355    position = newPosition;
356    return this;
357  }
358
359  @Override public ByteBuffer putInt(int index, int value) {
360    if (isReadOnly) {
361      throw new ReadOnlyBufferException();
362    }
363    checkIndex(index, SizeOf.INT);
364    Memory.pokeInt(backingArray, arrayOffset + index, value, order);
365    return this;
366  }
367
368  @Override public ByteBuffer putLong(int index, long value) {
369    if (isReadOnly) {
370      throw new ReadOnlyBufferException();
371    }
372    checkIndex(index, SizeOf.LONG);
373    Memory.pokeLong(backingArray, arrayOffset + index, value, order);
374    return this;
375  }
376
377  @Override public ByteBuffer putLong(long value) {
378    if (isReadOnly) {
379      throw new ReadOnlyBufferException();
380    }
381    int newPosition = position + SizeOf.LONG;
382    if (newPosition > limit) {
383      throw new BufferOverflowException();
384    }
385    Memory.pokeLong(backingArray, arrayOffset + position, value, order);
386    position = newPosition;
387    return this;
388  }
389
390  @Override public ByteBuffer putShort(int index, short value) {
391    if (isReadOnly) {
392      throw new ReadOnlyBufferException();
393    }
394    checkIndex(index, SizeOf.SHORT);
395    Memory.pokeShort(backingArray, arrayOffset + index, value, order);
396    return this;
397  }
398
399  @Override public ByteBuffer putShort(short value) {
400    if (isReadOnly) {
401      throw new ReadOnlyBufferException();
402    }
403    int newPosition = position + SizeOf.SHORT;
404    if (newPosition > limit) {
405      throw new BufferOverflowException();
406    }
407    Memory.pokeShort(backingArray, arrayOffset + position, value, order);
408    position = newPosition;
409    return this;
410  }
411
412  @Override public final CharBuffer asCharBuffer() {
413    return ByteBufferAsCharBuffer.asCharBuffer(this);
414  }
415
416  @Override public final DoubleBuffer asDoubleBuffer() {
417    return ByteBufferAsDoubleBuffer.asDoubleBuffer(this);
418  }
419
420  @Override public final FloatBuffer asFloatBuffer() {
421    return ByteBufferAsFloatBuffer.asFloatBuffer(this);
422  }
423
424  @Override public final IntBuffer asIntBuffer() {
425    return ByteBufferAsIntBuffer.asIntBuffer(this);
426  }
427
428  @Override public final LongBuffer asLongBuffer() {
429    return ByteBufferAsLongBuffer.asLongBuffer(this);
430  }
431
432  @Override public final ShortBuffer asShortBuffer() {
433    return ByteBufferAsShortBuffer.asShortBuffer(this);
434  }
435}
436