308 lines
10 KiB
Java
308 lines
10 KiB
Java
/*
|
|
* Copyright 2016-2020 chronicle.software
|
|
*
|
|
* https://chronicle.software
|
|
*
|
|
* Licensed 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 net.openhft.chronicle.bytes;
|
|
|
|
import net.openhft.chronicle.core.Maths;
|
|
import net.openhft.chronicle.core.io.IORuntimeException;
|
|
import net.openhft.chronicle.core.io.UnsafeText;
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
import java.io.Writer;
|
|
import java.math.BigDecimal;
|
|
import java.nio.BufferOverflowException;
|
|
import java.nio.BufferUnderflowException;
|
|
|
|
/**
|
|
* Methods to append text to a Bytes. This extends the Appendable interface.
|
|
*/
|
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
|
public interface ByteStringAppender<B extends ByteStringAppender<B>> extends StreamingDataOutput<B>, Appendable {
|
|
|
|
/**
|
|
* @return these Bytes as a Writer
|
|
*/
|
|
|
|
default Writer writer() {
|
|
return new ByteStringWriter(this);
|
|
}
|
|
|
|
/**
|
|
* Append a char in UTF-8
|
|
*
|
|
* @param ch to append
|
|
* @return this
|
|
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
|
*/
|
|
@Override
|
|
|
|
default B append(char ch) throws BufferOverflowException {
|
|
BytesInternal.appendUtf8Char(this, ch);
|
|
return (B) this;
|
|
}
|
|
|
|
/**
|
|
* Append a characters in UTF-8
|
|
*
|
|
* @param cs to append
|
|
* @return this
|
|
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
|
*/
|
|
@Override
|
|
|
|
default B append( CharSequence cs) throws BufferOverflowException {
|
|
if (cs.length() == 0)
|
|
return (B) this;
|
|
try {
|
|
return append(cs, 0, cs.length());
|
|
} catch (IndexOutOfBoundsException e) {
|
|
throw new AssertionError(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Append a boolean as T or F
|
|
*
|
|
* @param flag to append
|
|
* @return this
|
|
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
|
* @throws IORuntimeException if an error occurred while attempting to resize the underlying buffer
|
|
*/
|
|
|
|
default B append(boolean flag) throws BufferOverflowException {
|
|
return append(flag ? 'T' : 'F');
|
|
}
|
|
|
|
/**
|
|
* Append an int in decimal
|
|
*
|
|
* @param value to append
|
|
* @return this
|
|
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
|
* @throws IORuntimeException if an error occurred while attempting to resize the underlying buffer
|
|
*/
|
|
|
|
default B append(int value) throws BufferOverflowException {
|
|
BytesInternal.appendBase10(this, value);
|
|
return (B) this;
|
|
}
|
|
|
|
/**
|
|
* Append a long in decimal
|
|
*
|
|
* @param value to append
|
|
* @return this
|
|
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
|
* @throws IORuntimeException if an error occurred while attempting to resize the underlying buffer
|
|
*/
|
|
|
|
default B append(long value) throws BufferOverflowException {
|
|
if (value == (int) value)
|
|
BytesInternal.appendBase10(this, (int) value);
|
|
else
|
|
BytesInternal.appendBase10(this, value);
|
|
return (B) this;
|
|
}
|
|
|
|
|
|
default B appendBase(long value, int base) throws BufferOverflowException {
|
|
BytesInternal.append(this, value, base);
|
|
return (B) this;
|
|
}
|
|
|
|
|
|
default B appendBase16(long value) throws BufferOverflowException {
|
|
BytesInternal.appendBase16(this, value, 1);
|
|
return (B) this;
|
|
}
|
|
|
|
|
|
default B appendBase16(long value, int minDigits) throws BufferOverflowException {
|
|
BytesInternal.appendBase16(this, value, minDigits);
|
|
return (B) this;
|
|
}
|
|
|
|
/**
|
|
* Append a long in decimal with a given number of decimal places. Print value * 10^-decimalPlaces
|
|
*
|
|
* @param value to append
|
|
* @param decimalPlaces to shift the decimal place.
|
|
* @return this
|
|
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
|
* @throws IORuntimeException if an error occurred while attempting to resize the underlying buffer
|
|
*/
|
|
|
|
default B appendDecimal(long value, int decimalPlaces) throws BufferOverflowException {
|
|
BytesInternal.appendDecimal(this, value, decimalPlaces);
|
|
return (B) this;
|
|
}
|
|
|
|
/**
|
|
* Append a float in decimal notation
|
|
*
|
|
* @param f to append
|
|
* @return this
|
|
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
|
* @throws IORuntimeException if an error occurred while attempting to resize the underlying buffer
|
|
*/
|
|
|
|
default B append(float f) throws BufferOverflowException {
|
|
float f2 = Math.abs(f);
|
|
if (f2 > 1e6 || f2 < 1e-3) {
|
|
return append(Float.toString(f));
|
|
}
|
|
int precision = (int) Math.floor(6 - Math.log10(f2));
|
|
long tens = Maths.tens(precision);
|
|
return append((double) Math.round(f * tens) / tens);
|
|
}
|
|
|
|
/**
|
|
* Append a double in decimal notation
|
|
*
|
|
* @param d to append
|
|
* @return this
|
|
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
|
* @throws IORuntimeException if an error occurred while attempting to resize the underlying buffer
|
|
*/
|
|
|
|
default B append(double d) throws BufferOverflowException {
|
|
BytesInternal.append(this, d);
|
|
return (B) this;
|
|
}
|
|
|
|
/**
|
|
* Append a double in decimal notation to a specific number of decimal places. Trailing zeros are not truncated.
|
|
* <p>
|
|
* If the number would normally be printed with more decimal places, the number is rounded.
|
|
*
|
|
* @param d to append
|
|
* @param decimalPlaces to always produce
|
|
* @return this
|
|
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
|
* @throws IORuntimeException if an error occurred while attempting to resize the underlying buffer
|
|
*/
|
|
|
|
default B append(double d, int decimalPlaces) throws BufferOverflowException {
|
|
if (decimalPlaces < 0)
|
|
throw new IllegalArgumentException();
|
|
if (decimalPlaces < 18) {
|
|
double d2 = d * Maths.tens(decimalPlaces);
|
|
if (d2 < Long.MAX_VALUE && d2 > Long.MIN_VALUE) {
|
|
// changed from java.lang.Math.round(d2) as this was shown up to cause latency
|
|
long round = d2 > 0.0 ? (long) (d2 + 0.5) : (long) (d2 - 0.5);
|
|
if (canWriteDirect(20 + decimalPlaces)) {
|
|
long address = addressForWritePosition();
|
|
long address2 = UnsafeText.appendBase10d(address, round, decimalPlaces);
|
|
writeSkip(address2 - address);
|
|
} else {
|
|
appendDecimal(round, decimalPlaces);
|
|
}
|
|
return (B) this;
|
|
}
|
|
}
|
|
return append(d);
|
|
}
|
|
|
|
/**
|
|
* Append a portion of a String to the Bytes in UTF-8.
|
|
*
|
|
* @param cs to copy
|
|
* @param start index of the first char inclusive
|
|
* @param end index of the last char exclusive.
|
|
* @return this
|
|
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
|
*/
|
|
@Override
|
|
|
|
default B append( CharSequence cs, int start, int end)
|
|
throws IndexOutOfBoundsException, BufferOverflowException {
|
|
BytesInternal.appendUtf8(this, cs, start, end - start);
|
|
return (B) this;
|
|
}
|
|
|
|
/**
|
|
* Append a String to the Bytes in ISO-8859-1
|
|
*
|
|
* @param cs to write
|
|
* @return this
|
|
* @throws BufferOverflowException If the string as too large to write in the capacity available
|
|
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
|
*/
|
|
|
|
default B append8bit( CharSequence cs)
|
|
throws BufferOverflowException, BufferUnderflowException, IndexOutOfBoundsException {
|
|
return append8bit(cs, 0, cs.length());
|
|
}
|
|
|
|
default B append8bit( BytesStore bs)
|
|
throws BufferOverflowException, BufferUnderflowException, IndexOutOfBoundsException {
|
|
return write(bs, 0L, bs.readRemaining());
|
|
}
|
|
|
|
default B append8bit( String cs)
|
|
throws BufferOverflowException, BufferUnderflowException, IndexOutOfBoundsException {
|
|
return append8bit(cs, 0, cs.length());
|
|
}
|
|
|
|
/**
|
|
* Append a portion of a String to the Bytes in ISO-8859-1
|
|
*
|
|
* @param cs to copy
|
|
* @param start index of the first char inclusive
|
|
* @param end index of the last char exclusive.
|
|
* @return this
|
|
* @throws BufferOverflowException If the string as too large to write in the capacity available
|
|
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
|
* @throws IndexOutOfBoundsException if the start or the end are not valid for the CharSequence
|
|
*/
|
|
default B append8bit( CharSequence cs, int start, int end)
|
|
throws IllegalArgumentException, BufferOverflowException, BufferUnderflowException, IndexOutOfBoundsException {
|
|
if (cs instanceof BytesStore) {
|
|
return write((BytesStore) cs, (long) start, end);
|
|
}
|
|
for (int i = start; i < end; i++) {
|
|
char c = cs.charAt(i);
|
|
if (c > 255) c = '?';
|
|
writeByte((byte) c);
|
|
}
|
|
return (B) this;
|
|
}
|
|
|
|
default B append8bit( BytesStore bs, long start, long end)
|
|
throws IllegalArgumentException, BufferOverflowException, BufferUnderflowException, IndexOutOfBoundsException {
|
|
return write(bs, start, end);
|
|
}
|
|
|
|
|
|
default B appendDateMillis(long dateInMillis) {
|
|
BytesInternal.appendDateMillis(this, dateInMillis);
|
|
return (B) this;
|
|
}
|
|
|
|
|
|
default B appendTimeMillis(long timeOfDayInMillis) {
|
|
BytesInternal.appendTimeMillis(this, timeOfDayInMillis % 86400_000L);
|
|
return (B) this;
|
|
}
|
|
|
|
|
|
default B append( BigDecimal bigDecimal) {
|
|
append(bigDecimal.toString());
|
|
return (B) this;
|
|
}
|
|
}
|