diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TByteBuffer.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TByteBuffer.java index 7bef817d6..cce9d702f 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TByteBuffer.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TByteBuffer.java @@ -200,4 +200,8 @@ public abstract class TByteBuffer extends TBuffer implements TComparable */ public abstract class TIntBuffer extends TBuffer implements Comparable { - int start; - int[] array; - - TIntBuffer(int start, int capacity, int[] array, int position, int limit) { + TIntBuffer(int capacity, int position, int limit) { super(capacity); - this.start = start; - this.array = array; this.position = position; this.limit = limit; } @@ -35,11 +30,11 @@ public abstract class TIntBuffer extends TBuffer implements Comparable= dst.length) { throw new IndexOutOfBoundsException("Offset " + offset + " is outside of range [0;" + dst.length + ")"); @@ -74,9 +73,9 @@ public abstract class TIntBuffer extends TBuffer implements Comparable */ -class TIntBufferImpl extends TIntBuffer { - private boolean readOnly; - - public TIntBufferImpl(int capacity) { - this(0, capacity, new int[capacity], 0, capacity, false); - } - - public TIntBufferImpl(int start, int capacity, int[] array, int position, int limit, boolean readOnly) { - super(start, capacity, array, position, limit); - this.readOnly = readOnly; +abstract class TIntBufferImpl extends TIntBuffer { + public TIntBufferImpl(int capacity, int position, int limit) { + super(capacity, position, limit); } @Override public TIntBuffer slice() { - return new TIntBufferImpl(position, limit - position, array, 0, limit - position, readOnly); + return duplicate(position, limit - position, 0, limit - position, isReadOnly()); } @Override public TIntBuffer duplicate() { - return new TIntBufferImpl(start, capacity, array, position, limit, readOnly); + return duplicate(0, capacity, position, limit, isReadOnly()); } @Override public TIntBuffer asReadOnlyBuffer() { - return new TIntBufferImpl(start, capacity, array, position, limit, true); + return duplicate(0, capacity, position, limit, true); } + abstract TIntBuffer duplicate(int start, int capacity, int position, int limit, boolean readOnly); + @Override public int get() { if (position >= limit) { throw new TBufferUnderflowException(); } - return array[start + position++]; + return getElement(position++); } @Override public TIntBuffer put(int b) { - if (readOnly) { + if (isReadOnly()) { throw new TReadOnlyBufferException(); } if (position >= limit) { throw new TBufferOverflowException(); } - array[start + position++] = b; + putElement(position++, b); return this; } @@ -71,32 +66,31 @@ class TIntBufferImpl extends TIntBuffer { if (index < 0 || index >= limit) { throw new IndexOutOfBoundsException("Index " + index + " is outside of range [0;" + limit + ")"); } - return array[start + index]; + return getElement(index); } @Override public TIntBuffer put(int index, int b) { - if (readOnly) { + if (isReadOnly()) { throw new TReadOnlyBufferException(); } if (index < 0 || index >= limit) { throw new IndexOutOfBoundsException("Index " + index + " is outside of range [0;" + limit + ")"); } - array[start + index] = b; + putElement(index, b); return this; } @Override public TIntBuffer compact() { - if (readOnly) { + if (isReadOnly()) { throw new TReadOnlyBufferException(); } if (position > 0) { int sz = remaining(); - int dst = start; - int src = start + position; + int src = position; for (int i = 0; i < sz; ++i) { - array[dst++] = array[src++]; + putElement(i, getElement(src++)); } position = sz; } @@ -112,6 +106,8 @@ class TIntBufferImpl extends TIntBuffer { @Override public boolean isReadOnly() { - return readOnly; + return readOnly(); } + + abstract boolean readOnly(); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TIntBufferOverArray.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TIntBufferOverArray.java new file mode 100644 index 000000000..b839ec3c5 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TIntBufferOverArray.java @@ -0,0 +1,77 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed 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 org.teavm.classlib.java.nio; + +/** + * + * @author Alexey Andreev + */ +class TIntBufferOverArray extends TIntBufferImpl { + boolean readOnly; + int start; + int[] array; + + public TIntBufferOverArray(int capacity) { + this(0, capacity, new int[capacity], 0, capacity, false); + } + + public TIntBufferOverArray(int start, int capacity, int[] array, int position, int limit, boolean readOnly) { + super(capacity, position, limit); + this.start = start; + this.readOnly = readOnly; + this.array = array; + } + + @Override + TIntBuffer duplicate(int start, int capacity, int position, int limit, boolean readOnly) { + return new TIntBufferOverArray(this.start + start, capacity, array, position, limit, readOnly); + } + + @Override + int getElement(int index) { + return array[index + start]; + } + + @Override + void putElement(int index, int value) { + array[index + start] = value; + } + + @Override + boolean isArrayPresent() { + return true; + } + + @Override + int[] getArray() { + return array; + } + + @Override + int getArrayOffset() { + return start; + } + + @Override + boolean readOnly() { + return readOnly; + } + + @Override + public TByteOrder order() { + return TByteOrder.BIG_ENDIAN; + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TIntBufferOverByteBuffer.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TIntBufferOverByteBuffer.java new file mode 100644 index 000000000..1c8f82835 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TIntBufferOverByteBuffer.java @@ -0,0 +1,100 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed 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 org.teavm.classlib.java.nio; + +/** + * + * @author Alexey Andreev + */ +public class TIntBufferOverByteBuffer extends TIntBufferImpl { + private TByteBufferImpl byteByffer; + TByteOrder byteOrder = TByteOrder.BIG_ENDIAN; + boolean readOnly; + private int start; + + public TIntBufferOverByteBuffer(int start, int capacity, TByteBufferImpl byteBuffer, int position, int limit, + boolean readOnly) { + super(capacity, position, limit); + this.start = start; + this.byteByffer = byteBuffer; + this.readOnly = readOnly; + } + + @Override + TIntBuffer duplicate(int start, int capacity, int position, int limit, boolean readOnly) { + TIntBufferOverByteBuffer result = new TIntBufferOverByteBuffer(this.start + start * 2, capacity, + byteByffer, position, limit, readOnly); + result.byteOrder = byteOrder; + return result; + } + + @Override + int getElement(int index) { + int value; + if (byteOrder == TByteOrder.BIG_ENDIAN) { + value = (byteByffer.array[start + index * 4] << 24) | + (byteByffer.array[start + index * 4 + 1] << 16) | + (byteByffer.array[start + index * 4 + 2] << 8) | + (byteByffer.array[start + index * 4 + 3]); + } else { + value = (byteByffer.array[start + index * 4]) | + (byteByffer.array[start + index * 4 + 1] << 8) | + (byteByffer.array[start + index * 4 + 2] << 16) | + (byteByffer.array[start + index * 4 + 3] << 24); + } + return value; + } + + @Override + void putElement(int index, int value) { + if (byteOrder == TByteOrder.BIG_ENDIAN) { + byteByffer.array[start + index * 4] = (byte)(value >> 24); + byteByffer.array[start + index * 4 + 1] = (byte)(value >> 16); + byteByffer.array[start + index * 4 + 2] = (byte)(value >> 8); + byteByffer.array[start + index * 4 + 3] = (byte)value; + } else { + byteByffer.array[start + index * 4] = (byte)value; + byteByffer.array[start + index * 4 + 1] = (byte)(value >> 8); + byteByffer.array[start + index * 4 + 2] = (byte)(value >> 16); + byteByffer.array[start + index * 4 + 3] = (byte)(value >> 24); + } + } + + @Override + boolean isArrayPresent() { + return false; + } + + @Override + int[] getArray() { + throw new UnsupportedOperationException(); + } + + @Override + int getArrayOffset() { + throw new UnsupportedOperationException(); + } + + @Override + boolean readOnly() { + return readOnly; + } + + @Override + public TByteOrder order() { + return byteOrder; + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TShortBuffer.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TShortBuffer.java index 5a1940713..de5c4224d 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TShortBuffer.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TShortBuffer.java @@ -20,13 +20,8 @@ package org.teavm.classlib.java.nio; * @author Alexey Andreev */ public abstract class TShortBuffer extends TBuffer implements Comparable { - int start; - short[] array; - - TShortBuffer(int start, int capacity, short[] array, int position, int limit) { + TShortBuffer(int capacity, int position, int limit) { super(capacity); - this.start = start; - this.array = array; this.position = position; this.limit = limit; } @@ -35,11 +30,11 @@ public abstract class TShortBuffer extends TBuffer implements Comparable= dst.length) { throw new IndexOutOfBoundsException("Offset " + offset + " is outside of range [0;" + dst.length + ")"); @@ -74,9 +73,9 @@ public abstract class TShortBuffer extends TBuffer implements Comparable */ -class TShortBufferImpl extends TShortBuffer { - private boolean readOnly; - - public TShortBufferImpl(int capacity) { - this(0, capacity, new short[capacity], 0, capacity, false); - } - - public TShortBufferImpl(int start, int capacity, short[] array, int position, int limit, boolean readOnly) { - super(start, capacity, array, position, limit); - this.readOnly = readOnly; +abstract class TShortBufferImpl extends TShortBuffer { + public TShortBufferImpl(int capacity, int position, int limit) { + super(capacity, position, limit); } @Override public TShortBuffer slice() { - return new TShortBufferImpl(position, limit - position, array, 0, limit - position, readOnly); + return duplicate(position, limit - position, 0, limit - position, isReadOnly()); } @Override public TShortBuffer duplicate() { - return new TShortBufferImpl(start, capacity, array, position, limit, readOnly); + return duplicate(0, capacity, position, limit, isReadOnly()); } @Override public TShortBuffer asReadOnlyBuffer() { - return new TShortBufferImpl(start, capacity, array, position, limit, true); + return duplicate(0, capacity, position, limit, true); } + abstract TShortBuffer duplicate(int start, int capacity, int position, int limit, boolean readOnly); + @Override public short get() { if (position >= limit) { throw new TBufferUnderflowException(); } - return array[start + position++]; + return getElement(position++); } @Override public TShortBuffer put(short b) { - if (readOnly) { + if (isReadOnly()) { throw new TReadOnlyBufferException(); } if (position >= limit) { throw new TBufferOverflowException(); } - array[start + position++] = b; + putElement(position++, b); return this; } @@ -71,32 +66,31 @@ class TShortBufferImpl extends TShortBuffer { if (index < 0 || index >= limit) { throw new IndexOutOfBoundsException("Index " + index + " is outside of range [0;" + limit + ")"); } - return array[start + index]; + return getElement(index); } @Override public TShortBuffer put(int index, short b) { - if (readOnly) { + if (isReadOnly()) { throw new TReadOnlyBufferException(); } if (index < 0 || index >= limit) { throw new IndexOutOfBoundsException("Index " + index + " is outside of range [0;" + limit + ")"); } - array[start + index] = b; + putElement(index, b); return this; } @Override public TShortBuffer compact() { - if (readOnly) { + if (isReadOnly()) { throw new TReadOnlyBufferException(); } if (position > 0) { int sz = remaining(); - int dst = start; - int src = start + position; + int src = position; for (int i = 0; i < sz; ++i) { - array[dst++] = array[src++]; + putElement(i, getElement(src++)); } position = sz; } @@ -112,6 +106,8 @@ class TShortBufferImpl extends TShortBuffer { @Override public boolean isReadOnly() { - return readOnly; + return readOnly(); } + + abstract boolean readOnly(); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TShortBufferOverArray.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TShortBufferOverArray.java new file mode 100644 index 000000000..f166f1baf --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TShortBufferOverArray.java @@ -0,0 +1,77 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed 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 org.teavm.classlib.java.nio; + +/** + * + * @author Alexey Andreev + */ +class TShortBufferOverArray extends TShortBufferImpl { + boolean readOnly; + int start; + short[] array; + + public TShortBufferOverArray(int capacity) { + this(0, capacity, new short[capacity], 0, capacity, false); + } + + public TShortBufferOverArray(int start, int capacity, short[] array, int position, int limit, boolean readOnly) { + super(capacity, position, limit); + this.start = start; + this.readOnly = readOnly; + this.array = array; + } + + @Override + TShortBuffer duplicate(int start, int capacity, int position, int limit, boolean readOnly) { + return new TShortBufferOverArray(this.start + start, capacity, array, position, limit, readOnly); + } + + @Override + short getElement(int index) { + return array[index + start]; + } + + @Override + void putElement(int index, short value) { + array[index + start] = value; + } + + @Override + boolean isArrayPresent() { + return true; + } + + @Override + short[] getArray() { + return array; + } + + @Override + int getArrayOffset() { + return start; + } + + @Override + boolean readOnly() { + return readOnly; + } + + @Override + public TByteOrder order() { + return TByteOrder.BIG_ENDIAN; + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TShortBufferOverByteBuffer.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TShortBufferOverByteBuffer.java new file mode 100644 index 000000000..f5c1e3020 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TShortBufferOverByteBuffer.java @@ -0,0 +1,90 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed 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 org.teavm.classlib.java.nio; + +/** + * + * @author Alexey Andreev + */ +class TShortBufferOverByteBuffer extends TShortBufferImpl { + private TByteBufferImpl byteByffer; + TByteOrder byteOrder = TByteOrder.BIG_ENDIAN; + boolean readOnly; + private int start; + + public TShortBufferOverByteBuffer(int start, int capacity, TByteBufferImpl byteBuffer, int position, int limit, + boolean readOnly) { + super(capacity, position, limit); + this.start = start; + this.byteByffer = byteBuffer; + this.readOnly = readOnly; + } + + @Override + TShortBuffer duplicate(int start, int capacity, int position, int limit, boolean readOnly) { + TShortBufferOverByteBuffer result = new TShortBufferOverByteBuffer(this.start + start * 2, capacity, + byteByffer, position, limit, readOnly); + result.byteOrder = byteOrder; + return result; + } + + @Override + short getElement(int index) { + int value; + if (byteOrder == TByteOrder.BIG_ENDIAN) { + value = (byteByffer.array[start + index * 2] << 8) | (byteByffer.array[start + index * 2 + 1]); + } else { + value = (byteByffer.array[start + index * 2 + 1] << 8) | (byteByffer.array[start + index * 2]); + } + return (short)value; + } + + @Override + void putElement(int index, short value) { + if (byteOrder == TByteOrder.BIG_ENDIAN) { + byteByffer.array[start + index * 2] = (byte)(value >> 8); + byteByffer.array[start + index * 2 + 1] = (byte)value; + } else { + byteByffer.array[start + index * 2] = (byte)value; + byteByffer.array[start + index * 2 + 1] = (byte)(value >> 8); + } + } + + @Override + boolean isArrayPresent() { + return false; + } + + @Override + short[] getArray() { + throw new UnsupportedOperationException(); + } + + @Override + int getArrayOffset() { + throw new UnsupportedOperationException(); + } + + @Override + boolean readOnly() { + return readOnly; + } + + @Override + public TByteOrder order() { + return byteOrder; + } +} diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/nio/ByteBufferWrapperTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/nio/ByteBufferWrapperTest.java new file mode 100644 index 000000000..bf74d4d67 --- /dev/null +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/nio/ByteBufferWrapperTest.java @@ -0,0 +1,93 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed 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 org.teavm.classlib.java.nio; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; +import org.junit.Test; + +/** + * + * @author Alexey Andreev + */ +public class ByteBufferWrapperTest { + @Test + public void wrapsIntoShortBuffer() { + byte[] array = new byte[100]; + ByteBuffer buffer = ByteBuffer.wrap(array); + buffer.limit(80); + buffer.get(new byte[10]); + buffer = buffer.slice(); + buffer.put(0, (byte)0x23); + buffer.put(1, (byte)0x24); + ShortBuffer wrapper = buffer.asShortBuffer(); + assertThat(wrapper.capacity(), is(35)); + assertThat(wrapper.position(), is(0)); + assertThat(wrapper.limit(), is(35)); + assertThat(wrapper.get(0), is((short)0x2324)); + } + + @Test + public void wrapsIntoIntBuffer() { + byte[] array = new byte[100]; + ByteBuffer buffer = ByteBuffer.wrap(array); + buffer.limit(70); + buffer.get(new byte[10]); + buffer = buffer.slice(); + buffer.put(0, (byte)0x23); + buffer.put(1, (byte)0x24); + buffer.put(2, (byte)0x25); + IntBuffer wrapper = buffer.asIntBuffer(); + assertThat(wrapper.capacity(), is(15)); + assertThat(wrapper.position(), is(0)); + assertThat(wrapper.limit(), is(15)); + assertThat(wrapper.get(0), is(0x23242500)); + } + + @Test + public void endiannesWorks() { + byte[] array = new byte[100]; + ByteBuffer buffer = ByteBuffer.wrap(array); + buffer.order(ByteOrder.LITTLE_ENDIAN); + buffer.put(0, (byte)0x23); + buffer.put(1, (byte)0x24); + ShortBuffer wrapper = buffer.asShortBuffer(); + assertThat(wrapper.get(0), is((short)0x2423)); + } + + @Test + public void changesInWrapperSeenInBuffer() { + byte[] array = new byte[100]; + ByteBuffer buffer = ByteBuffer.wrap(array); + ShortBuffer wrapper = buffer.asShortBuffer(); + wrapper.put(0, (short)0x2324); + assertThat(buffer.get(0), is((byte)0x23)); + assertThat(buffer.get(1), is((byte)0x24)); + } + + @Test + public void changesInBufferSeenInWrapper() { + byte[] array = new byte[100]; + ByteBuffer buffer = ByteBuffer.wrap(array); + ShortBuffer wrapper = buffer.asShortBuffer(); + buffer.put(1, (byte)0x24); + assertThat(wrapper.get(0), is((short)0x0024)); + } +}