Split ByteBuf.forEachByte() into forEachByte() and forEachByteDesc()

- Related: #1378
- As suggested by @liqweed
This commit is contained in:
Trustin Lee 2013-06-27 18:48:09 +09:00
parent 9804741fb3
commit ac39cad5ff
12 changed files with 172 additions and 96 deletions

View File

@ -767,7 +767,7 @@ public abstract class AbstractByteBuf implements ByteBuf {
@Override @Override
public ByteBuf writeByte(int value) { public ByteBuf writeByte(int value) {
ensureWritable(1); ensureWritable(1);
setByte(writerIndex ++, value); setByte(writerIndex++, value);
return this; return this;
} }
@ -1042,22 +1042,12 @@ public abstract class AbstractByteBuf implements ByteBuf {
@Override @Override
public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) { public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) {
if (fromIndex < toIndex) { if (fromIndex < 0 || fromIndex > toIndex || toIndex > capacity()) {
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()) {
throw new IndexOutOfBoundsException(String.format( 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())); fromIndex, toIndex, capacity()));
} }
return forEachByteAsc0(fromIndex, toIndex, processor); return forEachByteAsc0(fromIndex, toIndex, processor);
} }
@ -1066,6 +1056,10 @@ public abstract class AbstractByteBuf implements ByteBuf {
throw new NullPointerException("processor"); throw new NullPointerException("processor");
} }
if (fromIndex == toIndex) {
return -1;
}
int i = fromIndex; int i = fromIndex;
try { try {
do { do {
@ -1081,22 +1075,32 @@ public abstract class AbstractByteBuf implements ByteBuf {
return -1; return -1;
} }
private int forEachByteDesc(int fromIndex, int toIndex, ByteBufProcessor processor) { @Override
if (toIndex < -1 || fromIndex >= capacity()) { 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( throw new IndexOutOfBoundsException(String.format(
"fromIndex: %d, toIndex: %d (expected: -1 <= toIndex < fromIndex < capacity(%d))", "toIndex: %d, fromIndex: %d (expected: 0 <= toIndex <= fromIndex <= capacity(%d))",
fromIndex, toIndex, capacity())); toIndex, fromIndex, capacity()));
} }
return forEachByteDesc0(toIndex, fromIndex, processor);
}
private int forEachByteDesc0(int toIndex, int fromIndex, ByteBufProcessor processor) {
if (processor == null) { if (processor == null) {
throw new NullPointerException("processor"); throw new NullPointerException("processor");
} }
int i = fromIndex; int i = fromIndex - 1;
try { try {
do { do {
i -= processor.process(this, i, _getByte(i)); i -= processor.process(this, i, _getByte(i));
} while (i > toIndex); } while (i >= toIndex);
} catch (Signal signal) { } catch (Signal signal) {
signal.expect(ByteBufProcessor.ABORT); signal.expect(ByteBufProcessor.ABORT);
return i; return i;

View File

@ -1700,7 +1700,7 @@ public interface ByteBuf extends ReferenceCounted, Comparable<ByteBuf> {
int bytesBefore(int index, int length, ByteBufIndexFinder indexFinder); 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. * @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. * 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<ByteBuf> {
int forEachByte(ByteBufProcessor processor); int forEachByte(ByteBufProcessor processor);
/** /**
* Iterates over the specified area of this buffer with the specified {@code processor}. * Iterates over the specified area of this buffer with the specified {@code processor} in ascending order.
* <ul>
* <li>If {@code fromIndex} is less than {@code toIndex}, the iteration is performed in an ascending order.
* ({@code [fromIndex, fromIndex&#41} i.e. {@code fromIndex}, {@code (fromIndex + 1)}, .. {@code (toIndex - 1)}) * ({@code [fromIndex, fromIndex&#41} i.e. {@code fromIndex}, {@code (fromIndex + 1)}, .. {@code (toIndex - 1)})
* </li>
* <li>If {@code fromIndex} is greater than {@code toIndex}, the iteration is performed in a descending order.
* ({@code [toIndex, fromIndex&#41} i.e. {@code (fromIndex)}, {@code (fromIndex - 1)}, ... {@code toIndex + 1})
* </li>
* <li>If {@code fromIndex} is equal to {@code toIndex}, {@code -1} is returned immediately.</li>
* </ul>
* *
* @return {@code -1} if the processor iterated to or beyond the end of the specified area. * @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. * If the {@code processor} raised {@link ByteBufProcessor#ABORT}, the last-visited index will be returned.
*/ */
int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor); 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&#41} 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 * 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. * of the returned buffer or this buffer does not affect each other at all.

View File

@ -294,7 +294,12 @@ public class DuplicatedByteBuf extends AbstractDerivedByteBuf {
@Override @Override
public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) { 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));
} }
} }

View File

@ -719,7 +719,20 @@ public final class EmptyByteBuf implements ByteBuf {
@Override @Override
public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) { 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(); throw new IndexOutOfBoundsException();
} }
return -1; return -1;

View File

@ -297,7 +297,12 @@ public class ReadOnlyByteBuf extends AbstractDerivedByteBuf {
@Override @Override
public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) { 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 @Override

View File

@ -276,7 +276,19 @@ public class SlicedByteBuf extends AbstractDerivedByteBuf {
@Override @Override
public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) { 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) { if (ret >= adjustment) {
return ret - adjustment; return ret - adjustment;
} else { } else {

View File

@ -721,12 +721,22 @@ public final class SwappedByteBuf implements ByteBuf {
@Override @Override
public int forEachByte(ByteBufProcessor processor) { public int forEachByte(ByteBufProcessor processor) {
return buf.forEachByte(new SwappedByteBufProcessor(processor)); return buf.forEachByte(new WrappedByteBufProcessor(this, processor));
} }
@Override @Override
public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) { 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 @Override
@ -897,21 +907,4 @@ public final class SwappedByteBuf implements ByteBuf {
return indexFinder.find(SwappedByteBuf.this, guessedIndex); 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);
}
}
} }

View File

@ -727,12 +727,22 @@ final class UnreleasableByteBuf implements ByteBuf {
@Override @Override
public int forEachByte(ByteBufProcessor processor) { public int forEachByte(ByteBufProcessor processor) {
return buf.forEachByte(processor); return buf.forEachByte(new WrappedByteBufProcessor(this, processor));
} }
@Override @Override
public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) { 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 @Override

View File

@ -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);
}
}

View File

@ -1663,8 +1663,8 @@ public abstract class AbstractByteBufTest {
@Override @Override
public int process(ByteBuf buf, int index, byte value) throws Exception { public int process(ByteBuf buf, int index, byte value) throws Exception {
assertThat(value, is((byte) (i + 1)));
assertThat(index, is(i)); assertThat(index, is(i));
assertThat(value, is((byte) (i + 1)));
i ++; i ++;
lastIndex.set(index); lastIndex.set(index);
return 1; return 1;
@ -1687,9 +1687,9 @@ public abstract class AbstractByteBufTest {
@Override @Override
public int process(ByteBuf buf, int index, byte value) throws Exception { public int process(ByteBuf buf, int index, byte value) throws Exception {
assertThat(value, is((byte) (i + 1)));
assertThat(index, is(i)); assertThat(index, is(i));
i ++; assertThat(value, is((byte) (i + 1)));
i++;
if (index == stop) { if (index == stop) {
throw ABORT; throw ABORT;
@ -1707,20 +1707,19 @@ public abstract class AbstractByteBufTest {
} }
final AtomicInteger lastIndex = new AtomicInteger(); final AtomicInteger lastIndex = new AtomicInteger();
buffer.setIndex(CAPACITY / 4, CAPACITY * 3 / 4); assertThat(buffer.forEachByteDesc(CAPACITY / 4, CAPACITY * 3 / 4, new ByteBufProcessor() {
assertThat(buffer.forEachByte(CAPACITY * 3 / 4, CAPACITY / 4, new ByteBufProcessor() { int i = CAPACITY * 3 / 4 - 1;
int i = CAPACITY * 3 / 4;
@Override @Override
public int process(ByteBuf buf, int index, byte value) throws Exception { public int process(ByteBuf buf, int index, byte value) throws Exception {
assertThat(value, is((byte) (i + 1)));
assertThat(index, is(i)); assertThat(index, is(i));
i --; assertThat(value, is((byte) (i + 1)));
i--;
lastIndex.set(index); lastIndex.set(index);
return 1; return 1;
} }
}), is(-1)); }), is(-1));
assertThat(lastIndex.get(), is(CAPACITY / 4 + 1)); assertThat(lastIndex.get(), is(CAPACITY / 4));
} }
} }

View File

@ -43,16 +43,16 @@ public class ByteBufProcessorTest {
public void testBackward() { public void testBackward() {
ByteBuf buf = Unpooled.copiedBuffer("abc\r\n\ndef\r\rghi\n\njkl\0\0mno \t\tx", CharsetUtil.ISO_8859_1); 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(27, buf.forEachByteDesc(0, buf.writerIndex(), ByteBufProcessor.FIND_LINEAR_WHITESPACE));
assertEquals(23, buf.forEachByte(27, -1, ByteBufProcessor.FIND_NON_LINEAR_WHITESPACE)); assertEquals(23, buf.forEachByteDesc(0, 28, ByteBufProcessor.FIND_NON_LINEAR_WHITESPACE));
assertEquals(20, buf.forEachByte(23, -1, ByteBufProcessor.FIND_NUL)); assertEquals(20, buf.forEachByteDesc(0, 24, ByteBufProcessor.FIND_NUL));
assertEquals(18, buf.forEachByte(20, -1, ByteBufProcessor.FIND_NON_NUL)); assertEquals(18, buf.forEachByteDesc(0, 21, ByteBufProcessor.FIND_NON_NUL));
assertEquals(15, buf.forEachByte(18, -1, ByteBufProcessor.FIND_LF)); assertEquals(15, buf.forEachByteDesc(0, 19, ByteBufProcessor.FIND_LF));
assertEquals(13, buf.forEachByte(15, -1, ByteBufProcessor.FIND_NON_LF)); assertEquals(13, buf.forEachByteDesc(0, 16, ByteBufProcessor.FIND_NON_LF));
assertEquals(10, buf.forEachByte(13, -1, ByteBufProcessor.FIND_CR)); assertEquals(10, buf.forEachByteDesc(0, 14, ByteBufProcessor.FIND_CR));
assertEquals(8, buf.forEachByte(10, -1, ByteBufProcessor.FIND_NON_CR)); assertEquals(8, buf.forEachByteDesc(0, 11, ByteBufProcessor.FIND_NON_CR));
assertEquals(5, buf.forEachByte(8, -1, ByteBufProcessor.FIND_CRLF)); assertEquals(5, buf.forEachByteDesc(0, 9, ByteBufProcessor.FIND_CRLF));
assertEquals(2, buf.forEachByte(5, -1, ByteBufProcessor.FIND_NON_CRLF)); assertEquals(2, buf.forEachByteDesc(0, 6, ByteBufProcessor.FIND_NON_CRLF));
assertEquals(-1, buf.forEachByte(2, -1, ByteBufProcessor.FIND_CRLF)); assertEquals(-1, buf.forEachByteDesc(0, 3, ByteBufProcessor.FIND_CRLF));
} }
} }

View File

@ -378,7 +378,7 @@ final class ReplayingDecoderBuffer implements ByteBuf {
@Override @Override
public int forEachByte(ByteBufProcessor processor) { public int forEachByte(ByteBufProcessor processor) {
int ret = buffer.forEachByte(processor); int ret = buffer.forEachByte(processor);
if (ret < 0) { if (!terminated && ret < 0) {
throw REPLAY; throw REPLAY;
} else { } else {
return ret; return ret;
@ -387,21 +387,6 @@ final class ReplayingDecoderBuffer implements ByteBuf {
@Override @Override
public int forEachByte(int fromIndex, int toIndex, ByteBufProcessor processor) { 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(); final int writerIndex = buffer.writerIndex();
if (fromIndex >= writerIndex) { if (fromIndex >= writerIndex) {
throw REPLAY; throw REPLAY;
@ -419,16 +404,22 @@ final class ReplayingDecoderBuffer implements ByteBuf {
} }
} }
private int forEachByteDesc(int fromIndex, int toIndex, ByteBufProcessor processor) { @Override
if (toIndex < -1) { public int forEachByteDesc(ByteBufProcessor processor) {
throw new IndexOutOfBoundsException("toIndex: " + toIndex); 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; throw REPLAY;
} }
return buffer.forEachByte(fromIndex, toIndex, processor); return buffer.forEachByteDesc(toIndex, fromIndex, processor);
} }
@Override @Override