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

com.firenio.buffer.ByteBuf Maven / Gradle / Ivy

There is a newer version: 1.3.6
Show newest version
/*
 * Copyright 2015 The FireNio Project
 *
 * 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 com.firenio.buffer;

import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

import com.firenio.Options;
import com.firenio.Releasable;
import com.firenio.common.Unsafe;

public abstract class ByteBuf implements Releasable {

    static final boolean                            BUF_THREAD_YIELD;
    static final boolean                            AUTO_EXPANSION;
    static final AtomicIntegerFieldUpdater refCntUpdater;

    static {
        BUF_THREAD_YIELD = Options.isBufThreadYield();
        AUTO_EXPANSION = Options.isBufAutoExpansion();
        refCntUpdater = AtomicIntegerFieldUpdater.newUpdater(ByteBuf.class, "referenceCount");
    }

    protected volatile int referenceCount = 0;

    protected int offset;
    protected int abs_write_index;
    protected int abs_read_index;
    protected int marked_abs_write_index;
    protected int marked_abs_read_index;

    public static ByteBuf direct(int cap) {
        return wrap(Unsafe.allocateDirectByteBuffer(cap));
    }

    public static ByteBuf buffer(int cap) {
        if (Unsafe.UNSAFE_BUF_AVAILABLE) {
            return unsafe(cap);
        } else {
            if (Unsafe.DIRECT_BUFFER_AVAILABLE) {
                return direct(cap);
            } else {
                return heap(cap);
            }
        }
    }

    public static ByteBuf unsafe(int cap) {
        return new UnpooledUnsafeByteBuf(Unsafe.allocate(cap), cap);
    }

    public static ByteBuf wrapAuto(byte[] data) {
        return wrapAuto(data, 0, data.length);
    }

    public static ByteBuf wrapAuto(byte[] data, int off, int len) {
        if (preferHeap()) {
            return wrap(data, off, len);
        }
        ByteBuf buf = buffer(len);
        buf.writeBytes(data, off, len);
        return buf;
    }

    public static ByteBuf wrapUnsafe(byte[] data) {
        return wrapUnsafe(data, 0, data.length);
    }

    public static ByteBuf wrapUnsafe(byte[] data, int off, int len) {
        ByteBuf buf = unsafe(len);
        buf.writeBytes(data, off, len);
        return buf;
    }

    public static ByteBuf empty() {
        return UnpooledHeapByteBuf.EmptyByteBuf.EMPTY;
    }

    public static ByteBuf heap(int cap) {
        return wrap(new byte[cap]);
    }

    public static ByteBuf wrap(byte[] data) {
        return wrap(data, 0, data.length);
    }

    public static ByteBuf wrap(byte[] data, int offset, int length) {
        return new UnpooledHeapByteBuf(data, offset, length);
    }

    public static ByteBuf wrap(ByteBuffer buffer) {
        if (buffer.isDirect()) {
            return new UnpooledDirectByteBuf(buffer);
        } else {
            return new UnpooledHeapByteBuf(buffer);
        }
    }

    public static ByteBuf wrap(long address, int cap) {
        return new UnpooledUnsafeByteBuf(address, cap);
    }

    public abstract byte getByteAbs(int pos);

    public int absWriteIndex() {
        return abs_write_index;
    }

    public ByteBuf absWriteIndex(int index) {
        this.abs_write_index = index;
        return this;
    }

    public int absReadIndex() {
        return abs_read_index;
    }

    public ByteBuf absReadIndex(int index) {
        this.abs_read_index = index;
        return this;
    }

    public boolean retain() {
        int referenceCount = this.referenceCount;
        if (referenceCount == 0) {
            return false;
        }
        if (refCntUpdater.compareAndSet(this, referenceCount, referenceCount + 1)) {
            return true;
        }
        for (; ; ) {
            referenceCount = this.referenceCount;
            if (referenceCount == 0) {
                return false;
            }
            if (refCntUpdater.compareAndSet(this, referenceCount, referenceCount + 1)) {
                return true;
            } else {
                if (BUF_THREAD_YIELD) {
                    Thread.yield();
                }
            }
        }
    }

    public abstract long address();

    public abstract byte[] array();

    public abstract int capacity();

    public abstract void compact();

    protected void capacity(int cap) {}

    public ByteBuf clear() {
        abs_read_index = 0;
        abs_write_index = 0;
        return this;
    }

    public abstract ByteBuf duplicate();

    final void ensureWritable(int len) {
        if (AUTO_EXPANSION && len > writableBytes()) {
            int cap     = capacity();
            int wantCap = capacity() + len;
            int newCap  = cap + (cap >> 1);
            for (; newCap < wantCap; ) {
                newCap = newCap + (newCap >> 1);
            }
            expansion(newCap);
        }
    }

    public abstract void expansion(int cap);

    public abstract byte readByte();

    public abstract byte getByte(int index);


    public byte[] getBytes(int index) {
        return getBytes(index, readableBytes());
    }

    public byte[] getBytes(int index, int length) {
        byte[] bytes = new byte[length];
        getBytes(index, bytes);
        return bytes;
    }

    public void getBytes(int index, byte[] dst) {
        getBytes(index, dst, 0, dst.length);
    }

    public abstract void getBytes(int index, byte[] dst, int offset, int length);

    public int getBytes(int index, ByteBuf dst) {
        return getBytes(index, dst, dst.writableBytes());
    }

    public int getBytes(int index, ByteBuf dst, int length) {
        int len = Math.min(readableBytes(), length);
        if (len == 0) {
            return 0;
        }
        return getBytes0(index, dst, len);
    }

    public int getBytes(int index, ByteBuffer dst) {
        return getBytes(index, dst, dst.remaining());
    }

    public int getBytes(int index, ByteBuffer dst, int length) {
        int len = Math.min(readableBytes(), length);
        if (len == 0) {
            return 0;
        }
        return getBytes0(index, dst, len);
    }

    protected abstract int getBytes0(int index, ByteBuf dst, int len);

    protected abstract int getBytes0(int index, ByteBuffer dst, int len);


    public byte[] readBytes() {
        return readBytes(readableBytes());
    }

    public byte[] readBytes(int length) {
        byte[] bytes = new byte[length];
        readBytes(bytes);
        return bytes;
    }

    public void readBytes(byte[] dst) {
        readBytes(dst, 0, dst.length);
    }

    public abstract void readBytes(byte[] dst, int offset, int length);

    public int readBytes(ByteBuf dst) {
        return readBytes(dst, dst.writableBytes());
    }

    public int readBytes(ByteBuf dst, int length) {
        int len = Math.min(readableBytes(), length);
        if (len == 0) {
            return 0;
        }
        return readBytes0(dst, len);
    }

    public int readBytes(ByteBuffer dst) {
        return readBytes(dst, dst.remaining());
    }

    public int readBytes(ByteBuffer dst, int length) {
        int len = Math.min(readableBytes(), length);
        if (len == 0) {
            return 0;
        }
        return readBytes0(dst, len);
    }

    protected abstract int readBytes0(ByteBuf dst, int len);

    protected abstract int readBytes0(ByteBuffer dst, int len);

    public abstract int readInt();

    public abstract int getInt(int index);

    public abstract int readIntLE();

    public abstract int getIntLE(int index);

    public abstract long readLong();

    public abstract long getLong(int index);

    public abstract long readLongLE();

    public abstract long getLongLE(int index);

    public float readFloat() {
        return Float.intBitsToFloat(readInt());
    }

    public float getFloat(int index) {
        return Float.intBitsToFloat(getInt(index));
    }

    public float readFloatLE() {
        return Float.intBitsToFloat(readIntLE());
    }

    public float getFloatLE(int index) {
        return Float.intBitsToFloat(getIntLE(index));
    }

    public double readDouble() {
        return Double.longBitsToDouble(readLong());
    }

    public double getDouble(int index) {
        return Double.longBitsToDouble(getLong(index));
    }

    public double readDoubleLE() {
        return Double.longBitsToDouble(readLongLE());
    }

    public double getDoubleLE(int index) {
        return Double.longBitsToDouble(getLongLE(index));
    }

    protected abstract ByteBuffer getNioBuffer();

    public abstract short readShort();

    public abstract short getShort(int index);

    public abstract short readShortLE();

    public abstract short getShortLE(int index);

    public abstract short readUnsignedByte();

    public abstract short getUnsignedByte(int index);

    public abstract long readUnsignedInt();

    public abstract long getUnsignedInt(int index);

    public abstract long readUnsignedIntLE();

    public abstract long getUnsignedIntLE(int index);

    public abstract int readUnsignedShort();

    public abstract int getUnsignedShort(int index);

    public abstract int readUnsignedShortLE();

    public abstract int getUnsignedShortLE(int index);

    public abstract boolean hasArray();

    public boolean hasReadableBytes() {
        return absReadIndex() < absWriteIndex();
    }

    public int indexOf(byte b) {
        return indexOf(b, absReadIndex(), readableBytes());
    }

    public int indexOf(byte b, int size) {
        return indexOf(b, absReadIndex(), size);
    }

    public abstract int indexOf(byte b, int absPos, int size);

    public boolean hasWritableBytes() {
        return writableBytes() > 0;
    }

    public abstract boolean isPooled();

    @Override
    public boolean isReleased() {
        return referenceCount < 1;
    }

    protected int ix(int index) {
        return offset() + index;
    }

    public int lastIndexOf(byte b) {
        return lastIndexOf(b, absWriteIndex() - 1, readableBytes());
    }

    public int lastIndexOf(byte b, int size) {
        return lastIndexOf(b, absWriteIndex() - 1, size);
    }

    public abstract int lastIndexOf(byte b, int absPos, int size);

    public int writeIndex() {
        return absWriteIndex() - offset();
    }

    public ByteBuf writeIndex(int index) {
        this.abs_write_index = ix(index);
        return this;
    }

    public ByteBuf markWriteIndex() {
        this.marked_abs_write_index = absWriteIndex();
        return this;
    }

    public ByteBuf markReadIndex() {
        this.marked_abs_read_index = this.abs_read_index;
        return this;
    }

    public int offset() {
        return offset;
    }

    protected void offset(int offset) {
        this.offset = offset;
    }

    public int readIndex() {
        return absReadIndex() - offset();
    }

    public ByteBuf readIndex(int index) {
        this.abs_read_index = ix(index);
        return this;
    }

    protected ByteBuf produce(int unitOffset, int unitSize) {
        return this;
    }

    public void writeByte(byte b) {
        ensureWritable(1);
        writeByte0(b);
    }

    public abstract void setByte(int index, byte b);

    protected abstract void writeByte0(byte b);

    public void setBytes(int index, byte[] src) {
        setBytes(index, src, 0, src.length);
    }

    public int setBytes(int index, byte[] src, int offset, int length) {
        if (AUTO_EXPANSION) {
            ensureWritable(length);
            return setBytes0(index, src, offset, length);
        } else {
            int len = Math.min(writableBytes(), length);
            if (len == 0) {
                return 0;
            }
            return setBytes0(index, src, offset, length);
        }
    }

    protected abstract int setBytes0(int index, byte[] src, int offset, int length);

    public int setBytes(int index, ByteBuf src) {
        return setBytes(index, src, src.readableBytes());
    }

    public int setBytes(int index, ByteBuf src, int length) {
        if (AUTO_EXPANSION) {
            ensureWritable(length);
            return setBytes0(index, src, length);
        } else {
            int len = Math.min(writableBytes(), length);
            if (len == 0) {
                return 0;
            }
            return setBytes0(index, src, len);
        }
    }

    public int setBytes(int index, ByteBuffer src) {
        return setBytes(index, src, src.remaining());
    }

    public int setBytes(int index, ByteBuffer src, int length) {
        if (AUTO_EXPANSION) {
            ensureWritable(length);
            return setBytes0(index, src, length);
        } else {
            int len = Math.min(writableBytes(), length);
            if (len == 0) {
                return 0;
            }
            return setBytes0(index, src, len);
        }
    }

    protected abstract int setBytes0(int index, ByteBuf src, int len);

    protected abstract int setBytes0(int index, ByteBuffer src, int len);


    public void writeBytes(byte[] src) {
        writeBytes(src, 0, src.length);
    }

    public int writeBytes(byte[] src, int offset, int length) {
        if (AUTO_EXPANSION) {
            ensureWritable(length);
            return writeBytes0(src, offset, length);
        } else {
            int len = Math.min(writableBytes(), length);
            if (len == 0) {
                return 0;
            }
            return writeBytes0(src, offset, length);
        }
    }

    protected abstract int writeBytes0(byte[] src, int offset, int length);

    public int writeBytes(ByteBuf src) {
        return writeBytes(src, src.readableBytes());
    }

    public int writeBytes(ByteBuf src, int length) {
        if (AUTO_EXPANSION) {
            ensureWritable(length);
            return writeBytes0(src, length);
        } else {
            int len = Math.min(writableBytes(), length);
            if (len == 0) {
                return 0;
            }
            return writeBytes0(src, len);
        }
    }

    public int writeBytes(ByteBuffer src) {
        return writeBytes(src, src.remaining());
    }

    public int writeBytes(ByteBuffer src, int length) {
        if (AUTO_EXPANSION) {
            ensureWritable(length);
            return writeBytes0(src, length);
        } else {
            int len = Math.min(writableBytes(), length);
            if (len == 0) {
                return 0;
            }
            return writeBytes0(src, len);
        }
    }

    protected abstract int writeBytes0(ByteBuf src, int len);

    protected abstract int writeBytes0(ByteBuffer src, int len);

    public void writeInt(int value) {
        ensureWritable(4);
        writeInt0(value);
    }

    protected abstract void writeInt0(int value);

    public abstract void setInt(int index, int value);

    public void writeIntLE(int value) {
        ensureWritable(4);
        writeIntLE0(value);
    }

    protected abstract void writeIntLE0(int value);

    public abstract void setIntLE(int index, int value);

    public abstract void setLong(int index, long value);

    public void writeLong(long value) {
        ensureWritable(8);
        writeLong0(value);
    }

    protected abstract void writeLong0(long value);

    public abstract void setLongLE(int index, long value);

    public void writeLongLE(long value) {
        ensureWritable(8);
        writeLongLE0(value);
    }

    protected abstract void writeLongLE0(long value);

    public void setDouble(int index, double value) {
        setLong(index, Double.doubleToRawLongBits(value));
    }

    public void writeDouble(double value) {
        writeLong(Double.doubleToRawLongBits(value));
    }

    public void setDoubleLE(int index, double value) {
        setLongLE(index, Double.doubleToRawLongBits(value));
    }

    public void writeDoubleLE(double value) {
        writeLongLE(Double.doubleToRawLongBits(value));
    }

    public void setFloat(int index, float value) {
        setInt(index, Float.floatToRawIntBits(value));
    }

    public void writeFloat(float value) {
        writeInt(Float.floatToRawIntBits(value));
    }

    public void setFloatLE(int index, float value) {
        setIntLE(index, Float.floatToRawIntBits(value));
    }

    public void writeFloatLE(float value) {
        writeIntLE(Float.floatToRawIntBits(value));
    }

    public void writeShort(int value) {
        ensureWritable(2);
        writeShort0(value);
    }

    public abstract void setShort(int index, int value);

    protected abstract void writeShort0(int value);

    public void writeShortLE(int value) {
        ensureWritable(2);
        writeShortLE0(value);
    }

    public abstract void setShortLE(int index, int value);

    protected abstract void writeShortLE0(int value);

    @Override
    public final void release() {
        int referenceCount = this.referenceCount;
        if (referenceCount < 1) {
            return;
        }
        if (refCntUpdater.compareAndSet(this, referenceCount, referenceCount - 1)) {
            if (referenceCount == 1) {
                release0();
            }
            return;
        }
        for (; ; ) {
            referenceCount = this.referenceCount;
            if (referenceCount < 1) {
                return;
            }
            if (refCntUpdater.compareAndSet(this, referenceCount, referenceCount - 1)) {
                if (referenceCount == 1) {
                    release0();
                }
                return;
            } else {
                if (BUF_THREAD_YIELD) {
                    Thread.yield();
                }
            }
        }
    }

    public abstract ByteBuf reverseRead();

    public abstract ByteBuf reverseWrite();

    public ByteBuffer nioReadBuffer() {
        ByteBuffer buffer = getNioBuffer();
        return (ByteBuffer) buffer.limit(absWriteIndex()).position(absReadIndex());
    }

    public ByteBuffer nioWriteBuffer() {
        ByteBuffer buffer = getNioBuffer();
        return (ByteBuffer) buffer.limit(capacity() + offset()).position(absWriteIndex());
    }

    protected abstract void release0();

    public int readableBytes() {
        return absWriteIndex() - absReadIndex();
    }

    public void reset(byte[] memory) {
        reset(memory, 0, memory.length);
    }

    public void reset(byte[] memory, int off, int len) {
        throw unsupportedOperationException();
    }

    public void reset(long memory, int capacity, int off, int len) {
        throw unsupportedOperationException();
    }

    public void reset(ByteBuffer memory) {
        throw unsupportedOperationException();
    }

    public int writableBytes() {
        return capacity() - writeIndex();
    }

    public ByteBuf resetWriteIndex() {
        this.abs_write_index = marked_abs_write_index;
        return this;
    }

    public ByteBuf resetReadIndex() {
        this.abs_read_index = marked_abs_read_index;
        return this;
    }

    public int getMarkedReadIndex() {
        return marked_abs_read_index - offset();
    }

    public int getMarkedWriteIndex() {
        return marked_abs_write_index - offset();
    }

    public int getMarkedAbsReadIndex() {
        return marked_abs_read_index;
    }

    public int getMarkedAbsWriteIndex() {
        return marked_abs_write_index;
    }

    public ByteBuf skipRead(int length) {
        this.abs_read_index += length;
        return this;
    }

    public ByteBuf skipWrite(int length) {
        this.abs_write_index += length;
        return this;
    }

    @Override
    public String toString() {
        StringBuilder b = new StringBuilder();
        b.append(getClass().getSimpleName());
        b.append("[r=");
        b.append(readIndex());
        b.append(",w=");
        b.append(writeIndex());
        b.append(",c=");
        b.append(capacity());
        b.append(",ra=");
        b.append(readableBytes());
        b.append(",off=");
        b.append(offset());
        b.append("]");
        return b.toString();
    }

    protected int unitOffset() {
        return -1;
    }

    protected void unitOffset(int unitOffset) {}

    protected void recycleObject(){}

    UnsupportedOperationException unsupportedOperationException() {
        return new UnsupportedOperationException();
    }

    public static boolean preferUnsafe() {
        return Unsafe.UNSAFE_BUF_AVAILABLE;
    }

    public static boolean preferDirect() {
        return !preferUnsafe() && Unsafe.DIRECT_BUFFER_AVAILABLE;
    }

    public static boolean preferHeap() {
        return !preferUnsafe() && !Unsafe.DIRECT_BUFFER_AVAILABLE;
    }

    static void copy(byte[] src, int srcPos, byte[] dst, int dstPos, int len) {
        System.arraycopy(src, srcPos, dst, dstPos, len);
    }

    static void copy(byte[] src, int srcPos, long dst, int len) {
        Unsafe.copyFromArray(src, srcPos, dst, len);
    }

    static void copy(long src, byte[] dst, int dstPos, int len) {
        Unsafe.copyToArray(src, dst, dstPos, len);
    }

    static void copy(long src, long dst, int len) {
        Unsafe.copyMemory(src, dst, len);
    }

    static long toUnsignedInt(int value) {
        return value & 0xffffffffL;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy