package io.vertx.redis.client.impl;
import io.vertx.core.buffer.Buffer;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
final class ReadableBuffer {
enum NumericType {
INTEGER,
DECIMAL,
BIGINTEGER
}
private static final long MAX_INTEGER_DIV_10 = Long.MAX_VALUE / 10;
private static final int MARK_WATERMARK = 4 * 1024 * 1024;
private Buffer buffer;
private int offset;
private int mark;
void append(Buffer chunk) {
if (buffer == null || Math.min(mark, offset) == buffer.length()) {
buffer = chunk;
offset = 0;
return;
}
if (
offset >= mark &&
mark > MARK_WATERMARK &&
buffer.length() > mark) {
buffer = buffer.getBuffer(mark, buffer.length());
offset -= mark;
mark = 0;
}
buffer.appendBuffer(chunk);
}
int findLineEnd() {
int index = -1;
for (int i = offset; i < buffer.length(); i++) {
if (buffer.getByte(i) == '\n') {
index = i;
break;
}
}
return (index > 0 && buffer.getByte(index - 1) == '\r') ? index : -1;
}
long readLong(int end) {
long value = 0;
boolean negative = buffer.getByte(this.offset) == '-';
int offset = negative ? this.offset + 1 : this.offset;
while (offset < end - 1) {
if (value > MAX_INTEGER_DIV_10) {
throw new ArithmeticException("Overflow");
}
int digit = buffer.getByte(offset++) - '0';
if (digit < 0 || digit > 9) {
throw new IllegalStateException("Not a digit " + (char) digit);
}
value = value * 10 - digit;
}
if (!negative) value = -value;
this.offset = end + 1;
return value;
}
Number readNumber(int end, NumericType type) {
Number number = null;
if (end >= offset) {
byte[] bytes = buffer.getBytes(offset, end - 1);
switch (type) {
case INTEGER:
number = Long.parseLong(new String(bytes, StandardCharsets.US_ASCII));
break;
case DECIMAL:
if (bytes.length == 3 && bytes[0] == 'i' && bytes[1] == 'n' && bytes[2] == 'f') {
number = Double.POSITIVE_INFINITY;
} else if (bytes.length == 4 && bytes[0] == '-' && bytes[1] == 'i' && bytes[2] == 'n' && bytes[3] == 'f') {
number = Double.NEGATIVE_INFINITY;
} else {
number = Double.parseDouble(new String(bytes, StandardCharsets.US_ASCII));
}
break;
case BIGINTEGER:
number = new BigInteger(bytes);
break;
}
offset = end + 1;
}
return number;
}
String readLine(int end) {
byte[] bytes = null;
if (end >= offset) {
bytes = buffer.getBytes(offset, end - 1);
offset = end + 1;
}
if (bytes != null) {
return new String(bytes, StandardCharsets.ISO_8859_1);
}
return null;
}
Buffer readBytes(int count) {
Buffer bytes = null;
if (buffer.length() - offset >= count) {
bytes = buffer.getBuffer(offset, offset + count);
offset += count;
}
return bytes;
}
byte readByte() {
return buffer.getByte(offset++);
}
byte getByte(int index) {
return buffer.getByte(index);
}
int readableBytes() {
return buffer.length() - offset;
}
void mark() {
mark = offset;
}
void reset() {
offset = mark;
}
int offset() {
return offset;
}
boolean skipEOL() {
while (readableBytes() > 0) {
byte b;
b = readByte();
if (b == '\r') {
if (readableBytes() > 0) {
b = readByte();
if (b == '\n') {
return true;
}
}
}
}
return false;
}
@Override
public String toString() {
return buffer != null ? buffer.toString() : "null";
}
}