datastructures/datastructures-bytes/src/main/java/net/openhft/chronicle/bytes/ByteStringAppender.java

309 lines
10 KiB
Java
Raw Normal View History

2021-04-08 22:36:40 +02:00
/*
* 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;
}
}