From 5a897af28dd3d00d44d9febf0dd0e5aa6eea2dd9 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Wed, 20 Jan 2010 05:55:16 +0000 Subject: [PATCH] Resolved issue: NETTY-278 ChannelBuffer.bytesBefore() as an alternative to indexOf() * Added various bytesBefore() methods to ChannelBuffer * Deprecated the methods that could be replaced by bytesBefore() --- .../netty/buffer/AbstractChannelBuffer.java | 35 ++++ .../org/jboss/netty/buffer/ChannelBuffer.java | 156 +++++++++++++----- .../buffer/ChannelBufferIndexFinder.java | 6 +- .../codec/replay/ReplayingDecoderBuffer.java | 51 ++++++ .../buffer/AbstractChannelBufferTest.java | 3 + .../codec/replay/ReplayingDecoderTest.java | 3 +- 6 files changed, 208 insertions(+), 46 deletions(-) diff --git a/src/main/java/org/jboss/netty/buffer/AbstractChannelBuffer.java b/src/main/java/org/jboss/netty/buffer/AbstractChannelBuffer.java index 19b8bb0aab..0ba46f77ff 100644 --- a/src/main/java/org/jboss/netty/buffer/AbstractChannelBuffer.java +++ b/src/main/java/org/jboss/netty/buffer/AbstractChannelBuffer.java @@ -583,6 +583,41 @@ public abstract class AbstractChannelBuffer implements ChannelBuffer { return ChannelBuffers.indexOf(this, fromIndex, toIndex, indexFinder); } + public int bytesBefore(byte value) { + return bytesBefore(readerIndex(), readableBytes(), value); + } + + public int bytesBefore(ChannelBufferIndexFinder indexFinder) { + return bytesBefore(readerIndex(), readableBytes(), indexFinder); + } + + public int bytesBefore(int length, byte value) { + checkReadableBytes(length); + return bytesBefore(readerIndex(), length, value); + } + + public int bytesBefore(int length, ChannelBufferIndexFinder indexFinder) { + checkReadableBytes(length); + return bytesBefore(readerIndex(), length, indexFinder); + } + + public int bytesBefore(int index, int length, byte value) { + int endIndex = indexOf(index, index + length, value); + if (endIndex < 0) { + return -1; + } + return endIndex - index; + } + + public int bytesBefore(int index, int length, + ChannelBufferIndexFinder indexFinder) { + int endIndex = indexOf(index, index + length, indexFinder); + if (endIndex < 0) { + return -1; + } + return endIndex - index; + } + @Override public int hashCode() { return ChannelBuffers.hashCode(this); diff --git a/src/main/java/org/jboss/netty/buffer/ChannelBuffer.java b/src/main/java/org/jboss/netty/buffer/ChannelBuffer.java index 197dfe9724..273452027a 100644 --- a/src/main/java/org/jboss/netty/buffer/ChannelBuffer.java +++ b/src/main/java/org/jboss/netty/buffer/ChannelBuffer.java @@ -24,7 +24,6 @@ import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; -import java.util.NoSuchElementException; /** * A random and sequential accessible sequence of zero or more bytes (octets). @@ -176,10 +175,13 @@ import java.util.NoSuchElementException; * *

Search operations

* - * Various {@code indexOf()} methods help you locate an index of a value which - * meets a certain criteria. Complicated dynamic sequential search can be done - * with {@link ChannelBufferIndexFinder} as well as simple static single byte - * search. + * Various {@link #indexOf(int, int, byte)} methods help you locate an index of + * a value which meets a certain criteria. Complicated dynamic sequential + * search can be done with {@link ChannelBufferIndexFinder} as well as simple + * static single byte search. + *

+ * If you are decoding variable length data such as NUL-terminated string, you + * will find {@link #bytesBefore(byte)} also useful. * *

Mark and reset

* @@ -1080,20 +1082,9 @@ public interface ChannelBuffer extends Comparable { ChannelBuffer readBytes(int length); /** - * Transfers this buffer's data to a newly created buffer starting at - * the current {@code readerIndex} until the specified {@code indexFinder} - * returns {@code true} and increases the {@code readerIndex} - * by the number of the transferred bytes. The returned buffer's - * {@code readerIndex} and {@code writerIndex} are {@code 0} and - * the number of the transferred bytes respectively. - * - * @param indexFinder finds the end index of the sub-region - * - * @return the newly created buffer which contains the transferred bytes - * - * @throws NoSuchElementException - * if {@code indexFinder} didn't return {@code true} at all + * @deprecated Use {@link #bytesBefore(ChannelBufferIndexFinder)} and {@link #readBytes(int)} instead. */ + @Deprecated ChannelBuffer readBytes(ChannelBufferIndexFinder indexFinder); /** @@ -1111,17 +1102,9 @@ public interface ChannelBuffer extends Comparable { ChannelBuffer readSlice(int length); /** - * Returns a new slice of this buffer's sub-region starting at the current - * {@code readerIndex} and increases the {@code readerIndex} by the size - * of the new slice (determined by {@code indexFinder}). - * - * @param indexFinder finds the end index of the sub-region - * - * @return the newly created slice - * - * @throws NoSuchElementException - * if {@code indexFinder} didn't return {@code true} at all + * @deprecated Use {@link #bytesBefore(ChannelBufferIndexFinder)} and {@link #readSlice(int)} instead. */ + @Deprecated ChannelBuffer readSlice(ChannelBufferIndexFinder indexFinder); /** @@ -1246,14 +1229,9 @@ public interface ChannelBuffer extends Comparable { void skipBytes(int length); /** - * Increases the current {@code readerIndex} until the specified - * {@code indexFinder} returns {@code true} in this buffer. - * - * @return the number of skipped bytes - * - * @throws NoSuchElementException - * if {@code firstIndexFinder} didn't return {@code true} at all + * @deprecated Use {@link #bytesBefore(ChannelBufferIndexFinder)} and {@link #skipBytes(int)} instead. */ + @Deprecated int skipBytes(ChannelBufferIndexFinder indexFinder); /** @@ -1483,7 +1461,7 @@ public interface ChannelBuffer extends Comparable { int indexOf(int fromIndex, int toIndex, byte value); /** - * Locates the first index where the specified {@code indexFinder} + * Locates the first place where the specified {@code indexFinder} * returns {@code true}. The search takes place from the specified * {@code fromIndex} (inclusive) to the specified {@code toIndex} * (exclusive). @@ -1495,11 +1473,107 @@ public interface ChannelBuffer extends Comparable { * this buffer. * * @return the absolute index where the specified {@code indexFinder} - * returned {@code true} if the {@code indexFinder} returned - * {@code true}. {@code -1} otherwise. + * returned {@code true}. {@code -1} if the {@code indexFinder} + * did not return {@code true} at all. */ int indexOf(int fromIndex, int toIndex, ChannelBufferIndexFinder indexFinder); + /** + * Locates the first occurrence of the specified {@code value} in this + * buffer. The search takes place from the current {@code readerIndex} + * (inclusive) to the current {@code writerIndex} (exclusive). + *

+ * This method does not modify {@code readerIndex} or {@code writerIndex} of + * this buffer. + * + * @return the number of bytes between the current {@code readerIndex} + * and the first occurrence if found. {@code -1} otherwise. + */ + int bytesBefore(byte value); + + /** + * Locates the first place where the specified {@code indexFinder} returns + * {@code true}. The search takes place from the current {@code readerIndex} + * (inclusive) to the current {@code writerIndex}. + *

+ * This method does not modify {@code readerIndex} or {@code writerIndex} of + * this buffer. + * + * @return the number of bytes between the current {@code readerIndex} + * and the first place where the {@code indexFinder} returned + * {@code true}. {@code -1} if the {@code indexFinder} did not + * return {@code true} at all. + */ + int bytesBefore(ChannelBufferIndexFinder indexFinder); + + /** + * Locates the first occurrence of the specified {@code value} in this + * buffer. The search starts from the current {@code readerIndex} + * (inclusive) and lasts for the specified {@code length}. + *

+ * This method does not modify {@code readerIndex} or {@code writerIndex} of + * this buffer. + * + * @return the number of bytes between the current {@code readerIndex} + * and the first occurrence if found. {@code -1} otherwise. + * + * @throws IndexOutOfBoundsException + * if {@code length} is greater than {@code this.readableBytes} + */ + int bytesBefore(int length, byte value); + + /** + * Locates the first place where the specified {@code indexFinder} returns + * {@code true}. The search starts the current {@code readerIndex} + * (inclusive) and lasts for the specified {@code length}. + *

+ * This method does not modify {@code readerIndex} or {@code writerIndex} of + * this buffer. + * + * @return the number of bytes between the current {@code readerIndex} + * and the first place where the {@code indexFinder} returned + * {@code true}. {@code -1} if the {@code indexFinder} did not + * return {@code true} at all. + * + * @throws IndexOutOfBoundsException + * if {@code length} is greater than {@code this.readableBytes} + */ + int bytesBefore(int length, ChannelBufferIndexFinder indexFinder); + + /** + * Locates the first occurrence of the specified {@code value} in this + * buffer. The search starts from the specified {@code index} (inclusive) + * and lasts for the specified {@code length}. + *

+ * This method does not modify {@code readerIndex} or {@code writerIndex} of + * this buffer. + * + * @return the number of bytes between the specified {@code index} + * and the first occurrence if found. {@code -1} otherwise. + * + * @throws IndexOutOfBoundsException + * if {@code index + length} is greater than {@code this.capacity} + */ + int bytesBefore(int index, int length, byte value); + + /** + * Locates the first place where the specified {@code indexFinder} returns + * {@code true}. The search starts the specified {@code index} (inclusive) + * and lasts for the specified {@code length}. + *

+ * This method does not modify {@code readerIndex} or {@code writerIndex} of + * this buffer. + * + * @return the number of bytes between the specified {@code index} + * and the first place where the {@code indexFinder} returned + * {@code true}. {@code -1} if the {@code indexFinder} did not + * return {@code true} at all. + * + * @throws IndexOutOfBoundsException + * if {@code index + length} is greater than {@code this.capacity} + */ + int bytesBefore(int index, int length, ChannelBufferIndexFinder indexFinder); + /** * Returns a copy of this buffer's readable bytes. Modifying the content * of the returned buffer or this buffer does not affect each other at all. @@ -1636,20 +1710,20 @@ public interface ChannelBuffer extends Comparable { String toString(String charsetName); /** - * @deprecated Use {@link #toString(int, int, Charset)} instead. + * @deprecated Use {@link #bytesBefore(ChannelBufferIndexFinder)} and {@link #toString(int, int, Charset)} instead. */ @Deprecated String toString( String charsetName, ChannelBufferIndexFinder terminatorFinder); /** - * @deprecated Use {@link #toString(int, int, Charset)} instead. + * @deprecated Use {@link #bytesBefore(int, int, ChannelBufferIndexFinder)} and {@link #toString(int, int, Charset)} instead. */ @Deprecated String toString(int index, int length, String charsetName); /** - * @deprecated Use {@link #toString(int, int, Charset)} instead. + * @deprecated Use {@link #bytesBefore(int, int, ChannelBufferIndexFinder)} and {@link #toString(int, int, Charset)} instead. */ @Deprecated String toString( diff --git a/src/main/java/org/jboss/netty/buffer/ChannelBufferIndexFinder.java b/src/main/java/org/jboss/netty/buffer/ChannelBufferIndexFinder.java index 3bab8a9756..d9a393c3b2 100644 --- a/src/main/java/org/jboss/netty/buffer/ChannelBufferIndexFinder.java +++ b/src/main/java/org/jboss/netty/buffer/ChannelBufferIndexFinder.java @@ -21,10 +21,8 @@ package org.jboss.netty.buffer; *

* This interface enables the sequential search for the data which meets more * complex and dynamic condition than just a simple value matching. Please - * refer to {@link ChannelBuffer#indexOf(int, int, ChannelBufferIndexFinder)}, - * {@link ChannelBuffer#readBytes(ChannelBufferIndexFinder)}, - * {@link ChannelBuffer#readSlice(ChannelBufferIndexFinder)}, and - * {@link ChannelBuffer#skipBytes(ChannelBufferIndexFinder)} + * refer to {@link ChannelBuffer#indexOf(int, int, ChannelBufferIndexFinder)} and + * {@link ChannelBuffer#bytesBefore(int, int, ChannelBufferIndexFinder)} * for more explanation. * * @author The Netty Project (netty-dev@lists.jboss.org) diff --git a/src/main/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderBuffer.java b/src/main/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderBuffer.java index 8abe2a242f..e40abe6fb8 100644 --- a/src/main/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderBuffer.java +++ b/src/main/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderBuffer.java @@ -223,6 +223,57 @@ class ReplayingDecoderBuffer implements ChannelBuffer { return endIndex; } + public int bytesBefore(byte value) { + int bytes = buffer.bytesBefore(value); + if (bytes < 0) { + throw REPLAY; + } + return bytes; + } + + public int bytesBefore(ChannelBufferIndexFinder indexFinder) { + int bytes = buffer.bytesBefore(indexFinder); + if (bytes < 0) { + throw REPLAY; + } + return bytes; + } + + public int bytesBefore(int length, byte value) { + checkReadableBytes(length); + int bytes = buffer.bytesBefore(length, value); + if (bytes < 0) { + throw REPLAY; + } + return bytes; + } + + public int bytesBefore(int length, ChannelBufferIndexFinder indexFinder) { + checkReadableBytes(length); + int bytes = buffer.bytesBefore(length, indexFinder); + if (bytes < 0) { + throw REPLAY; + } + return bytes; + } + + public int bytesBefore(int index, int length, byte value) { + int bytes = buffer.bytesBefore(index, length, value); + if (bytes < 0) { + throw REPLAY; + } + return bytes; + } + + public int bytesBefore(int index, int length, + ChannelBufferIndexFinder indexFinder) { + int bytes = buffer.bytesBefore(index, length, indexFinder); + if (bytes < 0) { + throw REPLAY; + } + return bytes; + } + public void markReaderIndex() { buffer.markReaderIndex(); } diff --git a/src/test/java/org/jboss/netty/buffer/AbstractChannelBufferTest.java b/src/test/java/org/jboss/netty/buffer/AbstractChannelBufferTest.java index 2d5de9fdb6..6c2f2a7ff9 100644 --- a/src/test/java/org/jboss/netty/buffer/AbstractChannelBufferTest.java +++ b/src/test/java/org/jboss/netty/buffer/AbstractChannelBufferTest.java @@ -1199,6 +1199,7 @@ public abstract class AbstractChannelBufferTest { } @Test + @SuppressWarnings("deprecation") public void testSequentialCopiedBufferTransfer2() { buffer.clear(); buffer.writeZero(buffer.capacity()); @@ -1249,6 +1250,7 @@ public abstract class AbstractChannelBufferTest { } @Test + @SuppressWarnings("deprecation") public void testSequentialSlice2() { buffer.clear(); buffer.writeZero(buffer.capacity()); @@ -1641,6 +1643,7 @@ public abstract class AbstractChannelBufferTest { } @Test + @SuppressWarnings("deprecation") public void testSkipBytes2() { buffer.clear(); buffer.writeZero(buffer.capacity()); diff --git a/src/test/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderTest.java b/src/test/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderTest.java index 0414ca03dc..6d7a4118c1 100644 --- a/src/test/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderTest.java +++ b/src/test/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderTest.java @@ -63,7 +63,8 @@ public class ReplayingDecoderTest { @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, VoidEnum state) throws Exception { - ChannelBuffer msg = buffer.readBytes(ChannelBufferIndexFinder.LF); + ChannelBuffer msg = buffer.readBytes( + buffer.bytesBefore(ChannelBufferIndexFinder.LF)); buffer.skipBytes(1); return msg; }