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

io.github.shanqiang.table.VarbyteColumn Maven / Gradle / Ivy

The newest version!
package io.github.shanqiang.table;

import io.github.shanqiang.ArrayUtil;
import io.github.shanqiang.exception.UnknownTypeException;
import io.github.shanqiang.offheap.ByteArray;
import io.github.shanqiang.offheap.buffer.ByteBufferOffheap;
import io.github.shanqiang.offheap.buffer.DynamicVarbyteBufferOffheap;
import io.github.shanqiang.offheap.buffer.LongBufferOffheap;
import io.github.shanqiang.offheap.buffer.VarbyteBufferOffheap;
import io.github.shanqiang.offheap.*;

import java.math.BigDecimal;

import static io.github.shanqiang.offheap.InternalUnsafe.copyMemory;
import static io.github.shanqiang.offheap.InternalUnsafe.getLong;
import static io.github.shanqiang.offheap.InternalUnsafe.putLong;
import static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;

public class VarbyteColumn implements ColumnInterface {
    private DynamicVarbyteBufferOffheap values;
    private LongBufferOffheap offsets;
    private ByteBufferOffheap valueIsNull;
    private long size;
    private long capacity;

    VarbyteColumn() {
    }

    public VarbyteColumn(int capacity) {
        this.capacity = capacity;
        values = new DynamicVarbyteBufferOffheap(45 * capacity);
        offsets = new LongBufferOffheap(capacity + 1);
        offsets.set(0, 0);
    }

    @Override
    public long size() {
        return size;
    }

    @Override
    public long serializeSize() {
        long len = Long.BYTES + (size + 1) * Long.BYTES + offsets.get(size);
        if (null != valueIsNull) {
            len += size * Byte.BYTES;
        }
        return len;
    }

    @Override
    public void serialize(byte[] bytes, long offset, long length) {
        long end = offset + length;
        offset += ARRAY_BYTE_BASE_OFFSET;
        InternalUnsafe.putLong(bytes, offset, size);
        offset += Long.BYTES;

        long len = (size + 1) * Long.BYTES;
        InternalUnsafe.copyMemory(null, offsets.getAddr(), bytes, offset, len);
        offset += len;

        len = offsets.get(size);
        InternalUnsafe.copyMemory(null, values.getAddr(), bytes, offset, len);
        offset += len;

        if (null != valueIsNull) {
            len = size * Byte.BYTES;
            InternalUnsafe.copyMemory(null, valueIsNull.getAddr(), bytes, offset, len);
            offset += len;
        }

        if (offset - ARRAY_BYTE_BASE_OFFSET != end) {
            throw new IndexOutOfBoundsException();
        }
    }

    @Override
    public void deserialize(byte[] bytes, long offset, long length) {
        long end = offset + length;

        size = InternalUnsafe.getLong(bytes, offset);
        offset += Long.BYTES;

        capacity = size;
        offsets = new LongBufferOffheap(capacity + 1);
        long len = (size + 1) * Long.BYTES;
        InternalUnsafe.copyMemory(bytes, offset, null, offsets.getAddr(), len);
        offset += len;

        len = offsets.get(size);
        // 都是空串的情况下 len 会是 0
        if (0 == len) {
            values = new DynamicVarbyteBufferOffheap(1);
        } else {
            values = new DynamicVarbyteBufferOffheap(len);
        }
        InternalUnsafe.copyMemory(bytes, offset, null, values.getAddr(), len);
        offset += len;

        if (offset < end) {
            len = size * Byte.BYTES;
            valueIsNull = new ByteBufferOffheap(capacity);
            InternalUnsafe.copyMemory(bytes, offset, null, valueIsNull.getAddr(), len);
            offset += len;
        }

        if (offset != end) {
            throw new IndexOutOfBoundsException();
        }
    }

    private void grow() {
        if (size > capacity) {
            throw new IllegalStateException();
        }
        if (size == capacity) {
            capacity = ArrayUtil.calculateNewSize(capacity);
            if (null != valueIsNull) {
                valueIsNull = valueIsNull.copy(capacity);
                valueIsNull.init0(size);
            }

            offsets = offsets.copy(capacity + 1);
        }
    }

    @Override
    public void add(Comparable comparable) {
        addObject(comparable);
    }

    public void addBytes(byte[] bytes) {
        addObject(bytes);
    }

    private void addObject(Object object) {
        grow();
        if (null == object) {
            if (null == valueIsNull) {
                valueIsNull = new ByteBufferOffheap(capacity);
                valueIsNull.init();
            }
            valueIsNull.set(size, (byte) 1);
        } else {
            Class clazz = object.getClass();
            if (clazz == String.class) {
                values.add(((String) object));
            } else if (clazz == ByteArray.class) {
                values.add((ByteArray) object);
            } else if (clazz == BigDecimal.class) {
                values.add(object.toString());
            } else if (clazz == byte[].class) {
                values.add((byte[]) object);
            } else {
                throw new UnknownTypeException(null == clazz ? "null type" : clazz.getName());
            }
        }
        addEnd();
    }

    private void addEnd() {
        offsets.set(size + 1, values.size());
        size++;
    }

    public void addOffheap(VarbyteBufferOffheap.Offheap offheap) {
        if (null == offheap) {
            add(null);
        } else {
            grow();
            values.add(offheap);
            addEnd();
        }
    }

    public VarbyteBufferOffheap.Offheap getOffheap(int index) {
        if (checkNull(index)) {
            return null;
        }
        return values.getOffheap(offsets.get(index), offsets.get(index + 1) - offsets.get(index));
    }

    private boolean checkNull(int index) {
        if (index < 0) {
            throw new IllegalArgumentException();
        }
        if (index >= size) {
            throw new IndexOutOfBoundsException();
        }

        if (valueIsNull != null && valueIsNull.get(index) == 1) {
            return true;
        }

        return false;
    }

    @Override
    public Comparable get(int index) {
        if (checkNull(index)) {
            return null;
        }
        return new ByteArray(bytes(index));
    }

    public byte[] getBytes(int index) {
        if (checkNull(index)) {
            return null;
        }
        return bytes(index);
    }

    private byte[] bytes(int index) {
        return values.getBytes(offsets.get(index), offsets.get(index + 1) - offsets.get(index));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy