| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package java.nio; |
| |
| import java.nio.channels.FileChannel.MapMode; |
| import libcore.io.SizeOf; |
| |
| /** |
| * Rather than duplicate all the code from ReadOnlyDirectByteBuffer and |
| * ReadWriteDirectByteBuffer (and their superclasses), we delegate to one or the other. |
| * The tricky part is that we need to keep our fields in sync with our delegate's fields. |
| * There are lots of methods that access the fields directly. |
| * |
| * The main consequences of this implementation are: |
| * |
| * 1. we need to explicitly call wrapped.position(int) before any operation on our delegate |
| * that makes use of the implicit position. |
| * |
| * 2. we need to explicitly update position after any operation on our delegate that makes |
| * use of the implicit position. |
| * |
| * This means that, even more than usual, the implicit iteration |
| * operations are more expensive than the indexed operations. |
| * |
| * But we save a ton of code, for classes that no-one really uses because the API's broken |
| * by design (disallowing munmap(2) calls). Internally, we can use libcore.io.MemoryMappedFile |
| * as a high-performance and more usable replacement for MappedByteBuffer. |
| * |
| * FIXME: harmony changed their implementation after we diverged, switching to a scheme |
| * where DirectByteBuffer extends MappedByteBuffer and this class doesn't exist. That's |
| * much better than their original implementation, fossilized here. |
| */ |
| final class MappedByteBufferAdapter extends MappedByteBuffer { |
| private MappedByteBufferAdapter(ByteBuffer buffer) { |
| super(buffer); |
| effectiveDirectAddress = wrapped.effectiveDirectAddress; |
| } |
| |
| public MappedByteBufferAdapter(MemoryBlock block, int capacity, int offset, MapMode mode) { |
| super(block, capacity, offset, mode); |
| effectiveDirectAddress = wrapped.effectiveDirectAddress; |
| } |
| |
| @Override void limitImpl(int newLimit) { |
| super.limitImpl(newLimit); |
| wrapped.limit(newLimit); |
| } |
| |
| @Override void positionImpl(int newPosition) { |
| super.positionImpl(newPosition); |
| wrapped.position(newPosition); |
| } |
| |
| @Override |
| public CharBuffer asCharBuffer() { |
| return wrapped.asCharBuffer(); |
| } |
| |
| @Override |
| public DoubleBuffer asDoubleBuffer() { |
| return wrapped.asDoubleBuffer(); |
| } |
| |
| @Override |
| public FloatBuffer asFloatBuffer() { |
| return wrapped.asFloatBuffer(); |
| } |
| |
| @Override |
| public IntBuffer asIntBuffer() { |
| return wrapped.asIntBuffer(); |
| } |
| |
| @Override |
| public LongBuffer asLongBuffer() { |
| return wrapped.asLongBuffer(); |
| } |
| |
| @Override |
| public ByteBuffer asReadOnlyBuffer() { |
| MappedByteBufferAdapter result = new MappedByteBufferAdapter(wrapped.asReadOnlyBuffer()); |
| result.limit(limit); |
| result.position(position); |
| result.mark = mark; |
| return result; |
| } |
| |
| @Override |
| public ShortBuffer asShortBuffer() { |
| return wrapped.asShortBuffer(); |
| } |
| |
| @Override |
| public ByteBuffer compact() { |
| if (wrapped.isReadOnly()) { |
| throw new ReadOnlyBufferException(); |
| } |
| wrapped.compact(); |
| limit(capacity); |
| position(wrapped.position()); |
| this.mark = UNSET_MARK; |
| return this; |
| } |
| |
| @Override |
| public ByteBuffer duplicate() { |
| MappedByteBufferAdapter result = new MappedByteBufferAdapter(wrapped.duplicate()); |
| result.limit(limit); |
| result.position(position); |
| result.mark = mark; |
| return result; |
| } |
| |
| @Override |
| public byte get() { |
| wrapped.position(position); |
| byte result = wrapped.get(); |
| ++position; |
| return result; |
| } |
| |
| @Override |
| public byte get(int index) { |
| return wrapped.get(index); |
| } |
| |
| @Override |
| public ByteBuffer get(byte[] dst, int dstOffset, int byteCount) { |
| ByteBuffer result = wrapped.get(dst, dstOffset, byteCount); |
| position += byteCount; |
| return result; |
| } |
| |
| @Override |
| public char getChar() { |
| wrapped.position(position); |
| char result = wrapped.getChar(); |
| position += SizeOf.CHAR; |
| return result; |
| } |
| |
| @Override |
| public char getChar(int index) { |
| return wrapped.getChar(index); |
| } |
| |
| @Override |
| public double getDouble() { |
| wrapped.position(position); |
| double result = wrapped.getDouble(); |
| position += SizeOf.DOUBLE; |
| return result; |
| } |
| |
| @Override |
| public double getDouble(int index) { |
| return wrapped.getDouble(index); |
| } |
| |
| @Override |
| public float getFloat() { |
| wrapped.position(position); |
| float result = wrapped.getFloat(); |
| position += SizeOf.FLOAT; |
| return result; |
| } |
| |
| @Override |
| public float getFloat(int index) { |
| return wrapped.getFloat(index); |
| } |
| |
| @Override |
| public int getInt() { |
| wrapped.position(position); |
| int result = wrapped.getInt(); |
| position += SizeOf.INT; |
| return result; |
| } |
| |
| @Override |
| public int getInt(int index) { |
| return wrapped.getInt(index); |
| } |
| |
| @Override |
| public long getLong() { |
| wrapped.position(position); |
| long result = wrapped.getLong(); |
| position += SizeOf.LONG; |
| return result; |
| } |
| |
| @Override |
| public long getLong(int index) { |
| return wrapped.getLong(index); |
| } |
| |
| @Override |
| public short getShort() { |
| wrapped.position(position); |
| short result = wrapped.getShort(); |
| position += SizeOf.SHORT; |
| return result; |
| } |
| |
| @Override |
| public short getShort(int index) { |
| return wrapped.getShort(index); |
| } |
| |
| @Override |
| public boolean isDirect() { |
| return true; |
| } |
| |
| @Override |
| public boolean isReadOnly() { |
| return wrapped.isReadOnly(); |
| } |
| |
| @Override void orderImpl(ByteOrder byteOrder) { |
| super.orderImpl(byteOrder); |
| wrapped.order(byteOrder); |
| } |
| |
| @Override |
| public ByteBuffer put(byte b) { |
| wrapped.position(this.position); |
| wrapped.put(b); |
| this.position++; |
| return this; |
| } |
| |
| @Override |
| public ByteBuffer put(byte[] src, int srcOffset, int byteCount) { |
| wrapped.position(this.position); |
| wrapped.put(src, srcOffset, byteCount); |
| this.position += byteCount; |
| return this; |
| } |
| |
| @Override |
| public ByteBuffer put(int index, byte b) { |
| wrapped.position(this.position); |
| wrapped.put(index, b); |
| return this; |
| } |
| |
| @Override |
| public ByteBuffer putChar(char value) { |
| wrapped.position(this.position); |
| wrapped.putChar(value); |
| this.position += SizeOf.CHAR; |
| return this; |
| } |
| |
| @Override |
| public ByteBuffer putChar(int index, char value) { |
| wrapped.position(this.position); |
| wrapped.putChar(index, value); |
| return this; |
| } |
| |
| @Override |
| public ByteBuffer putDouble(double value) { |
| wrapped.position(this.position); |
| wrapped.putDouble(value); |
| this.position += SizeOf.DOUBLE; |
| return this; |
| } |
| |
| @Override |
| public ByteBuffer putDouble(int index, double value) { |
| wrapped.position(this.position); |
| wrapped.putDouble(index, value); |
| return this; |
| } |
| |
| @Override |
| public ByteBuffer putFloat(float value) { |
| wrapped.position(this.position); |
| wrapped.putFloat(value); |
| this.position += SizeOf.FLOAT; |
| return this; |
| } |
| |
| @Override |
| public ByteBuffer putFloat(int index, float value) { |
| wrapped.position(this.position); |
| wrapped.putFloat(index, value); |
| return this; |
| } |
| |
| @Override |
| public ByteBuffer putInt(int index, int value) { |
| wrapped.position(this.position); |
| wrapped.putInt(index, value); |
| return this; |
| } |
| |
| @Override |
| public ByteBuffer putInt(int value) { |
| wrapped.position(this.position); |
| wrapped.putInt(value); |
| this.position += SizeOf.INT; |
| return this; |
| } |
| |
| @Override |
| public ByteBuffer putLong(int index, long value) { |
| wrapped.position(this.position); |
| wrapped.putLong(index, value); |
| return this; |
| } |
| |
| @Override |
| public ByteBuffer putLong(long value) { |
| wrapped.position(this.position); |
| wrapped.putLong(value); |
| this.position += SizeOf.LONG; |
| return this; |
| } |
| |
| @Override |
| public ByteBuffer putShort(int index, short value) { |
| wrapped.position(this.position); |
| wrapped.putShort(index, value); |
| return this; |
| } |
| |
| @Override |
| public ByteBuffer putShort(short value) { |
| wrapped.position(this.position); |
| wrapped.putShort(value); |
| this.position += SizeOf.SHORT; |
| return this; |
| } |
| |
| @Override |
| public ByteBuffer slice() { |
| wrapped.position(this.position); |
| MappedByteBufferAdapter result = new MappedByteBufferAdapter(wrapped.slice()); |
| wrapped.clear(); |
| return result; |
| } |
| |
| @Override byte[] protectedArray() { |
| return wrapped.protectedArray(); |
| } |
| |
| @Override int protectedArrayOffset() { |
| return wrapped.protectedArrayOffset(); |
| } |
| |
| @Override boolean protectedHasArray() { |
| return wrapped.protectedHasArray(); |
| } |
| |
| public final void free() { |
| wrapped.free(); |
| } |
| } |