Revert "ByteProcessor shouldn't throw checked exception"
This reverts commit b70d0fa6e3
.
This commit is contained in:
parent
b70d0fa6e3
commit
ff2e790e89
@ -1262,37 +1262,58 @@ public abstract class AbstractByteBuf extends ByteBuf {
|
|||||||
@Override
|
@Override
|
||||||
public int forEachByte(ByteProcessor processor) {
|
public int forEachByte(ByteProcessor processor) {
|
||||||
ensureAccessible();
|
ensureAccessible();
|
||||||
|
try {
|
||||||
return forEachByteAsc0(readerIndex, writerIndex, processor);
|
return forEachByteAsc0(readerIndex, writerIndex, processor);
|
||||||
|
} catch (Exception e) {
|
||||||
|
PlatformDependent.throwException(e);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int forEachByte(int index, int length, ByteProcessor processor) {
|
public int forEachByte(int index, int length, ByteProcessor processor) {
|
||||||
checkIndex(index, length);
|
checkIndex(index, length);
|
||||||
|
try {
|
||||||
return forEachByteAsc0(index, index + length, processor);
|
return forEachByteAsc0(index, index + length, processor);
|
||||||
|
} catch (Exception e) {
|
||||||
|
PlatformDependent.throwException(e);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int forEachByteAsc0(int start, int end, ByteProcessor processor) {
|
int forEachByteAsc0(int start, int end, ByteProcessor processor) throws Exception {
|
||||||
for (; start < end; ++start) {
|
for (; start < end; ++start) {
|
||||||
if (!processor.process(_getByte(start))) {
|
if (!processor.process(_getByte(start))) {
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int forEachByteDesc(ByteProcessor processor) {
|
public int forEachByteDesc(ByteProcessor processor) {
|
||||||
ensureAccessible();
|
ensureAccessible();
|
||||||
|
try {
|
||||||
return forEachByteDesc0(writerIndex - 1, readerIndex, processor);
|
return forEachByteDesc0(writerIndex - 1, readerIndex, processor);
|
||||||
|
} catch (Exception e) {
|
||||||
|
PlatformDependent.throwException(e);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int forEachByteDesc(int index, int length, ByteProcessor processor) {
|
public int forEachByteDesc(int index, int length, ByteProcessor processor) {
|
||||||
checkIndex(index, length);
|
checkIndex(index, length);
|
||||||
|
try {
|
||||||
return forEachByteDesc0(index + length - 1, index, processor);
|
return forEachByteDesc0(index + length - 1, index, processor);
|
||||||
|
} catch (Exception e) {
|
||||||
|
PlatformDependent.throwException(e);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int forEachByteDesc0(int rStart, final int rEnd, ByteProcessor processor) {
|
int forEachByteDesc0(int rStart, final int rEnd, ByteProcessor processor) throws Exception {
|
||||||
for (; rStart >= rEnd; --rStart) {
|
for (; rStart >= rEnd; --rStart) {
|
||||||
if (!processor.process(_getByte(rStart))) {
|
if (!processor.process(_getByte(rStart))) {
|
||||||
return rStart;
|
return rStart;
|
||||||
|
@ -660,7 +660,7 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int forEachByteAsc0(int start, int end, ByteProcessor processor) {
|
protected int forEachByteAsc0(int start, int end, ByteProcessor processor) throws Exception {
|
||||||
if (end <= start) {
|
if (end <= start) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -686,7 +686,7 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int forEachByteDesc0(int rStart, int rEnd, ByteProcessor processor) {
|
protected int forEachByteDesc0(int rStart, int rEnd, ByteProcessor processor) throws Exception {
|
||||||
if (rEnd > rStart) { // rStart *and* rEnd are inclusive
|
if (rEnd > rStart) { // rStart *and* rEnd are inclusive
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -2284,7 +2284,7 @@ public abstract class AbstractByteBufTest {
|
|||||||
int i = CAPACITY / 4;
|
int i = CAPACITY / 4;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte value) {
|
public boolean process(byte value) throws Exception {
|
||||||
assertThat(value, is((byte) (i + 1)));
|
assertThat(value, is((byte) (i + 1)));
|
||||||
lastIndex.set(i);
|
lastIndex.set(i);
|
||||||
i ++;
|
i ++;
|
||||||
@ -2307,7 +2307,7 @@ public abstract class AbstractByteBufTest {
|
|||||||
int i = CAPACITY / 3;
|
int i = CAPACITY / 3;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte value) {
|
public boolean process(byte value) throws Exception {
|
||||||
assertThat(value, is((byte) (i + 1)));
|
assertThat(value, is((byte) (i + 1)));
|
||||||
if (i == stop) {
|
if (i == stop) {
|
||||||
return false;
|
return false;
|
||||||
@ -4608,7 +4608,7 @@ public abstract class AbstractByteBufTest {
|
|||||||
private int index = bytes.length - 1;
|
private int index = bytes.length - 1;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte value) {
|
public boolean process(byte value) throws Exception {
|
||||||
bytes[index--] = value;
|
bytes[index--] = value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -4631,7 +4631,7 @@ public abstract class AbstractByteBufTest {
|
|||||||
private int index;
|
private int index;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte value) {
|
public boolean process(byte value) throws Exception {
|
||||||
bytes[index++] = value;
|
bytes[index++] = value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -4804,7 +4804,7 @@ public abstract class AbstractByteBufTest {
|
|||||||
|
|
||||||
private static final class TestByteProcessor implements ByteProcessor {
|
private static final class TestByteProcessor implements ByteProcessor {
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte value) {
|
public boolean process(byte value) throws Exception {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import io.netty.handler.codec.HeadersUtils;
|
|||||||
import io.netty.handler.codec.ValueConverter;
|
import io.netty.handler.codec.ValueConverter;
|
||||||
import io.netty.util.AsciiString;
|
import io.netty.util.AsciiString;
|
||||||
import io.netty.util.ByteProcessor;
|
import io.netty.util.ByteProcessor;
|
||||||
|
import io.netty.util.internal.PlatformDependent;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
@ -49,10 +50,14 @@ public class DefaultHttpHeaders extends HttpHeaders {
|
|||||||
};
|
};
|
||||||
static final NameValidator<CharSequence> HttpNameValidator = name -> {
|
static final NameValidator<CharSequence> HttpNameValidator = name -> {
|
||||||
if (name == null || name.length() == 0) {
|
if (name == null || name.length() == 0) {
|
||||||
throw new IllegalArgumentException("empty headers are not allowed [" + name + ']');
|
throw new IllegalArgumentException("empty headers are not allowed [" + name + "]");
|
||||||
}
|
}
|
||||||
if (name instanceof AsciiString) {
|
if (name instanceof AsciiString) {
|
||||||
|
try {
|
||||||
((AsciiString) name).forEachByte(HEADER_NAME_VALIDATOR);
|
((AsciiString) name).forEachByte(HEADER_NAME_VALIDATOR);
|
||||||
|
} catch (Exception e) {
|
||||||
|
PlatformDependent.throwException(e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Go through each character in the name
|
// Go through each character in the name
|
||||||
for (int index = 0; index < name.length(); ++index) {
|
for (int index = 0; index < name.length(); ++index) {
|
||||||
@ -68,7 +73,7 @@ public class DefaultHttpHeaders extends HttpHeaders {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>Warning!</b> Setting {@code validate} to {@code false} will mean that Netty won't
|
* <b>Warning!</b> Setting <code>validate</code> to <code>false</code> will mean that Netty won't
|
||||||
* validate & protect against user-supplied header values that are malicious.
|
* validate & protect against user-supplied header values that are malicious.
|
||||||
* This can leave your server implementation vulnerable to
|
* This can leave your server implementation vulnerable to
|
||||||
* <a href="https://cwe.mitre.org/data/definitions/113.html">
|
* <a href="https://cwe.mitre.org/data/definitions/113.html">
|
||||||
|
@ -936,7 +936,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte value) {
|
public boolean process(byte value) throws Exception {
|
||||||
char nextByte = (char) (value & 0xFF);
|
char nextByte = (char) (value & 0xFF);
|
||||||
if (nextByte == HttpConstants.LF) {
|
if (nextByte == HttpConstants.LF) {
|
||||||
int len = seq.length();
|
int len = seq.length();
|
||||||
@ -983,7 +983,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte value) {
|
public boolean process(byte value) throws Exception {
|
||||||
if (currentState == State.SKIP_CONTROL_CHARS) {
|
if (currentState == State.SKIP_CONTROL_CHARS) {
|
||||||
char c = (char) (value & 0xFF);
|
char c = (char) (value & 0xFF);
|
||||||
if (Character.isISOControl(c) || Character.isWhitespace(c)) {
|
if (Character.isISOControl(c) || Character.isWhitespace(c)) {
|
||||||
|
@ -706,7 +706,7 @@ public class HttpPostStandardRequestDecoder implements InterfaceHttpPostRequestD
|
|||||||
|
|
||||||
private static final class UrlEncodedDetector implements ByteProcessor {
|
private static final class UrlEncodedDetector implements ByteProcessor {
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte value) {
|
public boolean process(byte value) throws Exception {
|
||||||
return value != '%' && value != '+';
|
return value != '%' && value != '+';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ final class Utf8Validator implements ByteProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte b) {
|
public boolean process(byte b) throws Exception {
|
||||||
byte type = TYPES[b & 0xFF];
|
byte type = TYPES[b & 0xFF];
|
||||||
|
|
||||||
codep = state != UTF8_ACCEPT ? b & 0x3f | codep << 6 : 0xff >> type & b;
|
codep = state != UTF8_ACCEPT ? b & 0x3f | codep << 6 : 0xff >> type & b;
|
||||||
|
@ -38,7 +38,18 @@ public class DefaultHttp2Headers
|
|||||||
"empty headers are not allowed [%s]", name));
|
"empty headers are not allowed [%s]", name));
|
||||||
}
|
}
|
||||||
if (name instanceof AsciiString) {
|
if (name instanceof AsciiString) {
|
||||||
int index = ((AsciiString) name).forEachByte(HTTP2_NAME_VALIDATOR_PROCESSOR);
|
final int index;
|
||||||
|
try {
|
||||||
|
index = ((AsciiString) name).forEachByte(HTTP2_NAME_VALIDATOR_PROCESSOR);
|
||||||
|
} catch (Http2Exception e) {
|
||||||
|
PlatformDependent.throwException(e);
|
||||||
|
return;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
PlatformDependent.throwException(connectionError(PROTOCOL_ERROR, t,
|
||||||
|
"unexpected error. invalid header name [%s]", name));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
PlatformDependent.throwException(connectionError(PROTOCOL_ERROR,
|
PlatformDependent.throwException(connectionError(PROTOCOL_ERROR,
|
||||||
"invalid header name [%s]", name));
|
"invalid header name [%s]", name));
|
||||||
@ -98,7 +109,7 @@ public class DefaultHttp2Headers
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Http2Headers clear() {
|
public Http2Headers clear() {
|
||||||
firstNonPseudo = head;
|
this.firstNonPseudo = head;
|
||||||
return super.clear();
|
return super.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,9 +70,11 @@ final class HpackHuffmanEncoder {
|
|||||||
requireNonNull(out, "out");
|
requireNonNull(out, "out");
|
||||||
if (data instanceof AsciiString) {
|
if (data instanceof AsciiString) {
|
||||||
AsciiString string = (AsciiString) data;
|
AsciiString string = (AsciiString) data;
|
||||||
encodeProcessor.out = out;
|
|
||||||
try {
|
try {
|
||||||
|
encodeProcessor.out = out;
|
||||||
string.forEachByte(encodeProcessor);
|
string.forEachByte(encodeProcessor);
|
||||||
|
} catch (Exception e) {
|
||||||
|
PlatformDependent.throwException(e);
|
||||||
} finally {
|
} finally {
|
||||||
encodeProcessor.end();
|
encodeProcessor.end();
|
||||||
}
|
}
|
||||||
@ -116,9 +118,14 @@ final class HpackHuffmanEncoder {
|
|||||||
int getEncodedLength(CharSequence data) {
|
int getEncodedLength(CharSequence data) {
|
||||||
if (data instanceof AsciiString) {
|
if (data instanceof AsciiString) {
|
||||||
AsciiString string = (AsciiString) data;
|
AsciiString string = (AsciiString) data;
|
||||||
|
try {
|
||||||
encodedLengthProcessor.reset();
|
encodedLengthProcessor.reset();
|
||||||
string.forEachByte(encodedLengthProcessor);
|
string.forEachByte(encodedLengthProcessor);
|
||||||
return encodedLengthProcessor.length();
|
return encodedLengthProcessor.length();
|
||||||
|
} catch (Exception e) {
|
||||||
|
PlatformDependent.throwException(e);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return getEncodedLengthSlowPath(data);
|
return getEncodedLengthSlowPath(data);
|
||||||
}
|
}
|
||||||
|
@ -427,6 +427,7 @@ public final class HttpConversionUtil {
|
|||||||
|
|
||||||
while (valuesIter.hasNext()) {
|
while (valuesIter.hasNext()) {
|
||||||
AsciiString lowerCased = AsciiString.of(valuesIter.next()).toLowerCase();
|
AsciiString lowerCased = AsciiString.of(valuesIter.next()).toLowerCase();
|
||||||
|
try {
|
||||||
int index = lowerCased.forEachByte(FIND_COMMA);
|
int index = lowerCased.forEachByte(FIND_COMMA);
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
int start = 0;
|
int start = 0;
|
||||||
@ -439,6 +440,11 @@ public final class HttpConversionUtil {
|
|||||||
} else {
|
} else {
|
||||||
result.add(lowerCased.trim(), EMPTY_STRING);
|
result.add(lowerCased.trim(), EMPTY_STRING);
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// This is not expect to happen because FIND_COMMA never throws but must be caught
|
||||||
|
// because of the ByteProcessor interface.
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -483,6 +489,7 @@ public final class HttpConversionUtil {
|
|||||||
AsciiString value = AsciiString.of(entry.getValue());
|
AsciiString value = AsciiString.of(entry.getValue());
|
||||||
// split up cookies to allow for better compression
|
// split up cookies to allow for better compression
|
||||||
// https://tools.ietf.org/html/rfc7540#section-8.1.2.5
|
// https://tools.ietf.org/html/rfc7540#section-8.1.2.5
|
||||||
|
try {
|
||||||
int index = value.forEachByte(FIND_SEMI_COLON);
|
int index = value.forEachByte(FIND_SEMI_COLON);
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
int start = 0;
|
int start = 0;
|
||||||
@ -499,6 +506,11 @@ public final class HttpConversionUtil {
|
|||||||
} else {
|
} else {
|
||||||
out.add(COOKIE, value);
|
out.add(COOKIE, value);
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// This is not expect to happen because FIND_SEMI_COLON never throws but must be caught
|
||||||
|
// because of the ByteProcessor interface.
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
out.add(aName, entry.getValue());
|
out.add(aName, entry.getValue());
|
||||||
}
|
}
|
||||||
|
@ -311,7 +311,7 @@ public final class RedisDecoder extends ByteToMessageDecoder {
|
|||||||
private long result;
|
private long result;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte value) {
|
public boolean process(byte value) throws Exception {
|
||||||
if (value < '0' || value > '9') {
|
if (value < '0' || value > '9') {
|
||||||
throw new RedisCodecException("bad byte in number: " + value);
|
throw new RedisCodecException("bad byte in number: " + value);
|
||||||
}
|
}
|
||||||
|
@ -274,7 +274,7 @@ public class StompSubframeDecoder extends ReplayingDecoder<State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte nextByte) {
|
public boolean process(byte nextByte) throws Exception {
|
||||||
if (nextByte == StompConstants.CR) {
|
if (nextByte == StompConstants.CR) {
|
||||||
++lineLength;
|
++lineLength;
|
||||||
return true;
|
return true;
|
||||||
@ -353,7 +353,7 @@ public class StompSubframeDecoder extends ReplayingDecoder<State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte nextByte) {
|
public boolean process(byte nextByte) throws Exception {
|
||||||
if (nextByte == StompConstants.COLON) {
|
if (nextByte == StompConstants.COLON) {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
AppendableCharSequence charSeq = charSequence();
|
AppendableCharSequence charSeq = charSequence();
|
||||||
|
@ -331,7 +331,7 @@ public final class Base64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte value) {
|
public boolean process(byte value) throws Exception {
|
||||||
if (value > 0) {
|
if (value > 0) {
|
||||||
byte sbiDecode = decodabet[value];
|
byte sbiDecode = decodabet[value];
|
||||||
if (sbiDecode >= WHITE_SPACE_ENC) { // White space, Equals sign or better
|
if (sbiDecode >= WHITE_SPACE_ENC) { // White space, Equals sign or better
|
||||||
|
@ -255,7 +255,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
|||||||
* @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.
|
||||||
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
|
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
|
||||||
*/
|
*/
|
||||||
public int forEachByte(ByteProcessor visitor) {
|
public int forEachByte(ByteProcessor visitor) throws Exception {
|
||||||
return forEachByte0(0, length(), visitor);
|
return forEachByte0(0, length(), visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,7 +266,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
|||||||
* @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.
|
||||||
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
|
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
|
||||||
*/
|
*/
|
||||||
public int forEachByte(int index, int length, ByteProcessor visitor) {
|
public int forEachByte(int index, int length, ByteProcessor visitor) throws Exception {
|
||||||
if (isOutOfBounds(index, length, length())) {
|
if (isOutOfBounds(index, length, length())) {
|
||||||
throw new IndexOutOfBoundsException("expected: " + "0 <= index(" + index + ") <= start + length(" + length
|
throw new IndexOutOfBoundsException("expected: " + "0 <= index(" + index + ") <= start + length(" + length
|
||||||
+ ") <= " + "length(" + length() + ')');
|
+ ") <= " + "length(" + length() + ')');
|
||||||
@ -274,7 +274,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
|||||||
return forEachByte0(index, length, visitor);
|
return forEachByte0(index, length, visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int forEachByte0(int index, int length, ByteProcessor visitor) {
|
private int forEachByte0(int index, int length, ByteProcessor visitor) throws Exception {
|
||||||
final int len = offset + index + length;
|
final int len = offset + index + length;
|
||||||
for (int i = offset + index; i < len; ++i) {
|
for (int i = offset + index; i < len; ++i) {
|
||||||
if (!visitor.process(value[i])) {
|
if (!visitor.process(value[i])) {
|
||||||
@ -290,7 +290,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
|||||||
* @return {@code -1} if the processor iterated to or beyond the beginning of the readable bytes.
|
* @return {@code -1} if the processor iterated to or beyond the beginning of the readable bytes.
|
||||||
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
|
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
|
||||||
*/
|
*/
|
||||||
public int forEachByteDesc(ByteProcessor visitor) {
|
public int forEachByteDesc(ByteProcessor visitor) throws Exception {
|
||||||
return forEachByteDesc0(0, length(), visitor);
|
return forEachByteDesc0(0, length(), visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +301,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
|||||||
* @return {@code -1} if the processor iterated to or beyond the beginning of the specified area.
|
* @return {@code -1} if the processor iterated to or beyond the beginning of the specified area.
|
||||||
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
|
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
|
||||||
*/
|
*/
|
||||||
public int forEachByteDesc(int index, int length, ByteProcessor visitor) {
|
public int forEachByteDesc(int index, int length, ByteProcessor visitor) throws Exception {
|
||||||
if (isOutOfBounds(index, length, length())) {
|
if (isOutOfBounds(index, length, length())) {
|
||||||
throw new IndexOutOfBoundsException("expected: " + "0 <= index(" + index + ") <= start + length(" + length
|
throw new IndexOutOfBoundsException("expected: " + "0 <= index(" + index + ") <= start + length(" + length
|
||||||
+ ") <= " + "length(" + length() + ')');
|
+ ") <= " + "length(" + length() + ')');
|
||||||
@ -309,7 +309,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
|||||||
return forEachByteDesc0(index, length, visitor);
|
return forEachByteDesc0(index, length, visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int forEachByteDesc0(int index, int length, ByteProcessor visitor) {
|
private int forEachByteDesc0(int index, int length, ByteProcessor visitor) throws Exception {
|
||||||
final int end = offset + index;
|
final int end = offset + index;
|
||||||
for (int i = offset + index + length - 1; i >= end; --i) {
|
for (int i = offset + index + length - 1; i >= end; --i) {
|
||||||
if (!visitor.process(value[i])) {
|
if (!visitor.process(value[i])) {
|
||||||
|
@ -124,5 +124,5 @@ public interface ByteProcessor {
|
|||||||
* @return {@code true} if the processor wants to continue the loop and handle the next byte in the buffer.
|
* @return {@code true} if the processor wants to continue the loop and handle the next byte in the buffer.
|
||||||
* {@code false} if the processor wants to stop handling bytes and abort the loop.
|
* {@code false} if the processor wants to stop handling bytes and abort the loop.
|
||||||
*/
|
*/
|
||||||
boolean process(byte value);
|
boolean process(byte value) throws Exception;
|
||||||
}
|
}
|
||||||
|
@ -78,13 +78,13 @@ public class AsciiStringMemoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void forEachTest() {
|
public void forEachTest() throws Exception {
|
||||||
final AtomicReference<Integer> aCount = new AtomicReference<>(0);
|
final AtomicReference<Integer> aCount = new AtomicReference<>(0);
|
||||||
final AtomicReference<Integer> bCount = new AtomicReference<>(0);
|
final AtomicReference<Integer> bCount = new AtomicReference<>(0);
|
||||||
aAsciiString.forEachByte(new ByteProcessor() {
|
aAsciiString.forEachByte(new ByteProcessor() {
|
||||||
int i;
|
int i;
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte value) {
|
public boolean process(byte value) throws Exception {
|
||||||
assertEquals("failed at index: " + i, value, bAsciiString.byteAt(i++));
|
assertEquals("failed at index: " + i, value, bAsciiString.byteAt(i++));
|
||||||
aCount.set(aCount.get() + 1);
|
aCount.set(aCount.get() + 1);
|
||||||
return true;
|
return true;
|
||||||
@ -93,7 +93,7 @@ public class AsciiStringMemoryTest {
|
|||||||
bAsciiString.forEachByte(new ByteProcessor() {
|
bAsciiString.forEachByte(new ByteProcessor() {
|
||||||
int i;
|
int i;
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte value) {
|
public boolean process(byte value) throws Exception {
|
||||||
assertEquals("failed at index: " + i, value, aAsciiString.byteAt(i++));
|
assertEquals("failed at index: " + i, value, aAsciiString.byteAt(i++));
|
||||||
bCount.set(bCount.get() + 1);
|
bCount.set(bCount.get() + 1);
|
||||||
return true;
|
return true;
|
||||||
@ -104,25 +104,25 @@ public class AsciiStringMemoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void forEachWithIndexEndTest() {
|
public void forEachWithIndexEndTest() throws Exception {
|
||||||
assertNotEquals(-1, aAsciiString.forEachByte(aAsciiString.length() - 1,
|
assertNotEquals(-1, aAsciiString.forEachByte(aAsciiString.length() - 1,
|
||||||
1, new IndexOfProcessor(aAsciiString.byteAt(aAsciiString.length() - 1))));
|
1, new IndexOfProcessor(aAsciiString.byteAt(aAsciiString.length() - 1))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void forEachWithIndexBeginTest() {
|
public void forEachWithIndexBeginTest() throws Exception {
|
||||||
assertNotEquals(-1, aAsciiString.forEachByte(0,
|
assertNotEquals(-1, aAsciiString.forEachByte(0,
|
||||||
1, new IndexOfProcessor(aAsciiString.byteAt(0))));
|
1, new IndexOfProcessor(aAsciiString.byteAt(0))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void forEachDescTest() {
|
public void forEachDescTest() throws Exception {
|
||||||
final AtomicReference<Integer> aCount = new AtomicReference<>(0);
|
final AtomicReference<Integer> aCount = new AtomicReference<>(0);
|
||||||
final AtomicReference<Integer> bCount = new AtomicReference<>(0);
|
final AtomicReference<Integer> bCount = new AtomicReference<>(0);
|
||||||
aAsciiString.forEachByteDesc(new ByteProcessor() {
|
aAsciiString.forEachByteDesc(new ByteProcessor() {
|
||||||
int i = 1;
|
int i = 1;
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte value) {
|
public boolean process(byte value) throws Exception {
|
||||||
assertEquals("failed at index: " + i, value, bAsciiString.byteAt(bAsciiString.length() - (i++)));
|
assertEquals("failed at index: " + i, value, bAsciiString.byteAt(bAsciiString.length() - (i++)));
|
||||||
aCount.set(aCount.get() + 1);
|
aCount.set(aCount.get() + 1);
|
||||||
return true;
|
return true;
|
||||||
@ -131,7 +131,7 @@ public class AsciiStringMemoryTest {
|
|||||||
bAsciiString.forEachByteDesc(new ByteProcessor() {
|
bAsciiString.forEachByteDesc(new ByteProcessor() {
|
||||||
int i = 1;
|
int i = 1;
|
||||||
@Override
|
@Override
|
||||||
public boolean process(byte value) {
|
public boolean process(byte value) throws Exception {
|
||||||
assertEquals("failed at index: " + i, value, aAsciiString.byteAt(aAsciiString.length() - (i++)));
|
assertEquals("failed at index: " + i, value, aAsciiString.byteAt(aAsciiString.length() - (i++)));
|
||||||
bCount.set(bCount.get() + 1);
|
bCount.set(bCount.get() + 1);
|
||||||
return true;
|
return true;
|
||||||
@ -142,13 +142,13 @@ public class AsciiStringMemoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void forEachDescWithIndexEndTest() {
|
public void forEachDescWithIndexEndTest() throws Exception {
|
||||||
assertNotEquals(-1, bAsciiString.forEachByteDesc(bAsciiString.length() - 1,
|
assertNotEquals(-1, bAsciiString.forEachByteDesc(bAsciiString.length() - 1,
|
||||||
1, new IndexOfProcessor(bAsciiString.byteAt(bAsciiString.length() - 1))));
|
1, new IndexOfProcessor(bAsciiString.byteAt(bAsciiString.length() - 1))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void forEachDescWithIndexBeginTest() {
|
public void forEachDescWithIndexBeginTest() throws Exception {
|
||||||
assertNotEquals(-1, bAsciiString.forEachByteDesc(0,
|
assertNotEquals(-1, bAsciiString.forEachByteDesc(0,
|
||||||
1, new IndexOfProcessor(bAsciiString.byteAt(0))));
|
1, new IndexOfProcessor(bAsciiString.byteAt(0))));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user