You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by mw...@apache.org on 2008/08/13 01:24:27 UTC
svn commit: r685367 [2/2] - in /mina/trunk/core/src:
main/java/org/apache/mina/util/byteaccess/
test/java/org/apache/mina/util/byteaccess/
Added: mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoAbsoluteWriter.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoAbsoluteWriter.java?rev=685367&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoAbsoluteWriter.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoAbsoluteWriter.java Tue Aug 12 16:24:26 2008
@@ -0,0 +1,101 @@
+/*
+ * 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 org.apache.mina.util.byteaccess;
+
+
+import java.nio.ByteOrder;
+
+import org.apache.mina.core.buffer.IoBuffer;
+
+
+/**
+ * Provides absolute write access to a sequence of bytes.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+public interface IoAbsoluteWriter
+{
+
+ /**
+ * Get the index of the first byte that can be accessed.
+ */
+ int first();
+
+
+ /**
+ * Gets the index after the last byte that can be accessed.
+ */
+ int last();
+
+
+ /**
+ * Gets the order of the bytes.
+ */
+ ByteOrder order();
+
+
+ /**
+ * Puts a <code>byte</code> at the given index.
+ */
+ void put( int index, byte b );
+
+
+ /**
+ * Puts bytes from the <code>IoBuffer</code> at the given index.
+ */
+ public void put( int index, IoBuffer bb );
+
+
+ /**
+ * Puts a <code>short</code> at the given index.
+ */
+ void putShort( int index, short s );
+
+
+ /**
+ * Puts an <code>int</code> at the given index.
+ */
+ void putInt( int index, int i );
+
+
+ /**
+ * Puts a <code>long</code> at the given index.
+ */
+ void putLong( int index, long l );
+
+
+ /**
+ * Puts a <code>float</code> at the given index.
+ */
+ void putFloat( int index, float f );
+
+
+ /**
+ * Puts a <code>double</code> at the given index.
+ */
+ void putDouble( int index, double d );
+
+
+ /**
+ * Puts a <code>char</code> at the given index.
+ */
+ void putChar( int index, char c );
+}
Added: mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoRelativeReader.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoRelativeReader.java?rev=685367&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoRelativeReader.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoRelativeReader.java Tue Aug 12 16:24:26 2008
@@ -0,0 +1,113 @@
+/*
+ * 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 org.apache.mina.util.byteaccess;
+
+
+import java.nio.ByteOrder;
+
+import org.apache.mina.core.buffer.IoBuffer;
+
+
+/**
+ * Provides relative read access to a sequence of bytes.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+public interface IoRelativeReader
+{
+
+ /**
+ * Gets the number of remaining bytes that can be read.
+ */
+ int getRemaining();
+
+
+ /**
+ * Checks if there are any remaining bytes that can be read.
+ */
+ boolean hasRemaining();
+
+
+ /**
+ * Advances the reader by the given number of bytes.
+ */
+ void skip( int length );
+
+
+ /**
+ * Creates an array with a view of part of this array.
+ */
+ ByteArray slice( int length );
+
+
+ /**
+ * Gets the order of the bytes.
+ */
+ ByteOrder order();
+
+
+ /**
+ * Gets a <code>byte</code> and advances the reader.
+ */
+ byte get();
+
+
+ /**
+ * Gets enough bytes to fill the <code>IoBuffer</code> and advances the reader.
+ */
+ void get( IoBuffer bb );
+
+
+ /**
+ * Gets a <code>short</code> and advances the reader.
+ */
+ short getShort();
+
+
+ /**
+ * Gets an <code>int</code> and advances the reader.
+ */
+ int getInt();
+
+
+ /**
+ * Gets a <code>long</code> and advances the reader.
+ */
+ long getLong();
+
+
+ /**
+ * Gets a <code>float</code> and advances the reader.
+ */
+ float getFloat();
+
+
+ /**
+ * Gets a <code>double</code> and advances the reader.
+ */
+ double getDouble();
+
+
+ /**
+ * Gets a <code>char</code> and advances the reader.
+ */
+ char getChar();
+}
Added: mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoRelativeWriter.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoRelativeWriter.java?rev=685367&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoRelativeWriter.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoRelativeWriter.java Tue Aug 12 16:24:26 2008
@@ -0,0 +1,107 @@
+/*
+ * 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 org.apache.mina.util.byteaccess;
+
+
+import java.nio.ByteOrder;
+
+import org.apache.mina.core.buffer.IoBuffer;
+
+
+/**
+ * Provides relative read access to a sequence of bytes.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+public interface IoRelativeWriter
+{
+
+ /**
+ * Gets the number of remaining bytes that can be read.
+ */
+ int getRemaining();
+
+
+ /**
+ * Checks if there are any remaining bytes that can be read.
+ */
+ boolean hasRemaining();
+
+
+ /**
+ * Advances the writer by the given number of bytes.
+ */
+ void skip( int length );
+
+
+ /**
+ * Gets the order of the bytes.
+ */
+ ByteOrder order();
+
+
+ /**
+ * Puts a <code>byte</code> and advances the reader.
+ */
+ void put( byte b );
+
+
+ /**
+ * Puts enough bytes to fill the <code>IoBuffer</code> and advances the reader.
+ */
+ void put( IoBuffer bb );
+
+
+ /**
+ * Puts a <code>short</code> and advances the reader.
+ */
+ void putShort( short s );
+
+
+ /**
+ * Puts an <code>int</code> and advances the reader.
+ */
+ void putInt( int i );
+
+
+ /**
+ * Puts a <code>long</code> and advances the reader.
+ */
+ void putLong( long l );
+
+
+ /**
+ * Puts a <code>float</code> and advances the reader.
+ */
+ void putFloat( float f );
+
+
+ /**
+ * Puts a <code>double</code> and advances the reader.
+ */
+ void putDouble( double d );
+
+
+ /**
+ * Puts a <code>char</code> and advances the reader.
+ */
+ void putChar( char c );
+}
Added: mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/SimpleByteArrayFactory.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/SimpleByteArrayFactory.java?rev=685367&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/SimpleByteArrayFactory.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/SimpleByteArrayFactory.java Tue Aug 12 16:24:26 2008
@@ -0,0 +1,70 @@
+/*
+ * 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 org.apache.mina.util.byteaccess;
+
+
+import org.apache.mina.core.buffer.IoBuffer;
+
+
+/**
+ * Creates <code>ByteArray</code> backed by a heap-allocated
+ * <code>IoBuffer</code>. The free method on returned
+ * <code>ByteArray</code>s is a nop.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+public class SimpleByteArrayFactory implements ByteArrayFactory
+{
+ /**
+ *
+ * Creates a new instance of SimpleByteArrayFactory.
+ *
+ */
+ public SimpleByteArrayFactory()
+ {
+ super();
+ }
+
+
+ /**
+ * @inheritDoc
+ */
+ public ByteArray create( int size )
+ {
+ if ( size < 0 )
+ {
+ throw new IllegalArgumentException( "Buffer size must not be negative:" + size );
+ }
+ IoBuffer bb = IoBuffer.allocate( size );
+ ByteArray ba = new BufferByteArray( bb )
+ {
+
+ @Override
+ public void free()
+ {
+ // Nothing to do.
+ }
+
+ };
+ return ba;
+ }
+
+}
Added: mina/trunk/core/src/test/java/org/apache/mina/util/byteaccess/ByteAccessTest.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/test/java/org/apache/mina/util/byteaccess/ByteAccessTest.java?rev=685367&view=auto
==============================================================================
--- mina/trunk/core/src/test/java/org/apache/mina/util/byteaccess/ByteAccessTest.java (added)
+++ mina/trunk/core/src/test/java/org/apache/mina/util/byteaccess/ByteAccessTest.java Tue Aug 12 16:24:26 2008
@@ -0,0 +1,558 @@
+/*
+ * 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 org.apache.mina.util.byteaccess;
+
+import static org.easymock.EasyMock.createStrictControl;
+
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.util.byteaccess.ByteArray.Cursor;
+import org.apache.mina.util.byteaccess.CompositeByteArray.CursorListener;
+import org.apache.mina.util.byteaccess.CompositeByteArrayRelativeWriter.ChunkedExpander;
+import org.apache.mina.util.byteaccess.CompositeByteArrayRelativeWriter.Flusher;
+import org.easymock.IMocksControl;
+
+/**
+ * Tests classes in the <code>byteaccess</code> package.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class ByteAccessTest extends TestCase {
+
+ private List<String> operations = new ArrayList<String>();
+
+ private void resetOperations() {
+ operations.clear();
+ }
+
+ private void assertOperationCountEquals(int expectedCount) {
+ assertEquals("Operations: " + operations, expectedCount, operations.size());
+ }
+
+ private void addOperation(String description) {
+ operations.add(description);
+ }
+
+ public void testBufferByteArray() throws Exception {
+ ByteArray ba = getByteArrayFactory().create(1000);
+ testAbsoluteReaderAndWriter(0, 1000, ba, ba);
+ testAbsoluteReaderAndWriter(0, 1000, ba, ba);
+ Cursor readCursor = ba.cursor();
+ Cursor writeCursor = ba.cursor();
+ testRelativeReaderAndWriter(1000, readCursor, writeCursor);
+ }
+
+ public void testCompositeAddAndRemove() throws Exception {
+ CompositeByteArray cba = new CompositeByteArray();
+ assertEquals(0, cba.first());
+ assertEquals(0, cba.last());
+ cba.addFirst(getByteArrayFactory().create(100));
+ assertEquals(-100, cba.first());
+ assertEquals(0, cba.last());
+ cba.addFirst(getByteArrayFactory().create(100));
+ assertEquals(-200, cba.first());
+ assertEquals(0, cba.last());
+ cba.addLast(getByteArrayFactory().create(100));
+ assertEquals(-200, cba.first());
+ assertEquals(100, cba.last());
+ cba.removeFirst();
+ assertEquals(-100, cba.first());
+ assertEquals(100, cba.last());
+ cba.addLast(getByteArrayFactory().create(100));
+ assertEquals(-100, cba.first());
+ assertEquals(200, cba.last());
+ cba.removeLast();
+ assertEquals(-100, cba.first());
+ assertEquals(100, cba.last());
+ cba.removeFirst();
+ assertEquals(0, cba.first());
+ assertEquals(100, cba.last());
+ cba.removeFirst();
+ assertEquals(100, cba.first());
+ assertEquals(100, cba.last());
+ cba.addLast(getByteArrayFactory().create(100));
+ assertEquals(100, cba.first());
+ assertEquals(200, cba.last());
+ }
+
+ private BufferByteArray wrapString(String string) {
+ byte[] bytes = string.getBytes();
+ IoBuffer bb = IoBuffer.wrap(bytes);
+ BufferByteArray ba = new BufferByteArray(bb) {
+
+ @Override
+ public void free() {
+ addOperation(this + ".free()");
+ // Nothing to do.
+ }
+
+ };
+ return ba;
+ }
+
+ private String toString(ByteArray ba) {
+ IoBuffer bb = IoBuffer.allocate(ba.length());
+ ba.get(0, bb);
+ byte[] bytes = bb.array();
+ String string = new String(bytes);
+ return string;
+ }
+
+ public void testCompositeStringJoin() throws Exception {
+ ByteArray ba1 = wrapString("Hello");
+ ByteArray ba2 = wrapString("MINA");
+ ByteArray ba3 = wrapString("World");
+
+ CompositeByteArray cba = new CompositeByteArray();
+ cba.addLast(ba1);
+ cba.addLast(ba2);
+ cba.addLast(ba3);
+
+ assertEquals("HelloMINAWorld", toString(cba));
+ }
+
+ public void testCompositeCursor() throws Exception {
+ IMocksControl mc = createStrictControl();
+
+ ByteArray ba1 = getByteArrayFactory().create(10);
+ ByteArray ba2 = getByteArrayFactory().create(10);
+ ByteArray ba3 = getByteArrayFactory().create(10);
+
+
+ CompositeByteArray cba = new CompositeByteArray();
+ cba.addLast(ba1);
+ cba.addLast(ba2);
+ cba.addLast(ba3);
+
+ CursorListener cl = mc.createMock(CursorListener.class);
+
+ mc.reset();
+ mc.replay();
+ Cursor cursor = cba.cursor(cl);
+ mc.verify();
+
+ mc.reset();
+ cl.enteredFirstComponent(0, ba1);
+ mc.replay();
+ cursor.get();
+ mc.verify();
+
+ mc.reset();
+ mc.replay();
+ cursor.setIndex(10);
+ mc.verify();
+
+ mc.reset();
+ cl.enteredNextComponent(10, ba2);
+ mc.replay();
+ cursor.put((byte) 55);
+ mc.verify();
+
+ mc.reset();
+ mc.replay();
+ cursor.setIndex(9);
+ mc.verify();
+
+ mc.reset();
+ cl.enteredPreviousComponent(0, ba1);
+ cl.enteredNextComponent(10, ba2);
+ mc.replay();
+ cursor.putInt(66);
+ mc.verify();
+
+ mc.reset();
+ cl.enteredNextComponent(20, ba3);
+ mc.replay();
+ cursor.setIndex(29);
+ cursor.get();
+ mc.verify();
+
+ cba.removeLast(); // Force cursor to relocate itself.
+
+ mc.reset();
+ cl.enteredLastComponent(10, ba2);
+ mc.replay();
+ cursor.setIndex(15);
+ cursor.get();
+ mc.verify();
+
+ mc.reset();
+ cl.enteredPreviousComponent(0, ba1);
+ mc.replay();
+ cursor.setIndex(0);
+ cursor.get();
+ mc.verify();
+ }
+
+ public void testCompositeByteArray() throws Exception {
+ CompositeByteArray ba = new CompositeByteArray();
+ for (int i = 0; i < 1000; i += 100) {
+ ba.addLast(getByteArrayFactory().create(100));
+ }
+ resetOperations();
+ testAbsoluteReaderAndWriter(0, 1000, ba, ba);
+ testAbsoluteReaderAndWriter(0, 1000, ba, ba);
+ assertOperationCountEquals(0);
+ Cursor readCursor = ba.cursor();
+ Cursor writeCursor = ba.cursor();
+ testRelativeReaderAndWriter(1000, readCursor, writeCursor);
+ assertOperationCountEquals(0);
+ }
+
+ public void testCompositeByteArrayRelativeReaderAndWriter() throws Exception {
+ CompositeByteArray cba = new CompositeByteArray();
+ CompositeByteArrayRelativeReader cbarr = new CompositeByteArrayRelativeReader(cba, true);
+ CompositeByteArrayRelativeWriter cbarw = new CompositeByteArrayRelativeWriter(cba, getExpander(100), getFlusher(), false);
+ resetOperations();
+ testRelativeReaderAndWriter(10, cbarr, cbarw);
+ assertOperationCountEquals(2);
+ resetOperations();
+ testRelativeReaderAndWriter(100, cbarr, cbarw);
+ assertOperationCountEquals(3);
+ resetOperations();
+ testRelativeReaderAndWriter(1000, cbarr, cbarw);
+ assertOperationCountEquals(30);
+ resetOperations();
+ testRelativeReaderAndWriter(10000, cbarr, cbarw);
+ assertOperationCountEquals(300);
+ resetOperations();
+ testRelativeReaderAndWriter(90, cbarr, cbarw);
+ assertOperationCountEquals(0); // Last free doesn't occur, since cursor only moves lazily.
+ }
+
+ public void testCompositeByteArrayRelativeReaderAndWriterWithFlush() throws Exception {
+ CompositeByteArray cba = new CompositeByteArray();
+ CompositeByteArrayRelativeReader cbarr = new CompositeByteArrayRelativeReader(cba, true);
+ CompositeByteArrayRelativeWriter cbarw = new CompositeByteArrayRelativeWriter(cba, getExpander(100), getFlusher(), true);
+ resetOperations();
+ testRelativeReaderAndWriter(10, cbarr, cbarw);
+ assertOperationCountEquals(2);
+ resetOperations();
+ testRelativeReaderAndWriter(100, cbarr, cbarw);
+ assertOperationCountEquals(4);
+ resetOperations();
+ testRelativeReaderAndWriter(1000, cbarr, cbarw);
+ assertOperationCountEquals(40);
+ resetOperations();
+ testRelativeReaderAndWriter(10000, cbarr, cbarw);
+ assertOperationCountEquals(400);
+ resetOperations();
+ testRelativeReaderAndWriter(90, cbarr, cbarw);
+ assertOperationCountEquals(0); // Last free doesn't occur, since cursor only moves lazily.
+ }
+
+ public void testCompositeRemoveTo() throws Exception {
+ CompositeByteArray cba = new CompositeByteArray();
+ {
+ // Remove nothing.
+ resetOperations();
+ ByteArray removed = cba.removeTo(0);
+ assertEquals(0, removed.first());
+ assertEquals(0, removed.last());
+ assertEquals(0, cba.first());
+ assertEquals(0, cba.last());
+ removed.free();
+ assertOperationCountEquals(0);
+ }
+ cba.addLast(getByteArrayFactory().create(100));
+ {
+ // Remove nothing.
+ resetOperations();
+ ByteArray removed = cba.removeTo(0);
+ assertEquals(0, removed.first());
+ assertEquals(0, removed.last());
+ assertEquals(0, cba.first());
+ assertEquals(100, cba.last());
+ removed.free();
+ assertOperationCountEquals(0);
+ }
+ {
+ // Remove entire component.
+ resetOperations();
+ ByteArray removed = cba.removeTo(100);
+ assertEquals(0, removed.first());
+ assertEquals(100, removed.last());
+ assertEquals(100, cba.first());
+ assertEquals(100, cba.last());
+ removed.free();
+ assertOperationCountEquals(1);
+ }
+ {
+ // Remove nothing.
+ resetOperations();
+ ByteArray removed = cba.removeTo(100);
+ assertEquals(0, removed.first());
+ assertEquals(0, removed.last());
+ assertEquals(100, cba.first());
+ assertEquals(100, cba.last());
+ removed.free();
+ assertOperationCountEquals(0);
+ }
+ cba.addLast(getByteArrayFactory().create(100));
+ {
+ // Remove nothing.
+ resetOperations();
+ ByteArray removed = cba.removeTo(100);
+ assertEquals(0, removed.first());
+ assertEquals(0, removed.last());
+ assertEquals(100, cba.first());
+ assertEquals(200, cba.last());
+ removed.free();
+ assertOperationCountEquals(0);
+ }
+ {
+ // Remove half a component.
+ resetOperations();
+ ByteArray removed = cba.removeTo(150);
+ assertEquals(0, removed.first());
+ assertEquals(50, removed.last());
+ assertEquals(150, cba.first());
+ assertEquals(200, cba.last());
+ removed.free();
+ assertOperationCountEquals(0); // Doesn't free until component finished.
+ }
+ {
+ // Remove nothing.
+ resetOperations();
+ ByteArray removed = cba.removeTo(150);
+ assertEquals(0, removed.first());
+ assertEquals(0, removed.last());
+ assertEquals(150, cba.first());
+ assertEquals(200, cba.last());
+ removed.free();
+ assertOperationCountEquals(0);
+ }
+ {
+ // Remove other half.
+ resetOperations();
+ ByteArray removed = cba.removeTo(200);
+ assertEquals(0, removed.first());
+ assertEquals(50, removed.last());
+ assertEquals(200, cba.first());
+ assertEquals(200, cba.last());
+ removed.free();
+ assertOperationCountEquals(1); // Frees ByteArray behind both buffers.
+ }
+ }
+
+ public void testCompositeByteArraySlicing() {
+ CompositeByteArray cba = new CompositeByteArray();
+ cba.addLast(getByteArrayFactory().create(10));
+ cba.addLast(getByteArrayFactory().create(10));
+ cba.addLast(getByteArrayFactory().create(10));
+ testByteArraySlicing(cba, 0, 30);
+ testByteArraySlicing(cba, 5, 10);
+ testByteArraySlicing(cba, 10, 20);
+ testByteArraySlicing(cba, 1, 28);
+ testByteArraySlicing(cba, 19, 2);
+ }
+
+ public void testBufferByteArraySlicing() {
+ ByteArray bba = getByteArrayFactory().create(30);
+ testByteArraySlicing(bba, 0, 30);
+ testByteArraySlicing(bba, 5, 10);
+ testByteArraySlicing(bba, 10, 20);
+ testByteArraySlicing(bba, 1, 28);
+ testByteArraySlicing(bba, 19, 2);
+
+ }
+
+ private void testByteArraySlicing(ByteArray ba, int start, int length) {
+ ByteArray slice = ba.slice(start, length);
+ for (int i = 0; i < length; i++) {
+ byte b1 = (byte) (i % 67);
+ byte b2 = (byte) (i % 36);
+ int sourceIndex = i + start;
+ int sliceIndex = i;
+ ba.put(sourceIndex, b1);
+ assertEquals(b1, ba.get(sourceIndex));
+ assertEquals(b1, slice.get(sliceIndex));
+ slice.put(sliceIndex, b2);
+ assertEquals(b2, ba.get(sourceIndex));
+ assertEquals(b2, slice.get(sliceIndex));
+ }
+ }
+
+ private ChunkedExpander getExpander(final int chunkSize) {
+ return new ChunkedExpander(getByteArrayFactory(), chunkSize) {
+ @Override
+ public void expand(CompositeByteArray cba, int minSize) {
+ addOperation("ChunkedExpander(" + chunkSize + ").expand(" + cba + "," + minSize + ")");
+ super.expand(cba, minSize);
+ }
+ };
+ }
+
+ private Flusher getFlusher() {
+ return new CompositeByteArrayRelativeWriter.Flusher() {
+
+ public void flush(ByteArray ba) {
+ addOperation("Flusher().flush(" + ba + ")");
+ ba.free();
+ }
+
+ };
+ }
+
+ private SimpleByteArrayFactory getByteArrayFactory() {
+ return new SimpleByteArrayFactory() {
+ @Override
+ public ByteArray create(final int size) {
+ if (size < 0) {
+ throw new IllegalArgumentException(
+ "Buffer size must not be negative:" + size);
+ }
+ IoBuffer bb = IoBuffer.allocate(size);
+ ByteArray ba = new BufferByteArray(bb) {
+
+ @Override
+ public void free() {
+ addOperation(this + ".free()");
+ // Nothing to do.
+ }
+
+ };
+ addOperation("SimpleByteArrayFactory().create(" + size + ") = " + ba);
+ return ba;
+ }
+ };
+ }
+
+ private void testRelativeReaderAndWriter(int length, IoRelativeReader reader, IoRelativeWriter writer) {
+ for (int i = 0; i < length; i++) {
+ byte b = (byte) (i % 67);
+ writer.put(b);
+ assertEquals(b, reader.get());
+ }
+ }
+
+ private void testAbsoluteReaderAndWriter(int start, int length, IoAbsoluteReader reader, IoAbsoluteWriter writer) {
+ for (int i = start; i < length; i++) {
+ byte b = (byte) (i % 67);
+ writer.put(i, b);
+ assertEquals(b, reader.get(i));
+ }
+ }
+
+ public void testByteArrayPrimitiveAccess() {
+ ByteArray bbaBig = getByteArrayFactory().create(1000);
+ bbaBig.order(ByteOrder.BIG_ENDIAN);
+ testPrimitiveAccess(bbaBig.cursor(), bbaBig.cursor());
+
+ ByteArray bbaLittle = getByteArrayFactory().create(1000);
+ bbaLittle.order(ByteOrder.LITTLE_ENDIAN);
+ testPrimitiveAccess(bbaLittle.cursor(), bbaLittle.cursor());
+ }
+
+ public void testByteArrayBufferAccess() {
+ ByteArray ba = getByteArrayFactory().create(1);
+ ba.put(0, (byte) 99);
+ IoBuffer bb = IoBuffer.allocate(2);
+
+ bb.clear();
+ Cursor cursor = ba.cursor();
+ assertEquals(0, cursor.getIndex());
+ assertEquals(1, cursor.getRemaining());
+ assertEquals(0, bb.position());
+ assertEquals(2, bb.remaining());
+ cursor.get(bb);
+ assertEquals(1, cursor.getIndex());
+ assertEquals(0, cursor.getRemaining());
+ assertEquals(1, bb.position());
+ assertEquals(1, bb.remaining());
+ }
+
+ public void testCompositeByteArrayPrimitiveAccess() {
+ CompositeByteArray cbaBig = new CompositeByteArray();
+ cbaBig.order(ByteOrder.BIG_ENDIAN);
+ for (int i = 0; i < 1000; i++) {
+ ByteArray component = getByteArrayFactory().create(1);
+ component.order(ByteOrder.BIG_ENDIAN);
+ cbaBig.addLast(component);
+ }
+ testPrimitiveAccess(cbaBig.cursor(), cbaBig.cursor());
+
+ CompositeByteArray cbaLittle = new CompositeByteArray();
+ cbaLittle.order(ByteOrder.LITTLE_ENDIAN);
+ for (int i = 0; i < 1000; i++) {
+ ByteArray component = getByteArrayFactory().create(1);
+ component.order(ByteOrder.LITTLE_ENDIAN);
+ cbaLittle.addLast(component);
+ }
+ testPrimitiveAccess(cbaLittle.cursor(), cbaLittle.cursor());
+ }
+
+ public void testCompositeByteArrayWrapperPrimitiveAccess() {
+ CompositeByteArray cbaBig = new CompositeByteArray();
+ cbaBig.order(ByteOrder.BIG_ENDIAN);
+ for (int i = 0; i < 1000; i++) {
+ ByteArray component = getByteArrayFactory().create(1);
+ component.order(ByteOrder.BIG_ENDIAN);
+ cbaBig.addLast(component);
+ }
+ testPrimitiveAccess(new CompositeByteArrayRelativeWriter(cbaBig, getExpander(10), getFlusher(), false), new CompositeByteArrayRelativeReader(cbaBig, true));
+
+ CompositeByteArray cbaLittle = new CompositeByteArray();
+ cbaLittle.order(ByteOrder.LITTLE_ENDIAN);
+ for (int i = 0; i < 1000; i++) {
+ ByteArray component = getByteArrayFactory().create(1);
+ component.order(ByteOrder.LITTLE_ENDIAN);
+ cbaLittle.addLast(component);
+ }
+ testPrimitiveAccess(new CompositeByteArrayRelativeWriter(cbaLittle, getExpander(10), getFlusher(), false), new CompositeByteArrayRelativeReader(cbaLittle, true));
+ }
+
+ private void testPrimitiveAccess(IoRelativeWriter write, IoRelativeReader read) {
+ byte b = (byte) 0x12;
+ write.put(b);
+ assertEquals(b, read.get());
+
+ short s = (short) 0x12;
+ write.putShort(s);
+ assertEquals(s, read.getShort());
+
+ int i = 0x12345678;
+ write.putInt(i);
+ assertEquals(i, read.getInt());
+
+ long l = 0x1234567890123456L;
+ write.putLong(l);
+ assertEquals(l, read.getLong());
+
+ float f = Float.intBitsToFloat(i);
+ write.putFloat(f);
+ assertEquals(f, read.getFloat());
+
+ double d = Double.longBitsToDouble(l);
+ write.putDouble(d);
+ assertEquals(d, read.getDouble());
+
+ char c = (char) 0x1234;
+ write.putChar(c);
+ assertEquals(c, read.getChar());
+ }
+
+}