diff --git a/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java b/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java index 0f24e085e8..cbbcc24e18 100644 --- a/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java @@ -767,7 +767,7 @@ public abstract class AbstractByteBuf implements ByteBuf { @Override public ByteBuf writeByte(int value) { ensureWritable(1); - setByte(writerIndex ++, value); + setByte(writerIndex++, value); return this; } @@ -1042,22 +1042,12 @@ public abstract class AbstractByteBuf implements ByteBuf { @Override public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) { - if (fromIndex < toIndex) { - return forEachByteAsc(fromIndex, toIndex, processor); - } else if (fromIndex > toIndex) { - return forEachByteDesc(fromIndex, toIndex, processor); - } else { - checkIndex(fromIndex); - return -1; - } - } - - private int forEachByteAsc(int fromIndex, int toIndex, ByteBufProcessor processor) { - if (fromIndex < 0 || toIndex > capacity()) { + if (fromIndex < 0 || fromIndex > toIndex || toIndex > capacity()) { throw new IndexOutOfBoundsException(String.format( - "fromIndex: %d, toIndex: %d (expected: 0 <= fromIndex < toIndex <= capacity(%d))", + "fromIndex: %d, toIndex: %d (expected: 0 <= fromIndex <= toIndex <= capacity(%d))", fromIndex, toIndex, capacity())); } + return forEachByteAsc0(fromIndex, toIndex, processor); } @@ -1066,6 +1056,10 @@ public abstract class AbstractByteBuf implements ByteBuf { throw new NullPointerException("processor"); } + if (fromIndex == toIndex) { + return -1; + } + int i = fromIndex; try { do { @@ -1081,22 +1075,32 @@ public abstract class AbstractByteBuf implements ByteBuf { return -1; } - private int forEachByteDesc(int fromIndex, int toIndex, ByteBufProcessor processor) { - if (toIndex < -1 || fromIndex >= capacity()) { + @Override + public int forEachByteDesc(ByteBufProcessor processor) { + return forEachByteDesc0(readerIndex, writerIndex, processor); + } + + @Override + public int forEachByteDesc(int toIndex, int fromIndex, ByteBufProcessor processor) { + if (toIndex < 0 || toIndex > fromIndex || fromIndex > capacity()) { throw new IndexOutOfBoundsException(String.format( - "fromIndex: %d, toIndex: %d (expected: -1 <= toIndex < fromIndex < capacity(%d))", - fromIndex, toIndex, capacity())); + "toIndex: %d, fromIndex: %d (expected: 0 <= toIndex <= fromIndex <= capacity(%d))", + toIndex, fromIndex, capacity())); } + return forEachByteDesc0(toIndex, fromIndex, processor); + } + + private int forEachByteDesc0(int toIndex, int fromIndex, ByteBufProcessor processor) { if (processor == null) { throw new NullPointerException("processor"); } - int i = fromIndex; + int i = fromIndex - 1; try { do { i -= processor.process(this, i, _getByte(i)); - } while (i > toIndex); + } while (i >= toIndex); } catch (Signal signal) { signal.expect(ByteBufProcessor.ABORT); return i; diff --git a/buffer/src/main/java/io/netty/buffer/ByteBuf.java b/buffer/src/main/java/io/netty/buffer/ByteBuf.java index d220661cd3..1f548b42b1 100644 --- a/buffer/src/main/java/io/netty/buffer/ByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/ByteBuf.java @@ -1700,7 +1700,7 @@ public interface ByteBuf extends ReferenceCounted, Comparable { int bytesBefore(int index, int length, ByteBufIndexFinder indexFinder); /** - * Iterates over the readable bytes of this buffer with the specified {@code processor}. + * Iterates over the readable bytes of this buffer with the specified {@code processor} in ascending order. * * @return {@code -1} if the processor iterated to or beyond the end of the readable bytes. * If the {@code processor} raised {@link ByteBufProcessor#ABORT}, the last-visited index will be returned. @@ -1708,22 +1708,31 @@ public interface ByteBuf extends ReferenceCounted, Comparable { int forEachByte(ByteBufProcessor processor); /** - * Iterates over the specified area of this buffer with the specified {@code processor}. - * * * @return {@code -1} if the processor iterated to or beyond the end of the specified area. * If the {@code processor} raised {@link ByteBufProcessor#ABORT}, the last-visited index will be returned. */ int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor); + /** + * Iterates over the readable bytes of this buffer with the specified {@code processor} in descending order. + * + * @return {@code -1} if the processor iterated to or beyond the beginning of the readable bytes. + * If the {@code processor} raised {@link ByteBufProcessor#ABORT}, the last-visited index will be returned. + */ + int forEachByteDesc(ByteBufProcessor processor); + + /** + * Iterates over the specified area of this buffer with the specified {@code processor} in descending order. + * ({@code [toIndex, fromIndex)} i.e. {@code (fromIndex - 1)}, {@code (fromIndex - 2)}, ... {@code toIndex}) + * + * @return {@code -1} if the processor iterated to or beyond the beginning of the specified area. + * If the {@code processor} raised {@link ByteBufProcessor#ABORT}, the last-visited index will be returned. + */ + int forEachByteDesc(int toIndex, int fromIndex, ByteBufProcessor processor); + /** * 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. diff --git a/buffer/src/main/java/io/netty/buffer/DuplicatedByteBuf.java b/buffer/src/main/java/io/netty/buffer/DuplicatedByteBuf.java index 320c62192d..92e9f4172a 100644 --- a/buffer/src/main/java/io/netty/buffer/DuplicatedByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/DuplicatedByteBuf.java @@ -294,7 +294,12 @@ public class DuplicatedByteBuf extends AbstractDerivedByteBuf { @Override public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) { - return buffer.forEachByte(fromIndex, toIndex, processor); + return buffer.forEachByte(fromIndex, toIndex, new WrappedByteBufProcessor(this, processor)); + } + + @Override + public int forEachByteDesc(int toIndex, int fromIndex, ByteBufProcessor processor) { + return buffer.forEachByteDesc(toIndex, fromIndex, new WrappedByteBufProcessor(this, processor)); } } diff --git a/buffer/src/main/java/io/netty/buffer/EmptyByteBuf.java b/buffer/src/main/java/io/netty/buffer/EmptyByteBuf.java index 2ab14154ca..877f9a911b 100644 --- a/buffer/src/main/java/io/netty/buffer/EmptyByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/EmptyByteBuf.java @@ -719,7 +719,20 @@ public final class EmptyByteBuf implements ByteBuf { @Override public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) { - if (fromIndex != 0 && fromIndex != toIndex) { + if (fromIndex != 0 || fromIndex != toIndex) { + throw new IndexOutOfBoundsException(); + } + return -1; + } + + @Override + public int forEachByteDesc(ByteBufProcessor processor) { + return -1; + } + + @Override + public int forEachByteDesc(int toIndex, int fromIndex, ByteBufProcessor processor) { + if (toIndex != 0 || toIndex != fromIndex) { throw new IndexOutOfBoundsException(); } return -1; diff --git a/buffer/src/main/java/io/netty/buffer/ReadOnlyByteBuf.java b/buffer/src/main/java/io/netty/buffer/ReadOnlyByteBuf.java index 4479a74611..79d3f2331d 100644 --- a/buffer/src/main/java/io/netty/buffer/ReadOnlyByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/ReadOnlyByteBuf.java @@ -297,7 +297,12 @@ public class ReadOnlyByteBuf extends AbstractDerivedByteBuf { @Override public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) { - return buffer.forEachByte(fromIndex, toIndex, processor); + return buffer.forEachByte(fromIndex, toIndex, new WrappedByteBufProcessor(this, processor)); + } + + @Override + public int forEachByteDesc(int toIndex, int fromIndex, ByteBufProcessor processor) { + return buffer.forEachByteDesc(toIndex, fromIndex, new WrappedByteBufProcessor(this, processor)); } @Override diff --git a/buffer/src/main/java/io/netty/buffer/SlicedByteBuf.java b/buffer/src/main/java/io/netty/buffer/SlicedByteBuf.java index 11608fb6b5..b367022290 100644 --- a/buffer/src/main/java/io/netty/buffer/SlicedByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/SlicedByteBuf.java @@ -276,7 +276,19 @@ public class SlicedByteBuf extends AbstractDerivedByteBuf { @Override public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) { - int ret = buffer.forEachByte(fromIndex + adjustment, toIndex + adjustment, new SlicedByteBufProcessor(processor)); + int ret = buffer.forEachByte( + fromIndex + adjustment, toIndex + adjustment, new SlicedByteBufProcessor(processor)); + if (ret >= adjustment) { + return ret - adjustment; + } else { + return -1; + } + } + + @Override + public int forEachByteDesc(int toIndex, int fromIndex, ByteBufProcessor processor) { + int ret = buffer.forEachByteDesc( + toIndex + adjustment, fromIndex + adjustment, new SlicedByteBufProcessor(processor)); if (ret >= adjustment) { return ret - adjustment; } else { diff --git a/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java b/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java index 29e368fd94..dfb1794675 100644 --- a/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java @@ -721,12 +721,22 @@ public final class SwappedByteBuf implements ByteBuf { @Override public int forEachByte(ByteBufProcessor processor) { - return buf.forEachByte(new SwappedByteBufProcessor(processor)); + return buf.forEachByte(new WrappedByteBufProcessor(this, processor)); } @Override public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) { - return buf.forEachByte(fromIndex, toIndex, new SwappedByteBufProcessor(processor)); + return buf.forEachByte(fromIndex, toIndex, new WrappedByteBufProcessor(this, processor)); + } + + @Override + public int forEachByteDesc(ByteBufProcessor processor) { + return buf.forEachByteDesc(new WrappedByteBufProcessor(this, processor)); + } + + @Override + public int forEachByteDesc(int toIndex, int fromIndex, ByteBufProcessor processor) { + return buf.forEachByteDesc(toIndex, fromIndex, new WrappedByteBufProcessor(this, processor)); } @Override @@ -897,21 +907,4 @@ public final class SwappedByteBuf implements ByteBuf { return indexFinder.find(SwappedByteBuf.this, guessedIndex); } } - - private final class SwappedByteBufProcessor implements ByteBufProcessor { - - private final ByteBufProcessor processor; - - SwappedByteBufProcessor(ByteBufProcessor processor) { - if (processor == null) { - throw new NullPointerException("processor"); - } - this.processor = processor; - } - - @Override - public int process(ByteBuf buf, int index, byte value) throws Exception { - return processor.process(SwappedByteBuf.this, index, value); - } - } } diff --git a/buffer/src/main/java/io/netty/buffer/UnreleasableByteBuf.java b/buffer/src/main/java/io/netty/buffer/UnreleasableByteBuf.java index 0020967043..d4642f73e1 100644 --- a/buffer/src/main/java/io/netty/buffer/UnreleasableByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/UnreleasableByteBuf.java @@ -727,12 +727,22 @@ final class UnreleasableByteBuf implements ByteBuf { @Override public int forEachByte(ByteBufProcessor processor) { - return buf.forEachByte(processor); + return buf.forEachByte(new WrappedByteBufProcessor(this, processor)); } @Override public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) { - return buf.forEachByte(fromIndex, toIndex, processor); + return buf.forEachByte(fromIndex, toIndex, new WrappedByteBufProcessor(this, processor)); + } + + @Override + public int forEachByteDesc(ByteBufProcessor processor) { + return buf.forEachByteDesc(new WrappedByteBufProcessor(this, processor)); + } + + @Override + public int forEachByteDesc(int toIndex, int fromIndex, ByteBufProcessor processor) { + return buf.forEachByteDesc(toIndex, fromIndex, new WrappedByteBufProcessor(this, processor)); } @Override diff --git a/buffer/src/main/java/io/netty/buffer/WrappedByteBufProcessor.java b/buffer/src/main/java/io/netty/buffer/WrappedByteBufProcessor.java new file mode 100644 index 0000000000..7d129be210 --- /dev/null +++ b/buffer/src/main/java/io/netty/buffer/WrappedByteBufProcessor.java @@ -0,0 +1,35 @@ +/* + * Copyright 2013 The Netty Project + * + * The Netty Project 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 io.netty.buffer; + +final class WrappedByteBufProcessor implements ByteBufProcessor { + private final ByteBuf buffer; + private final ByteBufProcessor processor; + + WrappedByteBufProcessor(ByteBuf buffer, ByteBufProcessor processor) { + if (processor == null) { + throw new NullPointerException("processor"); + } + this.buffer = buffer; + this.processor = processor; + } + + @Override + public int process(ByteBuf buf, int index, byte value) throws Exception { + return processor.process(buffer, index, value); + } +} diff --git a/buffer/src/test/java/io/netty/buffer/AbstractByteBufTest.java b/buffer/src/test/java/io/netty/buffer/AbstractByteBufTest.java index 324eb513a1..c5e4c8d30d 100644 --- a/buffer/src/test/java/io/netty/buffer/AbstractByteBufTest.java +++ b/buffer/src/test/java/io/netty/buffer/AbstractByteBufTest.java @@ -1663,8 +1663,8 @@ public abstract class AbstractByteBufTest { @Override public int process(ByteBuf buf, int index, byte value) throws Exception { - assertThat(value, is((byte) (i + 1))); assertThat(index, is(i)); + assertThat(value, is((byte) (i + 1))); i ++; lastIndex.set(index); return 1; @@ -1687,9 +1687,9 @@ public abstract class AbstractByteBufTest { @Override public int process(ByteBuf buf, int index, byte value) throws Exception { - assertThat(value, is((byte) (i + 1))); assertThat(index, is(i)); - i ++; + assertThat(value, is((byte) (i + 1))); + i++; if (index == stop) { throw ABORT; @@ -1707,20 +1707,19 @@ public abstract class AbstractByteBufTest { } final AtomicInteger lastIndex = new AtomicInteger(); - buffer.setIndex(CAPACITY / 4, CAPACITY * 3 / 4); - assertThat(buffer.forEachByte(CAPACITY * 3 / 4, CAPACITY / 4, new ByteBufProcessor() { - int i = CAPACITY * 3 / 4; + assertThat(buffer.forEachByteDesc(CAPACITY / 4, CAPACITY * 3 / 4, new ByteBufProcessor() { + int i = CAPACITY * 3 / 4 - 1; @Override public int process(ByteBuf buf, int index, byte value) throws Exception { - assertThat(value, is((byte) (i + 1))); assertThat(index, is(i)); - i --; + assertThat(value, is((byte) (i + 1))); + i--; lastIndex.set(index); return 1; } }), is(-1)); - assertThat(lastIndex.get(), is(CAPACITY / 4 + 1)); + assertThat(lastIndex.get(), is(CAPACITY / 4)); } } diff --git a/buffer/src/test/java/io/netty/buffer/ByteBufProcessorTest.java b/buffer/src/test/java/io/netty/buffer/ByteBufProcessorTest.java index 9140bf71ac..e122267408 100644 --- a/buffer/src/test/java/io/netty/buffer/ByteBufProcessorTest.java +++ b/buffer/src/test/java/io/netty/buffer/ByteBufProcessorTest.java @@ -43,16 +43,16 @@ public class ByteBufProcessorTest { public void testBackward() { ByteBuf buf = Unpooled.copiedBuffer("abc\r\n\ndef\r\rghi\n\njkl\0\0mno \t\tx", CharsetUtil.ISO_8859_1); - assertEquals(27, buf.forEachByte(buf.capacity() - 1, -1, ByteBufProcessor.FIND_LINEAR_WHITESPACE)); - assertEquals(23, buf.forEachByte(27, -1, ByteBufProcessor.FIND_NON_LINEAR_WHITESPACE)); - assertEquals(20, buf.forEachByte(23, -1, ByteBufProcessor.FIND_NUL)); - assertEquals(18, buf.forEachByte(20, -1, ByteBufProcessor.FIND_NON_NUL)); - assertEquals(15, buf.forEachByte(18, -1, ByteBufProcessor.FIND_LF)); - assertEquals(13, buf.forEachByte(15, -1, ByteBufProcessor.FIND_NON_LF)); - assertEquals(10, buf.forEachByte(13, -1, ByteBufProcessor.FIND_CR)); - assertEquals(8, buf.forEachByte(10, -1, ByteBufProcessor.FIND_NON_CR)); - assertEquals(5, buf.forEachByte(8, -1, ByteBufProcessor.FIND_CRLF)); - assertEquals(2, buf.forEachByte(5, -1, ByteBufProcessor.FIND_NON_CRLF)); - assertEquals(-1, buf.forEachByte(2, -1, ByteBufProcessor.FIND_CRLF)); + assertEquals(27, buf.forEachByteDesc(0, buf.writerIndex(), ByteBufProcessor.FIND_LINEAR_WHITESPACE)); + assertEquals(23, buf.forEachByteDesc(0, 28, ByteBufProcessor.FIND_NON_LINEAR_WHITESPACE)); + assertEquals(20, buf.forEachByteDesc(0, 24, ByteBufProcessor.FIND_NUL)); + assertEquals(18, buf.forEachByteDesc(0, 21, ByteBufProcessor.FIND_NON_NUL)); + assertEquals(15, buf.forEachByteDesc(0, 19, ByteBufProcessor.FIND_LF)); + assertEquals(13, buf.forEachByteDesc(0, 16, ByteBufProcessor.FIND_NON_LF)); + assertEquals(10, buf.forEachByteDesc(0, 14, ByteBufProcessor.FIND_CR)); + assertEquals(8, buf.forEachByteDesc(0, 11, ByteBufProcessor.FIND_NON_CR)); + assertEquals(5, buf.forEachByteDesc(0, 9, ByteBufProcessor.FIND_CRLF)); + assertEquals(2, buf.forEachByteDesc(0, 6, ByteBufProcessor.FIND_NON_CRLF)); + assertEquals(-1, buf.forEachByteDesc(0, 3, ByteBufProcessor.FIND_CRLF)); } } diff --git a/codec/src/main/java/io/netty/handler/codec/ReplayingDecoderBuffer.java b/codec/src/main/java/io/netty/handler/codec/ReplayingDecoderBuffer.java index 6c17df011e..e31f5c638c 100644 --- a/codec/src/main/java/io/netty/handler/codec/ReplayingDecoderBuffer.java +++ b/codec/src/main/java/io/netty/handler/codec/ReplayingDecoderBuffer.java @@ -378,7 +378,7 @@ final class ReplayingDecoderBuffer implements ByteBuf { @Override public int forEachByte(ByteBufProcessor processor) { int ret = buffer.forEachByte(processor); - if (ret < 0) { + if (!terminated && ret < 0) { throw REPLAY; } else { return ret; @@ -387,21 +387,6 @@ final class ReplayingDecoderBuffer implements ByteBuf { @Override public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) { - if (fromIndex < toIndex) { - return forEachByteAsc(fromIndex, toIndex, processor); - } else if (fromIndex > toIndex) { - return forEachByteDesc(fromIndex, toIndex, processor); - } else { - checkIndex(fromIndex, 0); - return -1; - } - } - - private int forEachByteAsc(int fromIndex, int toIndex, ByteBufProcessor processor) { - if (fromIndex < 0) { - throw new IndexOutOfBoundsException("fromIndex: " + fromIndex); - } - final int writerIndex = buffer.writerIndex(); if (fromIndex >= writerIndex) { throw REPLAY; @@ -419,16 +404,22 @@ final class ReplayingDecoderBuffer implements ByteBuf { } } - private int forEachByteDesc(int fromIndex, int toIndex, ByteBufProcessor processor) { - if (toIndex < -1) { - throw new IndexOutOfBoundsException("toIndex: " + toIndex); + @Override + public int forEachByteDesc(ByteBufProcessor processor) { + if (terminated) { + return buffer.forEachByteDesc(processor); + } else { + throw new UnreplayableOperationException(); } + } - if (fromIndex >= buffer.writerIndex()) { + @Override + public int forEachByteDesc(int toIndex, int fromIndex, ByteBufProcessor processor) { + if (fromIndex > buffer.writerIndex()) { throw REPLAY; } - return buffer.forEachByte(fromIndex, toIndex, processor); + return buffer.forEachByteDesc(toIndex, fromIndex, processor); } @Override