From 999e02d316512ada90a038853f1c4ef219b67943 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Tue, 4 Nov 2014 14:02:19 +0300 Subject: [PATCH] Refactor FloatBuffer --- .../teavm/classlib/java/nio/TByteBuffer.java | 2 + .../classlib/java/nio/TByteBufferImpl.java | 9 ++ .../teavm/classlib/java/nio/TFloatBuffer.java | 72 ++++++++----- .../classlib/java/nio/TFloatBufferImpl.java | 44 ++++---- .../java/nio/TFloatBufferOverArray.java | 77 +++++++++++++ .../java/nio/TFloatBufferOverByteBuffer.java | 101 ++++++++++++++++++ .../java/nio/ByteBufferWrapperTest.java | 27 ++++- 7 files changed, 281 insertions(+), 51 deletions(-) create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TFloatBufferOverArray.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TFloatBufferOverByteBuffer.java 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 d78b98e8e..0a040d7cb 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 @@ -206,4 +206,6 @@ public abstract class TByteBuffer extends TBuffer implements TComparable */ public abstract class TFloatBuffer extends TBuffer implements Comparable { - int start; - float[] array; - - TFloatBuffer(int start, int capacity, float[] array, int position, int limit) { + TFloatBuffer(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 TFloatBuffer 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 TFloatBuffer extends TBuffer implements Comparable */ -class TFloatBufferImpl extends TFloatBuffer { - private boolean readOnly; - - public TFloatBufferImpl(int capacity) { - this(0, capacity, new float[capacity], 0, capacity, false); - } - - public TFloatBufferImpl(int start, int capacity, float[] array, int position, int limit, boolean readOnly) { - super(start, capacity, array, position, limit); - this.readOnly = readOnly; +abstract class TFloatBufferImpl extends TFloatBuffer { + public TFloatBufferImpl(int capacity, int position, int limit) { + super(capacity, position, limit); } @Override public TFloatBuffer slice() { - return new TFloatBufferImpl(position, limit - position, array, 0, limit - position, readOnly); + return duplicate(position, limit - position, 0, limit - position, isReadOnly()); } @Override public TFloatBuffer duplicate() { - return new TFloatBufferImpl(start, capacity, array, position, limit, readOnly); + return duplicate(0, capacity, position, limit, isReadOnly()); } @Override public TFloatBuffer asReadOnlyBuffer() { - return new TFloatBufferImpl(start, capacity, array, position, limit, true); + return duplicate(0, capacity, position, limit, true); } + abstract TFloatBuffer duplicate(int start, int capacity, int position, int limit, boolean readOnly); + @Override public float get() { if (position >= limit) { throw new TBufferUnderflowException(); } - return array[start + position++]; + return getElement(position++); } @Override public TFloatBuffer put(float 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 TFloatBufferImpl extends TFloatBuffer { 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 TFloatBuffer put(int index, float 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 TFloatBuffer 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 TFloatBufferImpl extends TFloatBuffer { @Override public boolean isReadOnly() { - return readOnly; + return readOnly(); } + + abstract boolean readOnly(); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TFloatBufferOverArray.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TFloatBufferOverArray.java new file mode 100644 index 000000000..dc4e79bab --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TFloatBufferOverArray.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 TFloatBufferOverArray extends TFloatBufferImpl { + boolean readOnly; + int start; + float[] array; + + public TFloatBufferOverArray(int capacity) { + this(0, capacity, new float[capacity], 0, capacity, false); + } + + public TFloatBufferOverArray(int start, int capacity, float[] array, int position, int limit, boolean readOnly) { + super(capacity, position, limit); + this.start = start; + this.readOnly = readOnly; + this.array = array; + } + + @Override + TFloatBuffer duplicate(int start, int capacity, int position, int limit, boolean readOnly) { + return new TFloatBufferOverArray(this.start + start, capacity, array, position, limit, readOnly); + } + + @Override + float getElement(int index) { + return array[index + start]; + } + + @Override + void putElement(int index, float value) { + array[index + start] = value; + } + + @Override + boolean isArrayPresent() { + return true; + } + + @Override + float[] 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/TFloatBufferOverByteBuffer.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TFloatBufferOverByteBuffer.java new file mode 100644 index 000000000..18ce83ef9 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TFloatBufferOverByteBuffer.java @@ -0,0 +1,101 @@ +/* + * 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 TFloatBufferOverByteBuffer extends TFloatBufferImpl { + private TByteBufferImpl byteByffer; + TByteOrder byteOrder = TByteOrder.BIG_ENDIAN; + boolean readOnly; + private int start; + + public TFloatBufferOverByteBuffer(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 + TFloatBuffer duplicate(int start, int capacity, int position, int limit, boolean readOnly) { + TFloatBufferOverByteBuffer result = new TFloatBufferOverByteBuffer(this.start + start * 2, capacity, + byteByffer, position, limit, readOnly); + result.byteOrder = byteOrder; + return result; + } + + @Override + float 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 Float.intBitsToFloat(value); + } + + @Override + void putElement(int index, float f) { + int value = Float.floatToIntBits(f); + 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 + float[] 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 index ec0eca497..cd5cc7a93 100644 --- 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 @@ -16,7 +16,7 @@ package org.teavm.classlib.java.nio; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.junit.Assert.*; import java.nio.*; import org.junit.Test; @@ -103,6 +103,31 @@ public class ByteBufferWrapperTest { assertThat(buffer.get(7), is((byte)0x32)); } + @Test + public void wrapsIntoFloatBuffer() { + 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)0x40); + buffer.put(1, (byte)0x49); + buffer.put(2, (byte)0x0F); + buffer.put(3, (byte)0xD0); + + FloatBuffer wrapper = buffer.asFloatBuffer(); + assertThat(wrapper.capacity(), is(15)); + assertThat(wrapper.position(), is(0)); + assertThat(wrapper.limit(), is(15)); + assertEquals(3.14159, wrapper.get(0), 0.00001); + + wrapper.put(0, 2.71828F); + assertThat(buffer.get(0), is((byte)0x40)); + assertThat(buffer.get(1), is((byte)0x2D)); + assertThat(buffer.get(2), is((byte)0xF8)); + assertThat(buffer.get(3) & 0xF0, is(0x40)); + } + @Test public void shortEndiannesWorks() { byte[] array = new byte[100];