blob: 4fce022ee94bcfef49e7e1335027eb2ba7d5b217 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.arrow.vector;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.arrow.memory.BufferAllocator;
import org.apache.arrow.memory.util.ArrowBufPointer;
import org.apache.arrow.memory.util.ByteFunctionHelpers;
import org.apache.arrow.util.Preconditions;
import org.apache.arrow.vector.compare.VectorVisitor;
import org.apache.arrow.vector.ipc.message.ArrowFieldNode;
import org.apache.arrow.vector.types.pojo.Field;
import org.apache.arrow.vector.util.CallBack;
import org.apache.arrow.vector.util.OversizedAllocationException;
import org.apache.arrow.vector.util.TransferPair;
import io.netty.buffer.ArrowBuf;
import io.netty.util.internal.PlatformDependent;
/**
* BaseFixedWidthVector provides an abstract interface for
* implementing vectors of fixed width values. The vectors are nullable
* implying that zero or more elements in the vector could be NULL.
*/
public abstract class BaseFixedWidthVector extends BaseValueVector
implements FixedWidthVector, FieldVector, VectorDefinitionSetter {
private final int typeWidth;
protected int lastValueCapacity;
protected final Field field;
private int allocationMonitor;
protected ArrowBuf validityBuffer;
protected ArrowBuf valueBuffer;
protected int valueCount;
/**
* Constructs a new instance.
*
* @param field field materialized by this vector
* @param allocator The allocator to use for allocating memory for the vector.
* @param typeWidth The width in bytes of the type.
*/
public BaseFixedWidthVector(Field field, final BufferAllocator allocator, final int typeWidth) {
super(allocator);
this.typeWidth = typeWidth;
this.field = field;
valueCount = 0;
allocationMonitor = 0;
validityBuffer = allocator.getEmpty();
valueBuffer = allocator.getEmpty();
lastValueCapacity = INITIAL_VALUE_ALLOCATION;
}
public int getTypeWidth() {
return typeWidth;
}
@Override
public String getName() {
return field.getName();
}
/* TODO:
* see if getNullCount() can be made faster -- O(1)
*/
/* TODO:
* Once the entire hierarchy has been refactored, move common functions
* like getNullCount(), splitAndTransferValidityBuffer to top level
* base class BaseValueVector.
*
* Along with this, some class members (validityBuffer) can also be
* abstracted out to top level base class.
*
* Right now BaseValueVector is the top level base class for other
* vector types in ValueVector hierarchy (non-nullable) and those
* vectors have not yet been refactored/removed so moving things to
* the top class as of now is not a good idea.
*/
/**
* Get the memory address of buffer that manages the validity
* (NULL or NON-NULL nature) of elements in the vector.
* @return starting address of the buffer
*/
@Override
public long getValidityBufferAddress() {
return (validityBuffer.memoryAddress());
}
/**
* Get the memory address of buffer that stores the data for elements
* in the vector.
* @return starting address of the buffer
*/
@Override
public long getDataBufferAddress() {
return (valueBuffer.memoryAddress());
}
/**
* Get the memory address of buffer that stores the offsets for elements
* in the vector. This operation is not supported for fixed-width vectors.
* @return starting address of the buffer
* @throws UnsupportedOperationException for fixed width vectors
*/
@Override
public long getOffsetBufferAddress() {
throw new UnsupportedOperationException("not supported for fixed-width vectors");
}
/**
* Get buffer that manages the validity (NULL or NON-NULL nature) of
* elements in the vector. Consider it as a buffer for internal bit vector
* data structure.
* @return buffer
*/
@Override
public ArrowBuf getValidityBuffer() {
return validityBuffer;
}
/**
* Get the buffer that stores the data for elements in the vector.
* @return buffer
*/
@Override
public ArrowBuf getDataBuffer() {
return valueBuffer;
}
/**
* buffer that stores the offsets for elements
* in the vector. This operation is not supported for fixed-width vectors.
* @return buffer
* @throws UnsupportedOperationException for fixed width vectors
*/
@Override
public ArrowBuf getOffsetBuffer() {
throw new UnsupportedOperationException("not supported for fixed-width vectors");
}
/**
* Sets the desired value capacity for the vector. This function doesn't
* allocate any memory for the vector.
* @param valueCount desired number of elements in the vector
*/
@Override
public void setInitialCapacity(int valueCount) {
computeAndCheckBufferSize(valueCount);
lastValueCapacity = valueCount;
}
/**
* Get the current value capacity for the vector
* @return number of elements that vector can hold.
*/
@Override
public int getValueCapacity() {
return Math.min(getValueBufferValueCapacity(), getValidityBufferValueCapacity());
}
private int getValueBufferValueCapacity() {
return valueBuffer.capacity() / typeWidth;
}
private int getValidityBufferValueCapacity() {
return validityBuffer.capacity() * 8;
}
/**
* zero out the vector and the data in associated buffers.
*/
@Override
public void zeroVector() {
initValidityBuffer();
initValueBuffer();
}
/* zero out the validity buffer */
private void initValidityBuffer() {
validityBuffer.setZero(0, validityBuffer.capacity());
}
/* zero out the data buffer */
private void initValueBuffer() {
valueBuffer.setZero(0, valueBuffer.capacity());
}
/**
* Reset the vector to initial state. Same as {@link #zeroVector()}.
* Note that this method doesn't release any memory.
*/
@Override
public void reset() {
valueCount = 0;
zeroVector();
}
/**
* Close the vector and release the associated buffers.
*/
@Override
public void close() {
clear();
}
/**
* Same as {@link #close()}.
*/
@Override
public void clear() {
valueCount = 0;
validityBuffer = releaseBuffer(validityBuffer);
valueBuffer = releaseBuffer(valueBuffer);
}
/* used to step down the memory allocation */
protected void incrementAllocationMonitor() {
if (allocationMonitor < 0) {
allocationMonitor = 0;
}
allocationMonitor++;
}
/* used to step up the memory allocation */
protected void decrementAllocationMonitor() {
if (allocationMonitor > 0) {
allocationMonitor = 0;
}
allocationMonitor--;
}
/**
* Same as {@link #allocateNewSafe()}.
*/
@Override
public void allocateNew() {
allocateNew(lastValueCapacity);
}
/**
* Allocate memory for the vector. We internally use a default value count
* of 4096 to allocate memory for at least these many elements in the
* vector. See {@link #allocateNew(int)} for allocating memory for specific
* number of elements in the vector.
*
* @return false if memory allocation fails, true otherwise.
*/
@Override
public boolean allocateNewSafe() {
try {
allocateNew(lastValueCapacity);
return true;
} catch (Exception e) {
return false;
}
}
/**
* Allocate memory for the vector to support storing at least the provided number of
* elements in the vector. This method must be called prior to using the ValueVector.
*
* @param valueCount the desired number of elements in the vector
* @throws org.apache.arrow.memory.OutOfMemoryException on error
*/
public void allocateNew(int valueCount) {
computeAndCheckBufferSize(valueCount);
/* we are doing a new allocation -- release the current buffers */
clear();
try {
allocateBytes(valueCount);
} catch (Exception e) {
clear();
throw e;
}
}
/*
* Compute the buffer size required for 'valueCount', and check if it's within bounds.
*/
private long computeAndCheckBufferSize(int valueCount) {
final long size = computeCombinedBufferSize(valueCount, typeWidth);
if (size > MAX_ALLOCATION_SIZE) {
throw new OversizedAllocationException("Memory required for vector capacity " +
valueCount +
" is (" + size + "), which is more than max allowed (" + MAX_ALLOCATION_SIZE + ")");
}
return size;
}
/**
* Actual memory allocation is done by this function. All the calculations
* and knowledge about what size to allocate is upto the callers of this
* method.
* Callers appropriately handle errors if memory allocation fails here.
* Callers should also take care of determining that desired size is
* within the bounds of max allocation allowed and any other error
* conditions.
*/
private void allocateBytes(int valueCount) {
DataAndValidityBuffers buffers = allocFixedDataAndValidityBufs(valueCount, typeWidth);
valueBuffer = buffers.getDataBuf();
validityBuffer = buffers.getValidityBuf();
zeroVector();
lastValueCapacity = getValueCapacity();
}
/**
* During splitAndTransfer, if we splitting from a random position within a byte,
* we can't just slice the source buffer so we have to explicitly allocate the
* validityBuffer of the target vector. This is unlike the databuffer which we can
* always slice for the target vector.
*/
private void allocateValidityBuffer(final int validityBufferSize) {
validityBuffer = allocator.buffer(validityBufferSize);
validityBuffer.readerIndex(0);
}
/**
* Get the potential buffer size for a particular number of records.
* @param count desired number of elements in the vector
* @return estimated size of underlying buffers if the vector holds
* a given number of elements
*/
@Override
public int getBufferSizeFor(final int count) {
if (count == 0) {
return 0;
}
return (count * typeWidth) + getValidityBufferSizeFromCount(count);
}
/**
* Get the size (number of bytes) of underlying buffers used by this
* vector.
* @return size of underlying buffers.
*/
@Override
public int getBufferSize() {
if (valueCount == 0) {
return 0;
}
return (valueCount * typeWidth) + getValidityBufferSizeFromCount(valueCount);
}
/**
* Get information about how this field is materialized.
* @return the field corresponding to this vector
*/
@Override
public Field getField() {
return field;
}
/**
* Return the underlying buffers associated with this vector. Note that this doesn't
* impact the reference counts for this buffer so it only should be used for in-context
* access. Also note that this buffer changes regularly thus
* external classes shouldn't hold a reference to it (unless they change it).
*
* @param clear Whether to clear vector before returning; the buffers will still be refcounted
* but the returned array will be the only reference to them
* @return The underlying {@link io.netty.buffer.ArrowBuf buffers} that is used by this
* vector instance.
*/
@Override
public ArrowBuf[] getBuffers(boolean clear) {
final ArrowBuf[] buffers;
setReaderAndWriterIndex();
if (getBufferSize() == 0) {
buffers = new ArrowBuf[0];
} else {
buffers = new ArrowBuf[2];
buffers[0] = validityBuffer;
buffers[1] = valueBuffer;
}
if (clear) {
for (final ArrowBuf buffer : buffers) {
buffer.getReferenceManager().retain(1);
}
clear();
}
return buffers;
}
/**
* Resize the vector to increase the capacity. The internal behavior is to
* double the current value capacity.
*/
@Override
public void reAlloc() {
int targetValueCount = getValueCapacity() * 2;
if (targetValueCount == 0) {
if (lastValueCapacity > 0) {
targetValueCount = lastValueCapacity;
} else {
targetValueCount = INITIAL_VALUE_ALLOCATION * 2;
}
}
computeAndCheckBufferSize(targetValueCount);
DataAndValidityBuffers buffers = allocFixedDataAndValidityBufs(targetValueCount, typeWidth);
final ArrowBuf newValueBuffer = buffers.getDataBuf();
newValueBuffer.setBytes(0, valueBuffer, 0, valueBuffer.capacity());
newValueBuffer.setZero(valueBuffer.capacity(), newValueBuffer.capacity() - valueBuffer.capacity());
valueBuffer.getReferenceManager().release();
valueBuffer = newValueBuffer;
final ArrowBuf newValidityBuffer = buffers.getValidityBuf();
newValidityBuffer.setBytes(0, validityBuffer, 0, validityBuffer.capacity());
newValidityBuffer.setZero(validityBuffer.capacity(), newValidityBuffer.capacity() - validityBuffer.capacity());
validityBuffer.getReferenceManager().release();
validityBuffer = newValidityBuffer;
lastValueCapacity = getValueCapacity();
}
@Override
@Deprecated
public List<BufferBacked> getFieldInnerVectors() {
throw new UnsupportedOperationException("There are no inner vectors. Use getFieldBuffers");
}
/**
* Initialize the children in schema for this Field. This operation is a
* NO-OP for scalar types since they don't have any children.
* @param children the schema
* @throws IllegalArgumentException if children is a non-empty list for scalar types.
*/
@Override
public void initializeChildrenFromFields(List<Field> children) {
if (!children.isEmpty()) {
throw new IllegalArgumentException("primitive type vector can not have children");
}
}
/**
* Get the inner child vectors.
* @return list of child vectors for complex types, empty list for scalar vector types
*/
@Override
public List<FieldVector> getChildrenFromFields() {
return Collections.emptyList();
}
/**
* Load the buffers of this vector with provided source buffers.
* The caller manages the source buffers and populates them before invoking
* this method.
* @param fieldNode the fieldNode indicating the value count
* @param ownBuffers the buffers for this Field (own buffers only, children not included)
*/
@Override
public void loadFieldBuffers(ArrowFieldNode fieldNode, List<ArrowBuf> ownBuffers) {
if (ownBuffers.size() != 2) {
throw new IllegalArgumentException("Illegal buffer count, expected " + 2 + ", got: " + ownBuffers.size());
}
ArrowBuf bitBuffer = ownBuffers.get(0);
ArrowBuf dataBuffer = ownBuffers.get(1);
validityBuffer.getReferenceManager().release();
validityBuffer = BitVectorHelper.loadValidityBuffer(fieldNode, bitBuffer, allocator);
valueBuffer.getReferenceManager().release();
valueBuffer = dataBuffer.getReferenceManager().retain(dataBuffer, allocator);
valueCount = fieldNode.getLength();
}
/**
* Get the buffers belonging to this vector
* @return the inner buffers.
*/
public List<ArrowBuf> getFieldBuffers() {
List<ArrowBuf> result = new ArrayList<>(2);
setReaderAndWriterIndex();
result.add(validityBuffer);
result.add(valueBuffer);
return result;
}
/**
* Set the reader and writer indexes for the inner buffers.
*/
private void setReaderAndWriterIndex() {
validityBuffer.readerIndex(0);
valueBuffer.readerIndex(0);
if (valueCount == 0) {
validityBuffer.writerIndex(0);
valueBuffer.writerIndex(0);
} else {
validityBuffer.writerIndex(getValidityBufferSizeFromCount(valueCount));
if (typeWidth == 0) {
/* specialized handling for BitVector */
valueBuffer.writerIndex(getValidityBufferSizeFromCount(valueCount));
} else {
valueBuffer.writerIndex(valueCount * typeWidth);
}
}
}
/**
* Construct a transfer pair of this vector and another vector of same type.
* @param ref name of the target vector
* @param allocator allocator for the target vector
* @param callBack not used
* @return TransferPair
*/
@Override
public TransferPair getTransferPair(String ref, BufferAllocator allocator, CallBack callBack) {
return getTransferPair(ref, allocator);
}
/**
* Construct a transfer pair of this vector and another vector of same type.
* @param allocator allocator for the target vector
* @return TransferPair
*/
@Override
public TransferPair getTransferPair(BufferAllocator allocator) {
return getTransferPair(getName(), allocator);
}
/**
* Construct a transfer pair of this vector and another vector of same type.
* @param ref name of the target vector
* @param allocator allocator for the target vector
* @return TransferPair
*/
public abstract TransferPair getTransferPair(String ref, BufferAllocator allocator);
/**
* Transfer this vector'data to another vector. The memory associated
* with this vector is transferred to the allocator of target vector
* for accounting and management purposes.
* @param target destination vector for transfer
*/
public void transferTo(BaseFixedWidthVector target) {
compareTypes(target, "transferTo");
target.clear();
target.validityBuffer = transferBuffer(validityBuffer, target.allocator);
target.valueBuffer = transferBuffer(valueBuffer, target.allocator);
target.valueCount = valueCount;
clear();
}
/**
* Slice this vector at desired index and length and transfer the
* corresponding data to the target vector.
* @param startIndex start position of the split in source vector.
* @param length length of the split.
* @param target destination vector
*/
public void splitAndTransferTo(int startIndex, int length,
BaseFixedWidthVector target) {
compareTypes(target, "splitAndTransferTo");
target.clear();
splitAndTransferValidityBuffer(startIndex, length, target);
splitAndTransferValueBuffer(startIndex, length, target);
target.setValueCount(length);
}
/**
* Data buffer can always be split and transferred using slicing.
*/
private void splitAndTransferValueBuffer(int startIndex, int length,
BaseFixedWidthVector target) {
final int startPoint = startIndex * typeWidth;
final int sliceLength = length * typeWidth;
final ArrowBuf slicedBuffer = valueBuffer.slice(startPoint, sliceLength);
target.valueBuffer = transferBuffer(slicedBuffer, target.allocator);
}
/**
* Validity buffer has multiple cases of split and transfer depending on
* the starting position of the source index.
*/
private void splitAndTransferValidityBuffer(int startIndex, int length,
BaseFixedWidthVector target) {
assert startIndex + length <= valueCount;
int firstByteSource = BitVectorHelper.byteIndex(startIndex);
int lastByteSource = BitVectorHelper.byteIndex(valueCount - 1);
int byteSizeTarget = getValidityBufferSizeFromCount(length);
int offset = startIndex % 8;
if (length > 0) {
if (offset == 0) {
/* slice */
if (target.validityBuffer != null) {
target.validityBuffer.getReferenceManager().release();
}
target.validityBuffer = validityBuffer.slice(firstByteSource, byteSizeTarget);
target.validityBuffer.getReferenceManager().retain(1);
} else {
/* Copy data
* When the first bit starts from the middle of a byte (offset != 0),
* copy data from src BitVector.
* Each byte in the target is composed by a part in i-th byte,
* another part in (i+1)-th byte.
*/
target.allocateValidityBuffer(byteSizeTarget);
for (int i = 0; i < byteSizeTarget - 1; i++) {
byte b1 = BitVectorHelper.getBitsFromCurrentByte(this.validityBuffer,
firstByteSource + i, offset);
byte b2 = BitVectorHelper.getBitsFromNextByte(this.validityBuffer,
firstByteSource + i + 1, offset);
target.validityBuffer.setByte(i, (b1 + b2));
}
/* Copying the last piece is done in the following manner:
* if the source vector has 1 or more bytes remaining, we copy
* the last piece as a byte formed by shifting data
* from the current byte and the next byte.
*
* if the source vector has no more bytes remaining
* (we are at the last byte), we copy the last piece as a byte
* by shifting data from the current byte.
*/
if ((firstByteSource + byteSizeTarget - 1) < lastByteSource) {
byte b1 = BitVectorHelper.getBitsFromCurrentByte(this.validityBuffer,
firstByteSource + byteSizeTarget - 1, offset);
byte b2 = BitVectorHelper.getBitsFromNextByte(this.validityBuffer,
firstByteSource + byteSizeTarget, offset);
target.validityBuffer.setByte(byteSizeTarget - 1, b1 + b2);
} else {
byte b1 = BitVectorHelper.getBitsFromCurrentByte(this.validityBuffer,
firstByteSource + byteSizeTarget - 1, offset);
target.validityBuffer.setByte(byteSizeTarget - 1, b1);
}
}
}
}
/*----------------------------------------------------------------*
| |
| common getters and setters |
| |
*----------------------------------------------------------------*/
/**
* Get the number of elements that are null in the vector.
*
* @return the number of null elements.
*/
@Override
public int getNullCount() {
return BitVectorHelper.getNullCount(validityBuffer, valueCount);
}
/**
* Get the value count of vector. This will always be zero unless
* {@link #setValueCount(int)} has been called prior to calling this.
*
* @return valueCount for the vector
*/
@Override
public int getValueCount() {
return valueCount;
}
/**
* Set value count for the vector.
*
* @param valueCount value count to set
*/
@Override
public void setValueCount(int valueCount) {
this.valueCount = valueCount;
final int currentValueCapacity = getValueCapacity();
while (valueCount > getValueCapacity()) {
reAlloc();
}
/*
* We are trying to understand the pattern of memory allocation.
* If initially, the user did vector.allocateNew(), we would have
* allocated memory of default size (4096 * type width).
* Later on user invokes setValueCount(count).
*
* If the existing value capacity is twice as large as the
* valueCount, we know that we over-provisioned memory in the
* first place when default memory allocation was done because user
* really needs a much less value count in the vector.
*
* We record this by bumping up the allocationMonitor. If this pattern
* happens for certain number of times and allocationMonitor
* reaches the threshold (internal hardcoded) value, subsequent
* call to allocateNew() will take care of stepping down the
* default memory allocation size.
*
* Another case would be under-provisioning the initial memory and
* thus going through a lot of realloc(). Here the goal is to
* see if we can minimize the number of reallocations. Again the
* state is recorded in allocationMonitor by decrementing it
* (negative value). If a threshold is hit, realloc will try to
* allocate more memory in order to possibly avoid a future realloc.
* This case is also applicable to setSafe() methods which can trigger
* a realloc() and thus we record the state there as well.
*/
if (valueCount > 0) {
if (currentValueCapacity >= (valueCount * 2)) {
incrementAllocationMonitor();
} else if (currentValueCapacity <= (valueCount / 2)) {
decrementAllocationMonitor();
}
}
setReaderAndWriterIndex();
}
/**
* Check if the given index is within the current value capacity
* of the vector.
*
* @param index position to check
* @return true if index is within the current value capacity
*/
public boolean isSafe(int index) {
return index < getValueCapacity();
}
/**
* Check if element at given index is null.
*
* @param index position of element
* @return true if element at given index is null, false otherwise
*/
@Override
public boolean isNull(int index) {
return (isSet(index) == 0);
}
/**
* Same as {@link #isNull(int)}.
*
* @param index position of element
* @return 1 if element at given index is not null, 0 otherwise
*/
public int isSet(int index) {
final int byteIndex = index >> 3;
final byte b = validityBuffer.getByte(byteIndex);
final int bitIndex = index & 7;
return (b >> bitIndex) & 0x01;
}
/**
* Mark the particular position in the vector as non-null.
*
* @param index position of the element.
*/
@Override
public void setIndexDefined(int index) {
handleSafe(index);
BitVectorHelper.setValidityBitToOne(validityBuffer, index);
}
public void set(int index, byte[] value, int start, int length) {
throw new UnsupportedOperationException();
}
public void setSafe(int index, byte[] value, int start, int length) {
throw new UnsupportedOperationException();
}
public void set(int index, ByteBuffer value, int start, int length) {
throw new UnsupportedOperationException();
}
public void setSafe(int index, ByteBuffer value, int start, int length) {
throw new UnsupportedOperationException();
}
/*----------------------------------------------------------------*
| |
| helper methods for setters |
| |
*----------------------------------------------------------------*/
protected void handleSafe(int index) {
while (index >= getValueCapacity()) {
decrementAllocationMonitor();
reAlloc();
}
}
/**
* Copy a cell value from a particular index in source vector to a particular
* position in this vector. The source vector should be of the same type as this one.
*
* @param fromIndex position to copy from in source vector
* @param thisIndex position to copy to in this vector
* @param from source vector
*/
@Override
public void copyFrom(int fromIndex, int thisIndex, ValueVector from) {
Preconditions.checkArgument(this.getMinorType() == from.getMinorType());
if (from.isNull(fromIndex)) {
BitVectorHelper.setValidityBit(this.getValidityBuffer(), thisIndex, 0);
} else {
BitVectorHelper.setValidityBit(this.getValidityBuffer(), thisIndex, 1);
PlatformDependent.copyMemory(from.getDataBuffer().memoryAddress() + fromIndex * typeWidth,
this.getDataBuffer().memoryAddress() + thisIndex * typeWidth, typeWidth);
}
}
/**
* Same as {@link #copyFrom(int, int, ValueVector)} except that
* it handles the case when the capacity of the vector needs to be expanded
* before copy.
*
* @param fromIndex position to copy from in source vector
* @param thisIndex position to copy to in this vector
* @param from source vector
*/
@Override
public void copyFromSafe(int fromIndex, int thisIndex, ValueVector from) {
Preconditions.checkArgument(this.getMinorType() == from.getMinorType());
handleSafe(thisIndex);
copyFrom(fromIndex, thisIndex, from);
}
/**
* Set the element at the given index to null.
*
* @param index position of element
*/
public void setNull(int index) {
handleSafe(index);
// not really needed to set the bit to 0 as long as
// the buffer always starts from 0.
BitVectorHelper.setValidityBit(validityBuffer, index, 0);
}
@Override
public ArrowBufPointer getDataPointer(int index) {
return getDataPointer(index, new ArrowBufPointer());
}
@Override
public ArrowBufPointer getDataPointer(int index, ArrowBufPointer reuse) {
if (isNull(index)) {
reuse.set(null, 0, 0);
} else {
reuse.set(valueBuffer, index * typeWidth, typeWidth);
}
return reuse;
}
@Override
public int hashCode(int index) {
int start = typeWidth * index;
int end = typeWidth * (index + 1);
return ByteFunctionHelpers.hash(this.getDataBuffer(), start, end);
}
@Override
public <OUT, IN> OUT accept(VectorVisitor<OUT, IN> visitor, IN value) {
return visitor.visit(this, value);
}
}