All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.openhft.chronicle.bytes.ByteStringAppender Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2016-2022 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.bytes.internal.ByteStringWriter;
import net.openhft.chronicle.bytes.internal.BytesInternal;
import net.openhft.chronicle.bytes.render.Decimaliser;
import net.openhft.chronicle.core.Maths;
import net.openhft.chronicle.core.annotation.NonNegative;
import net.openhft.chronicle.core.io.ClosedIllegalStateException;
import net.openhft.chronicle.core.io.IORuntimeException;
import net.openhft.chronicle.core.io.ThreadingIllegalStateException;
import net.openhft.chronicle.core.scoped.ScopedResource;
import org.jetbrains.annotations.NotNull;

import java.io.Writer;
import java.math.BigDecimal;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;

/**
 * This interface provides methods for appending different types of data to an underlying buffer. The data is appended in the form of bytes.
 * The interface also extends the StreamingDataOutput and Appendable interfaces, thus inheriting their methods.
 *
 * @param  the type that extends ByteStringAppender
 */
@SuppressWarnings({"rawtypes", "unchecked"})
public interface ByteStringAppender> extends StreamingDataOutput, Appendable {

    /**
     * Returns the current ByteStringAppender instance as a Writer.
     *
     * @return Writer object representing the ByteStringAppender
     */
    @NotNull
    default Writer writer() {
        return new ByteStringWriter(this);
    }

    /**
     * Appends a UTF-8 encoded character to the buffer.
     *
     * @param ch the character to append
     * @return the ByteStringAppender instance with the appended character
     * @throws BufferOverflowException        If the append operation exceeds the buffer's capacity
     * @throws ClosedIllegalStateException    If the resource has been released or closed.
     * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way
     */
    @Override
    @NotNull
    default B append(char ch)
            throws IllegalStateException {
        BytesInternal.appendUtf8Char(this, ch);
        return (B) this;
    }

    /**
     * Append a characters in UTF-8
     *
     * @param cs the CharSequence to append
     * @return this
     * @throws BufferUnderflowException       If the capacity of the underlying buffer was exceeded
     * @throws ClosedIllegalStateException    If the resource has been released or closed.
     * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way
     */
    @Override
    @NotNull
    default B append(@NotNull CharSequence cs) {
        if (cs.length() == 0)
            return (B) this;
        return append(cs, 0, cs.length());
    }

    /**
     * Appends a boolean as 'T' or 'F' character.
     *
     * @param flag to append
     * @return this
     * @throws BufferOverflowException        If the relative append operation exceeds the underlying buffer's capacity
     * @throws IORuntimeException             If an error occurred while attempting to resize the underlying buffer
     * @throws ClosedIllegalStateException    If the resource has been released or closed.
     * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way.
     */
    @NotNull
    default B append(boolean flag)
            throws BufferOverflowException, ClosedIllegalStateException, ThreadingIllegalStateException {
        return append(flag ? 'T' : 'F');
    }

    /**
     * Appends an int in decimal to this.
     *
     * @param value the integer value to append
     * @return this
     * @throws BufferOverflowException        If the relative append operation exceeds the underlying buffer's capacity
     * @throws IORuntimeException             If an error occurred while attempting to resize the underlying buffer
     * @throws ClosedIllegalStateException    If the resource has been released or closed.
     * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way.
     */
    @NotNull
    default B append(int value)
            throws BufferOverflowException, ClosedIllegalStateException, ThreadingIllegalStateException {
        BytesInternal.appendBase10(this, value);
        return (B) this;
    }

    /**
     * Appends a long value in decimal.
     *
     * @param value the long number to append
     * @return this
     * @throws BufferOverflowException        If the relative append operation exceeds the underlying buffer's capacity
     * @throws IORuntimeException             If an error occurred while attempting to resize the underlying buffer
     * @throws ClosedIllegalStateException    If the resource has been released or closed.
     * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way.
     */
    @NotNull
    default B append(long value)
            throws BufferOverflowException, ClosedIllegalStateException, ThreadingIllegalStateException {
        if (value == (int) value)
            BytesInternal.appendBase10(this, (int) value);
        else
            BytesInternal.appendBase10(this, value);
        return (B) this;
    }

    /**
     * Appends a string representation of the first argument in the radix specified by the second argument.
     *
     * @param value the number to append
     * @param base  the radix that the specified value should be converted to before append
     * @return this
     * @throws BufferOverflowException        If the relative append operation exceeds the underlying buffer's capacity
     * @throws IllegalArgumentException       If the specified arguments are illegal
     * @throws ClosedIllegalStateException    If the resource has been released or closed.
     * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way.
     */
    @NotNull
    default B appendBase(long value, int base)
            throws BufferOverflowException, IllegalArgumentException, ClosedIllegalStateException, ThreadingIllegalStateException {
        if (base == 10)
            append(value);
        else
            BytesInternal.append(this, value, base);
        return (B) this;
    }

    /**
     * Appends the base 16 (hexadecimal) representation of the specified long value.
     *
     * @param value the long value to be converted to base 16 and appended
     * @return this
     * @throws BufferOverflowException        If the relative append operation exceeds the underlying buffer's capacity
     * @throws IllegalArgumentException       If the specified argument is illegal
     * @throws ClosedIllegalStateException    If the resource has been released or closed.
     * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way.
     */
    @NotNull
    default B appendBase16(long value)
            throws BufferOverflowException, IllegalArgumentException, ClosedIllegalStateException, ThreadingIllegalStateException {
        BytesInternal.appendBase16(this, value, 1);
        return (B) this;
    }

    /**
     * Appends the base 16 (hexadecimal) representation of the specified long value,
     * padding with leading zeroes if the number of digits is less than minDigits.
     *
     * @param value     the long value to be converted to base 16 and appended
     * @param minDigits the minimum number of digits to be appended
     * @return this
     * @throws BufferOverflowException        If the relative append operation exceeds the underlying buffer's capacity
     * @throws IllegalArgumentException       If the specified argument is illegal
     * @throws ClosedIllegalStateException    If the resource has been released or closed.
     * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way.
     */
    @NotNull
    default B appendBase16(long value, int minDigits)
            throws BufferOverflowException, IllegalArgumentException, IllegalStateException {
        BytesInternal.appendBase16(this, value, minDigits);
        return (B) this;
    }

    /**
     * Appends a long in decimal with a given number of decimal places. Prints value * 10^-decimalPlaces
     *
     * @param value         to append
     * @param decimalPlaces to shift the decimal place
     * @return this
     * @throws BufferOverflowException        If the relative append operation exceeds the underlying buffer's capacity
     * @throws IORuntimeException             If an error occurred while attempting to resize the underlying buffer
     * @throws IllegalArgumentException       If the decimalPlaces is negative or too large
     * @throws ClosedIllegalStateException    If the resource has been released or closed.
     * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way.
     */
    @NotNull
    default B appendDecimal(long value, int decimalPlaces)
            throws BufferOverflowException, IllegalStateException, IllegalArgumentException {
        BytesInternal.appendDecimal(this, value, decimalPlaces);
        return (B) this;
    }

    /**
     * Appends a float in decimal notation
     *
     * @param f the float number to append
     * @return this
     * @throws BufferOverflowException        If the relative append operation exceeds the underlying buffer's capacity
     * @throws ClosedIllegalStateException    If the resource has been released or closed.
     * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way.
     */
    @NotNull
    default B append(float f)
            throws BufferOverflowException, IllegalStateException, ClosedIllegalStateException, ThreadingIllegalStateException {
        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);
    }

    /**
     * Appends a double in decimal notation
     *
     * @param d to append
     * @return this
     * @throws BufferOverflowException        If the capacity of the underlying buffer was exceeded
     * @throws IORuntimeException             If an error occurred while attempting to resize the underlying buffer
     * @throws ClosedIllegalStateException    If the resource has been released or closed.
     * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way.
     */
    @NotNull
    default B append(double d)
            throws BufferOverflowException, IllegalStateException, ClosedIllegalStateException, ThreadingIllegalStateException {
        try (ScopedResource> stlBytes = BytesInternal.acquireBytesScoped()) {
            Bytes bytes = stlBytes.get();
            bytes.append(d);
            append(bytes);
            return (B) this;
        }
    }

    /**
     * Gets the Decimaliser currently associated with this ByteStringAppender.
     *
     * @return The Decimaliser currently associated with this ByteStringAppender.
     */
    Decimaliser decimaliser();

    /**
     * Associates a Decimaliser with this ByteStringAppender.
     *
     * 

The Decimaliser is an interface which can be implemented to provide custom logic * for rendering decimal numbers in this ByteStringAppender. * * @param decimaliser The Decimaliser to be associated with this ByteStringAppender. * @return The ByteStringAppender instance with the Decimaliser set. */ B decimaliser(Decimaliser decimaliser); /** * @return whether floating point add .0 to indicate it is a floating point even if redundant. */ @Deprecated(/* to remove in x.28 */) boolean fpAppend0(); /** * @param append0 Does floating point add .0 to indicate it is a floating point even if redundant. * @return this */ @Deprecated(/* to remove in x.28 */) B fpAppend0(boolean append0); /** * Appends a double in decimal notation to a specific number of decimal places. Trailing zeros are not truncated. *

* 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 BufferOverflowException If the capacity of the underlying buffer was exceeded * @throws IORuntimeException If an error occurred while attempting to resize the underlying buffer * @throws IllegalArgumentException If the decimalPlaces is negative or too large * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ @NotNull default B append(double d, int decimalPlaces) throws BufferOverflowException, IllegalArgumentException, ClosedIllegalStateException, ThreadingIllegalStateException { BytesInternal.append(this, d, decimalPlaces); return (B) this; } /** * Appends a portion of a string to the Bytes in UTF-8. * * @param cs the CharacterSequence to append * @param start index of the first char inclusive * @param end index of the last char exclusive * @return this * @throws BufferOverflowException If the capacity of the underlying buffer was exceeded * @throws IndexOutOfBoundsException If the specified indexes are out of range * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ @Override @NotNull default B append(@NotNull CharSequence cs, @NonNegative int start, @NonNegative int end) throws IndexOutOfBoundsException { BytesInternal.appendUtf8(this, cs, start, end - start); return (B) this; } /** * Appends a String to the Bytes in ISO-8859-1. * * @param cs the CharSequence to append * @return this * @throws BufferOverflowException If the string is too large to write in the capacity available * @throws BufferUnderflowException If the capacity of the underlying buffer was exceeded * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ @NotNull default B append8bit(@NotNull CharSequence cs) throws BufferOverflowException, BufferUnderflowException, ClosedIllegalStateException, ThreadingIllegalStateException { return append8bit(cs, 0, cs.length()); } /** * Appends the ISO-8859-1 representation of the specified BytesStore. * * @param bs the BytesStore to append * @return this * @throws BufferOverflowException If the BytesStore is too large to write in the capacity available * @throws BufferUnderflowException If the capacity of the underlying buffer was exceeded * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default B append8bit(@NotNull BytesStore bs) throws BufferOverflowException, BufferUnderflowException, ClosedIllegalStateException, ThreadingIllegalStateException { return write(bs, 0L, bs.readRemaining()); } /** * Appends the ISO-8859-1 representation of the specified String. * * @param cs the String to append * @return this * @throws BufferOverflowException If the string is too large to write in the capacity available * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default B append8bit(@NotNull String cs) throws BufferOverflowException, ClosedIllegalStateException, ThreadingIllegalStateException { return append8bit(cs, 0, cs.length()); } /** * Appends a portion of a string to this Bytes in ISO-8859-1. * * @param cs the CharSequence to append * @param start index of the first char of cs (inclusive) to append * @param end index of the last char of cs (exclusive) to append * @return this * @throws BufferOverflowException If the string is 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 * @throws IllegalArgumentException If the start or end is negative or too large * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default B append8bit(@NotNull CharSequence cs, @NonNegative int start, @NonNegative int end) throws IllegalArgumentException, BufferOverflowException, BufferUnderflowException, IndexOutOfBoundsException, ClosedIllegalStateException, ThreadingIllegalStateException { assert end >= start : "end=" + end + ",start=" + start; if (cs instanceof BytesStore) { return write((BytesStore) cs, (long) start, end - start); } for (int i = start; i < end; i++) { char c = cs.charAt(i); if (c > 255) c = '?'; writeByte((byte) c); } return (B) this; } /** * Appends a portion of a BytesStore to this in ISO-8859-1 format. * * @param bs the specified BytesStore that a portion of it will be appended to this * @param start the index of first byte (inclusive) of bs to append * @param end the number of bytes of bs to append * @return this * @throws IllegalArgumentException If an illegal argument is passed to the method * @throws BufferOverflowException If the relative append operation exceeds the underlying buffer's capacity * @throws BufferUnderflowException If the capacity of the BytesStore was exceeded * @throws IndexOutOfBoundsException If the specified indexes for the BytesStore are out of range * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default B append8bit(@NotNull BytesStore bs, @NonNegative long start, @NonNegative long end) throws IllegalArgumentException, BufferOverflowException, BufferUnderflowException, IndexOutOfBoundsException, ClosedIllegalStateException, ThreadingIllegalStateException { assert end > start : "end=" + end + ",start=" + start; return write(bs, start, end - start); } /** * Converts a specified long number to a date in the format yyyymmdd and appends the date to this. * The specified long number represents a point in time that is time milliseconds after January 1, 1970 00:00:00 GMT. * * @param dateInMillis the specified long to convert to date and append to this * @return this * @throws BufferOverflowException If the relative append operation exceeds the underlying buffer's capacity * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ @NotNull default B appendDateMillis(long dateInMillis) throws BufferOverflowException, ClosedIllegalStateException, ThreadingIllegalStateException { BytesInternal.appendDateMillis(this, dateInMillis); return (B) this; } /** * Converts a specified long number to time of day and appends it to this. The specified long number * represents time in milliseconds after 00:00:00.000 GMT which will be converted to hours, minutes, seconds and milliseconds. *

* Twelve bytes in the format of hh:mm:ss.ddd will be appended to this. hh, mm, ss and ddd represent * hour, minute, second and millisecond. * * @param timeOfDayInMillis the long number that represents time of day in milliseconds * @return this * @throws BufferOverflowException If the relative append operation exceeds the underlying buffer's capacity * @throws IllegalArgumentException If an illegal argument is passed to the method * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ @NotNull default B appendTimeMillis(long timeOfDayInMillis) throws BufferOverflowException, IllegalArgumentException, ClosedIllegalStateException, ThreadingIllegalStateException { BytesInternal.appendTimeMillis(this, timeOfDayInMillis % 86400_000L); return (B) this; } /** * Appends a string representation of a specified BigDecimal to this. *

* The string representation of the BigDecimal number is a standard canonical string form as * described in {@link BigDecimal#toString()}. * * @param bigDecimal the specified BigDecimal to append * @return this * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. * @see java.math.BigDecimal */ @NotNull default B append(@NotNull BigDecimal bigDecimal) throws ClosedIllegalStateException, ThreadingIllegalStateException { append(bigDecimal.toString()); return (B) this; } }