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

at.yawk.dbus.protocol.object.AlignableByteBuf Maven / Gradle / Ivy

/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

package at.yawk.dbus.protocol.object;

import io.netty.buffer.ByteBuf;
import io.netty.util.ReferenceCounted;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

/**
 * @author yawkat
 */
@ToString
@EqualsAndHashCode
public class AlignableByteBuf implements ReferenceCounted {
    @Getter private final ByteBuf buffer;
    private final int messageOffset;
    private final int baseAlignment;

    // visible for testing
    public AlignableByteBuf(ByteBuf buffer, int messageOffset, int baseAlignment) {
        this.buffer = buffer;
        this.messageOffset = messageOffset;
        this.baseAlignment = baseAlignment;
    }

    public static AlignableByteBuf decoding(ByteBuf wrapping) {
        return decoding(wrapping, 1 << 30);
    }

    public static AlignableByteBuf decoding(ByteBuf wrapping, int baseAlignment) {
        return new AlignableByteBuf(wrapping, -wrapping.readerIndex(), baseAlignment);
    }

    /**
     * Create a new {@link AlignableByteBuf} from the given message buffer. The message must start at {@code
     * buffer[0]}.
     */
    public static AlignableByteBuf encoding(ByteBuf wrapping) {
        return new AlignableByteBuf(wrapping, 0, 1 << 30);
    }

    /**
     * Create a new {@link AlignableByteBuf} from a buffer that is known to be aligned to a block boundary with the
     * given block size.
     *
     * @param existingAlignment the alignment of the given buffer.
     */
    public static AlignableByteBuf fromAlignedBuffer(ByteBuf buffer, int existingAlignment) {
        return new AlignableByteBuf(buffer, 0, existingAlignment);
    }

    private int calculateAlignmentOffset(int position, int alignment) {
        return (alignment - ((this.messageOffset + position) % alignment)) % alignment;
    }

    private boolean canAlign(int alignment) {
        return (baseAlignment % alignment) == 0;
    }

    private void checkAlign(int alignment) {
        if (!canAlign(alignment)) {
            throw new IllegalArgumentException(
                    "Cannot align to boundary " + alignment + ": base boundary is " + baseAlignment);
        }
    }

    public boolean canAlignRead(int alignment) {
        if (!canAlign(alignment)) { return false; }
        int toPad = calculateAlignmentOffset(getBuffer().readerIndex(), alignment);
        return getBuffer().readableBytes() >= toPad;
    }

    public void alignRead(int alignment) {
        checkAlign(alignment);
        int toPad = calculateAlignmentOffset(getBuffer().readerIndex(), alignment);
        for (int i = 0; i < toPad; i++) {
            if (getBuffer().readByte() != 0) {
                throw new DeserializerException("Non-null byte in alignment padding");
            }
        }
    }

    public boolean canAlignWrite(int alignment) {
        if (!canAlign(alignment)) { return false; }
        int toPad = calculateAlignmentOffset(getBuffer().writerIndex(), alignment);
        return getBuffer().writableBytes() >= toPad;
    }

    public void alignWrite(int alignment) {
        checkAlign(alignment);
        int toPad = calculateAlignmentOffset(getBuffer().writerIndex(), alignment);
        getBuffer().writeZero(toPad);
    }

    public boolean isReadable() {
        return getBuffer().isReadable();
    }

    public boolean isReadable(int size) {
        return getBuffer().isReadable(size);
    }

    public boolean isWritable() {
        return getBuffer().isWritable();
    }

    public boolean isWritable(int size) {
        return getBuffer().isWritable(size);
    }

    public int readableBytes() {
        return getBuffer().readableBytes();
    }

    public int writableBytes() {
        return getBuffer().writableBytes();
    }

    public int readerIndex() {
        return getBuffer().readerIndex();
    }

    public AlignableByteBuf readerIndex(int readerIndex) {
        getBuffer().readerIndex(readerIndex);
        return this;
    }

    public int writerIndex() {
        return getBuffer().writerIndex();
    }

    public AlignableByteBuf writerIndex(int writerIndex) {
        getBuffer().writerIndex(writerIndex);
        return this;
    }

    public int readInt() {
        return getBuffer().readInt();
    }

    public int readUnsignedMedium() {
        return getBuffer().readUnsignedMedium();
    }

    public int readMedium() {
        return getBuffer().readMedium();
    }

    public int readUnsignedShort() {
        return getBuffer().readUnsignedShort();
    }

    public short readShort() {
        return getBuffer().readShort();
    }

    public byte readByte() {
        return getBuffer().readByte();
    }

    public boolean readBoolean() {
        return getBuffer().readBoolean();
    }

    public long readUnsignedInt() {
        return getBuffer().readUnsignedInt();
    }

    public long readLong() {
        return getBuffer().readLong();
    }

    public char readChar() {
        return getBuffer().readChar();
    }

    public float readFloat() {
        return getBuffer().readFloat();
    }

    public double readDouble() {
        return getBuffer().readDouble();
    }

    public ByteBuf readBytes(int length) {
        return getBuffer().readBytes(length);
    }

    public AlignableByteBuf readBytes(byte[] dst) {
        getBuffer().readBytes(dst);
        return this;
    }

    public AlignableByteBuf writeBoolean(boolean value) {
        getBuffer().writeBoolean(value);
        return this;
    }

    public AlignableByteBuf writeByte(int value) {
        getBuffer().writeByte(value);
        return this;
    }

    public AlignableByteBuf writeShort(int value) {
        getBuffer().writeShort(value);
        return this;
    }

    public AlignableByteBuf writeMedium(int value) {
        getBuffer().writeMedium(value);
        return this;
    }

    public AlignableByteBuf writeInt(int value) {
        getBuffer().writeInt(value);
        return this;
    }

    public AlignableByteBuf writeLong(long value) {
        getBuffer().writeLong(value);
        return this;
    }

    public AlignableByteBuf writeChar(int value) {
        getBuffer().writeChar(value);
        return this;
    }

    public AlignableByteBuf writeFloat(float value) {
        getBuffer().writeFloat(value);
        return this;
    }

    public AlignableByteBuf writeDouble(double value) {
        getBuffer().writeDouble(value);
        return this;
    }

    public AlignableByteBuf writeBytes(ByteBuf src) {
        getBuffer().writeBytes(src);
        return this;
    }

    public AlignableByteBuf writeBytes(byte[] src) {
        getBuffer().writeBytes(src);
        return this;
    }

    @Override
    public int refCnt() {
        return getBuffer().refCnt();
    }

    @Override
    public ReferenceCounted retain() {
        getBuffer().retain();
        return this;
    }

    @Override
    public ReferenceCounted retain(int increment) {
        getBuffer().retain(increment);
        return this;
    }

    @Override
    public ReferenceCounted touch() {
        getBuffer().touch();
        return this;
    }

    @Override
    public ReferenceCounted touch(Object hint) {
        getBuffer().touch(hint);
        return this;
    }

    @Override
    public boolean release() {
        return getBuffer().release();
    }

    @Override
    public boolean release(int decrement) {
        return getBuffer().release(decrement);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy