Add CharBuffer

This commit is contained in:
konsoletyper 2014-10-25 15:07:45 +04:00
parent f9cbcf4b80
commit 4629ff5450
5 changed files with 847 additions and 1 deletions

View File

@ -0,0 +1,27 @@
/*
* 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.lang;
import org.teavm.classlib.java.io.TIOException;
import org.teavm.classlib.java.nio.TCharBuffer;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public interface TReadable {
int read(TCharBuffer cb) throws TIOException;
}

View File

@ -0,0 +1,282 @@
/*
* 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 org.teavm.classlib.java.io.TIOException;
import org.teavm.classlib.java.lang.TReadable;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public abstract class TCharBuffer extends TBuffer implements Comparable<TCharBuffer>, Appendable,
CharSequence, TReadable {
int start;
char[] array;
TCharBuffer(int start, int capacity, char[] array, int position, int limit) {
super(capacity);
this.start = start;
this.array = array;
this.position = position;
this.limit = limit;
}
public static TCharBuffer allocate(int capacity) {
if (capacity < 0) {
throw new IllegalArgumentException("Capacity is negative: " + capacity);
}
return new TCharBufferImpl(capacity);
}
public static TCharBuffer wrap(char[] array, int offset, int length) {
return new TCharBufferImpl(0, array.length, array, offset, offset + length, false);
}
public static TCharBuffer wrap(char[] array) {
return wrap(array, 0, array.length);
}
@Override
public int read(TCharBuffer target) throws TIOException {
if (target == null) {
throw new NullPointerException("Target is null");
}
if (target.isReadOnly()) {
throw new TReadOnlyBufferException();
}
if (!hasRemaining()) {
return -1;
}
int sz = Math.min(remaining(), target.remaining());
target.put(array, start + position, sz);
return sz;
}
public static TCharBuffer wrap(CharSequence csq, int start, int end) {
return wrap(csq.toString().toCharArray(), start, end - start);
}
public static TCharBuffer wrap(CharSequence csq) {
return wrap(csq.toString().toCharArray());
}
public abstract TCharBuffer slice();
public abstract TCharBuffer duplicate();
public abstract TCharBuffer asReadOnlyBuffer();
public abstract char get();
public abstract TCharBuffer put(char c);
public abstract char get(int index);
public abstract TCharBuffer put(int index, char c);
public TCharBuffer get(char[] dst, int offset, int length) {
if (offset < 0 || offset >= dst.length) {
throw new IndexOutOfBoundsException("Offset " + offset + " is outside of range [0;" + dst.length + ")");
}
if (offset + length > dst.length) {
throw new IndexOutOfBoundsException("The last char in dst " + (offset + length) + " is outside " +
"of array of size " + dst.length);
}
if (remaining() < length) {
throw new TBufferUnderflowException();
}
if (length < 0) {
throw new IndexOutOfBoundsException("Length " + length + " must be non-negative");
}
int pos = position + start;
for (int i = 0; i < length; ++i) {
dst[offset++] = array[pos++];
}
position += length;
return this;
}
public TCharBuffer get(char[] dst) {
return get(dst, 0, dst.length);
}
public TCharBuffer put(TCharBuffer src) {
return put(src.array, src.start + src.position, src.remaining());
}
public TCharBuffer put(char[] src, int offset, int length) {
if (isReadOnly()) {
throw new TReadOnlyBufferException();
}
if (remaining() < length) {
throw new TBufferOverflowException();
}
if (offset < 0 || offset >= src.length) {
throw new IndexOutOfBoundsException("Offset " + offset + " is outside of range [0;" + src.length + ")");
}
if (offset + length > src.length) {
throw new IndexOutOfBoundsException("The last char in src " + (offset + length) + " is outside " +
"of array of size " + src.length);
}
if (length < 0) {
throw new IndexOutOfBoundsException("Length " + length + " must be non-negative");
}
int pos = position + start;
for (int i = 0; i < length; ++i) {
array[pos++] = src[offset++];
}
position += length;
return this;
}
public final TCharBuffer put(char[] src) {
return put(src, 0, src.length);
}
public TCharBuffer put(String src, int start, int end) {
if (isReadOnly()) {
throw new TReadOnlyBufferException();
}
int sz = end - start;
if (remaining() < sz) {
throw new TBufferOverflowException();
}
if (start < 0 || start >= src.length()) {
throw new IndexOutOfBoundsException("Start " + start + " is outside of range [0;" + src.length() + ")");
}
if (end > src.length()) {
throw new IndexOutOfBoundsException("The last char in src " + end + " is outside " +
"of string of size " + src.length());
}
if (start > end) {
throw new IndexOutOfBoundsException("Start " + start + " must be before end " + end);
}
int pos = position + this.start;
while (start < end) {
array[pos++] = src.charAt(start++);
}
position += sz;
return this;
}
public final TCharBuffer put(String src) {
return put(src, 0, src.length());
}
@Override
public final boolean hasArray() {
return true;
}
@Override
public final char[] array() {
return array;
}
@Override
public final int arrayOffset() {
return start;
}
public abstract TCharBuffer compact();
@Override
public abstract boolean isDirect();
@Override
public int hashCode() {
int hashCode = 0;
int pos = position + start;
for (int i = position; i < limit; ++i) {
hashCode = 31 * hashCode + array[pos++];
}
return hashCode;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof TCharBuffer)) {
return false;
}
TCharBuffer other = (TCharBuffer)obj;
int sz = remaining();
if (sz != other.remaining()) {
return false;
}
int a = position + start;
int b = other.position + other.start;
for (int i = 0; i < sz; ++i) {
if (array[a++] != other.array[b++]) {
return false;
}
}
return true;
}
@Override
public int compareTo(TCharBuffer other) {
if (this == other) {
return 0;
}
int sz = Math.min(remaining(), other.remaining());
int a = position + start;
int b = other.position + other.start;
for (int i = 0; i < sz; ++i) {
int r = Character.compare(array[a++], other.array[b++]);
if (r != 0) {
return r;
}
}
return Integer.compare(remaining(), other.remaining());
}
@Override
public String toString() {
return new String(array, start + position, limit - position);
}
@Override
public final int length() {
return remaining();
}
@Override
public final char charAt(int index) {
return get(index);
}
@Override
public abstract TCharBuffer subSequence(int start, int end);
@Override
public TCharBuffer append(CharSequence csq) {
return put(csq.toString());
}
@Override
public TCharBuffer append(CharSequence csq, int start, int end) {
return put(csq.subSequence(start, end).toString());
}
@Override
public TCharBuffer append(char c) {
return put(c);
}
}

View File

@ -0,0 +1,123 @@
/*
* 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 <konsoletyper@gmail.com>
*/
class TCharBufferImpl extends TCharBuffer {
private boolean readOnly;
public TCharBufferImpl(int capacity) {
this(0, capacity, new char[capacity], 0, capacity, false);
}
public TCharBufferImpl(int start, int capacity, char[] array, int position, int limit,
boolean readOnly) {
super(start, capacity, array, position, limit);
this.readOnly = readOnly;
}
@Override
public TCharBuffer slice() {
return new TCharBufferImpl(position, limit - position, array, 0, limit - position, readOnly);
}
@Override
public TCharBuffer duplicate() {
return new TCharBufferImpl(start, capacity, array, position, limit, readOnly);
}
@Override
public TCharBuffer asReadOnlyBuffer() {
return new TCharBufferImpl(start, capacity, array, position, limit, true);
}
@Override
public char get() {
if (position >= limit) {
throw new TBufferUnderflowException();
}
return array[start + position++];
}
@Override
public TCharBuffer put(char c) {
if (readOnly) {
throw new TReadOnlyBufferException();
}
if (position >= limit) {
throw new TBufferOverflowException();
}
array[start + position++] = c;
return this;
}
@Override
public char get(int index) {
if (index < 0 || index >= limit) {
throw new IndexOutOfBoundsException("Index " + index + " is outside of range [0;" + limit + ")");
}
return array[start + index];
}
@Override
public TCharBuffer put(int index, char b) {
if (readOnly) {
throw new TReadOnlyBufferException();
}
if (index < 0 || index >= limit) {
throw new IndexOutOfBoundsException("Index " + index + " is outside of range [0;" + limit + ")");
}
array[start + index] = b;
return this;
}
@Override
public TCharBuffer compact() {
if (readOnly) {
throw new TReadOnlyBufferException();
}
if (position > 0) {
int sz = remaining();
int dst = start;
int src = start + position;
for (int i = 0; i < sz; ++i) {
array[dst++] = array[src++];
}
position = sz;
}
limit = capacity;
mark = -1;
return this;
}
@Override
public boolean isDirect() {
return false;
}
@Override
public boolean isReadOnly() {
return readOnly;
}
@Override
public TCharBuffer subSequence(int start, int end) {
return wrap(array, arrayOffset() + start, end - start);
}
}

View File

@ -206,7 +206,6 @@ public class ByteBufferTest {
buffer.put((byte)5);
fail("Should have thrown error");
} catch (BufferOverflowException e) {
System.out.println(e);
assertThat(array[2], is((byte)0));
}
}

View File

@ -0,0 +1,415 @@
package org.teavm.classlib.java.nio;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.sameInstance;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.nio.*;
import org.junit.Test;
/**
*
* @author Alexey Andreev
*/
public class CharBufferTest {
@Test
public void allocates() {
CharBuffer buffer = CharBuffer.allocate(100);
assertThat(buffer.isDirect(), is(false));
assertThat(buffer.isReadOnly(), is(false));
assertThat(buffer.hasArray(), is(true));
assertThat(buffer.capacity(), is(100));
assertThat(buffer.position(), is(0));
assertThat(buffer.limit(), is(100));
try {
buffer.reset();
fail("Mark is expected to be undefined");
} catch (InvalidMarkException e) {
// ok
}
}
@Test(expected = IllegalArgumentException.class)
public void errorIfAllocatingBufferOfNegativeSize() {
CharBuffer.allocate(-1);
}
@Test
public void wrapsArray() {
char[] array = new char[100];
CharBuffer buffer = CharBuffer.wrap(array, 10, 70);
assertThat(buffer.isDirect(), is(false));
assertThat(buffer.isReadOnly(), is(false));
assertThat(buffer.hasArray(), is(true));
assertThat(buffer.array(), is(array));
assertThat(buffer.arrayOffset(), is(0));
assertThat(buffer.capacity(), is(100));
assertThat(buffer.position(), is(10));
assertThat(buffer.limit(), is(80));
try {
buffer.reset();
fail("Mark is expected to be undefined");
} catch (InvalidMarkException e) {
// ok
}
array[0] = 'A';
assertThat(buffer.get(0), is('A'));
buffer.put(1, 'B');
assertThat(array[1], is('B'));
}
@Test
public void errorWhenWrappingWithWrongParameters() {
char[] array = new char[100];
try {
CharBuffer.wrap(array, -1, 10);
} catch (IndexOutOfBoundsException e) {
// ok
}
try {
CharBuffer.wrap(array, 101, 10);
} catch (IndexOutOfBoundsException e) {
// ok
}
try {
CharBuffer.wrap(array, 98, 3);
} catch (IndexOutOfBoundsException e) {
// ok
}
try {
CharBuffer.wrap(array, 98, -1);
} catch (IndexOutOfBoundsException e) {
// ok
}
}
@Test
public void wrapsArrayWithoutOffset() {
char[] array = new char[100];
CharBuffer buffer = CharBuffer.wrap(array);
assertThat(buffer.position(), is(0));
assertThat(buffer.limit(), is(100));
}
@Test
public void createsSlice() {
CharBuffer buffer = CharBuffer.allocate(100);
buffer.put(new char[60]);
buffer.flip();
buffer.put(new char[15]);
CharBuffer slice = buffer.slice();
assertThat(slice.array(), is(buffer.array()));
assertThat(slice.position(), is(0));
assertThat(slice.capacity(), is(45));
assertThat(slice.limit(), is(45));
assertThat(slice.isDirect(), is(false));
assertThat(slice.isReadOnly(), is(false));
slice.put(3, 'A');
assertThat(buffer.get(18), is('A'));
slice.put('B');
assertThat(buffer.get(15), is('B'));
buffer.put(16, 'C');
assertThat(slice.get(1), is('C'));
}
@Test
public void slicePropertiesSameWithOriginal() {
CharBuffer buffer = CharBuffer.allocate(100).asReadOnlyBuffer().slice();
assertThat(buffer.isReadOnly(), is(true));
}
@Test
public void createsDuplicate() {
CharBuffer buffer = CharBuffer.allocate(100);
buffer.put(new char[60]);
buffer.flip();
buffer.put(new char[15]);
CharBuffer duplicate = buffer.duplicate();
assertThat(duplicate.array(), is(buffer.array()));
assertThat(duplicate.position(), is(15));
assertThat(duplicate.capacity(), is(100));
assertThat(duplicate.limit(), is(60));
assertThat(duplicate.isDirect(), is(false));
assertThat(duplicate.isReadOnly(), is(false));
duplicate.put(3, 'A');
assertThat(buffer.get(3), is('A'));
duplicate.put('B');
assertThat(buffer.get(15), is('B'));
buffer.put(1, 'C');
assertThat(duplicate.get(1), is('C'));
assertThat(duplicate.array(), is(sameInstance(buffer.array())));
}
@Test
public void getsChar() {
char[] array = { 'T', 'e', 'a', 'V', 'M' };
CharBuffer buffer = CharBuffer.wrap(array);
assertThat(buffer.get(), is('T'));
assertThat(buffer.get(), is('e'));
buffer = buffer.slice();
assertThat(buffer.get(), is('a'));
assertThat(buffer.get(), is('V'));
}
@Test
public void gettingCharFromEmptyBufferCausesError() {
char[] array = { 'T', 'e', 'a', 'V', 'M' };
CharBuffer buffer = CharBuffer.wrap(array);
buffer.limit(2);
buffer.get();
buffer.get();
try {
buffer.get();
fail("Should have thrown error");
} catch (BufferUnderflowException e) {
// ok
}
}
@Test
public void putsChar() {
char[] array = new char[5];
CharBuffer buffer = CharBuffer.wrap(array);
buffer.put('T').put('e').put('a').put('V').put('M');
assertThat(array, is(new char[] { 'T', 'e', 'a', 'V', 'M' }));
}
@Test
public void puttingCharToEmptyBufferCausesError() {
char[] array = new char[4];
CharBuffer buffer = CharBuffer.wrap(array);
buffer.limit(2);
buffer.put('A').put('B');
try {
buffer.put('C');
fail("Should have thrown error");
} catch (BufferOverflowException e) {
assertThat(array[2], is('\0'));
}
}
@Test(expected = ReadOnlyBufferException.class)
public void puttingCharToReadOnlyBufferCausesError() {
char[] array = new char[4];
CharBuffer buffer = CharBuffer.wrap(array).asReadOnlyBuffer();
buffer.put('A');
}
@Test
public void getsCharFromGivenLocation() {
char[] array = { 'T', 'e', 'a', 'V', 'M' };
CharBuffer buffer = CharBuffer.wrap(array);
assertThat(buffer.get(0), is('T'));
assertThat(buffer.get(1), is('e'));
buffer.get();
buffer = buffer.slice();
assertThat(buffer.get(1), is('a'));
assertThat(buffer.get(2), is('V'));
}
@Test
public void gettingCharFromWrongLocationCausesError() {
char[] array = { 'T', 'e', 'a', 'V', 'M' };
CharBuffer buffer = CharBuffer.wrap(array);
buffer.limit(3);
try {
buffer.get(-1);
} catch (IndexOutOfBoundsException e) {
// ok
}
try {
buffer.get(3);
} catch (IndexOutOfBoundsException e) {
// ok
}
}
@Test
public void putsCharToGivenLocation() {
char[] array = new char[5];
CharBuffer buffer = CharBuffer.wrap(array);
buffer.put(0, 'T');
buffer.put(1, 'e');
buffer.get();
buffer = buffer.slice();
buffer.put(1, 'a');
buffer.put(2, 'V');
buffer.put(3, 'M');
assertThat(array, is(new char[] { 'T', 'e', 'a', 'V', 'M' }));
}
@Test
public void puttingCharToWrongLocationCausesError() {
char[] array = new char[4];
CharBuffer buffer = CharBuffer.wrap(array);
buffer.limit(3);
try {
buffer.put(-1, 'A');
} catch (IndexOutOfBoundsException e) {
// ok
}
try {
buffer.put(3, 'A');
} catch (IndexOutOfBoundsException e) {
// ok
}
}
@Test(expected = ReadOnlyBufferException.class)
public void puttingCharToGivenLocationOfReadOnlyBufferCausesError() {
char[] array = new char[4];
CharBuffer buffer = CharBuffer.wrap(array).asReadOnlyBuffer();
buffer.put(0, 'A');
}
@Test
public void getsChars() {
char[] array = { 'T', 'e', 'a', 'V', 'M' };
CharBuffer buffer = CharBuffer.wrap(array);
buffer.get();
char[] receiver = new char[2];
buffer.get(receiver, 0, 2);
assertThat(buffer.position(), is(3));
assertThat(receiver, is(new char[] { 'e', 'a' }));
}
@Test
public void gettingCharsFromEmptyBufferCausesError() {
char[] array = { 'T', 'e', 'a', 'V', 'M' };
CharBuffer buffer = CharBuffer.wrap(array);
buffer.limit(3);
char[] receiver = new char[5];
try {
buffer.get(receiver, 0, 4);
fail("Error expected");
} catch (BufferUnderflowException e) {
assertThat(receiver, is(new char[5]));
assertThat(buffer.position(), is(0));
}
}
@Test
public void gettingCharsWithIllegalArgumentsCausesError() {
char[] array = { 'T', 'e', 'a', 'V', 'M' };
CharBuffer buffer = CharBuffer.wrap(array);
char[] receiver = new char[5];
try {
buffer.get(receiver, 0, 6);
} catch (IndexOutOfBoundsException e) {
assertThat(receiver, is(new char[5]));
assertThat(buffer.position(), is(0));
}
try {
buffer.get(receiver, -1, 3);
} catch (IndexOutOfBoundsException e) {
assertThat(receiver, is(new char[5]));
assertThat(buffer.position(), is(0));
}
try {
buffer.get(receiver, 6, 3);
} catch (IndexOutOfBoundsException e) {
assertThat(receiver, is(new char[5]));
assertThat(buffer.position(), is(0));
}
}
@Test
public void putsChars() {
char[] array = new char[4];
CharBuffer buffer = CharBuffer.wrap(array);
buffer.get();
char[] data = { 'A', 'B' };
buffer.put(data, 0, 2);
assertThat(buffer.position(), is(3));
assertThat(array, is(new char[] { '\0', 'A', 'B', '\0' }));
}
@Test
public void compacts() {
char[] array = { 'T', 'e', 'a', 'V', 'M' };
CharBuffer buffer = CharBuffer.wrap(array);
buffer.get();
buffer.mark();
buffer.compact();
assertThat(array, is(new char[] { 'e', 'a', 'V', 'M', 'M' }));
assertThat(buffer.position(), is(4));
assertThat(buffer.limit(), is(5));
assertThat(buffer.capacity(), is(5));
try {
buffer.reset();
fail("Exception expected");
} catch (InvalidMarkException e) {
// ok
}
}
@Test
public void marksPosition() {
char[] array = { 'T', 'e', 'a', 'V', 'M' };
CharBuffer buffer = CharBuffer.wrap(array);
buffer.position(1);
buffer.mark();
buffer.position(2);
buffer.reset();
assertThat(buffer.position(), is(1));
}
@Test
public void readsChars() throws IOException {
char[] array = { 'T', 'e', 'a', 'V', 'M' };
CharBuffer buffer = CharBuffer.wrap(array);
CharBuffer target = CharBuffer.allocate(10);
int charsRead = buffer.read(target);
assertThat(charsRead, is(5));
assertThat(target.get(0), is('T'));
assertThat(target.get(4), is('M'));
assertThat(target.get(5), is('\0'));
}
@Test
public void readsCharsToSmallBuffer() throws IOException {
char[] array = { 'T', 'e', 'a', 'V', 'M' };
CharBuffer buffer = CharBuffer.wrap(array);
CharBuffer target = CharBuffer.allocate(2);
int charsRead = buffer.read(target);
assertThat(charsRead, is(2));
assertThat(target.get(0), is('T'));
assertThat(target.get(1), is('e'));
}
@Test
public void readsCharsToEmptyBuffer() throws IOException {
char[] array = { 'T', 'e', 'a', 'V', 'M' };
CharBuffer buffer = CharBuffer.wrap(array);
CharBuffer target = CharBuffer.allocate(2);
target.position(2);
int charsRead = buffer.read(target);
assertThat(charsRead, is(0));
}
@Test
public void readsCharsFromEmptyBuffer() throws IOException {
char[] array = { 'T', 'e', 'a', 'V', 'M' };
CharBuffer buffer = CharBuffer.wrap(array);
CharBuffer target = CharBuffer.allocate(2);
buffer.position(5);
int charsRead = buffer.read(target);
assertThat(charsRead, is(-1));
}
@Test
public void wrapsCharSequence() {
CharBuffer buffer = CharBuffer.wrap("TeaVM", 2, 4);
assertThat(buffer.capacity(), is(5));
assertThat(buffer.limit(), is(4));
assertThat(buffer.position(), is(2));
}
@Test
public void putsString() {
CharBuffer buffer = CharBuffer.allocate(100);
buffer.put("TeaVM");
assertThat(buffer.flip().toString(), is("TeaVM"));
}
}