blob: 02787497aab8a588e59c5c23ee47a4f210dd3e07 [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.
*/
<@pp.dropOutputFile />
<#list vv.types as type>
<#list type.minor as minor>
<#assign friendlyType = (minor.friendlyType!minor.boxedType!type.boxedType) />
<#if type.major == "Fixed">
<@pp.changeOutputFile name="/org/apache/drill/exec/vector/${minor.class}Vector.java" />
<#include "/@includes/license.ftl" />
package org.apache.drill.exec.vector;
<#include "/@includes/vv_imports.ftl" />
<#if minor.class == "Int" || minor.class == "UInt4" || minor.class == "UInt1">
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
</#if>
import org.apache.drill.exec.util.DecimalUtility;
/**
* ${minor.class} implements a vector of fixed width values. Elements in the
* vector are accessed by position, starting from the logical start of the
* vector. Values should be pushed onto the vector sequentially, but may be
* accessed randomly.
* <ul>
* <li>The width of each element is {@link #VALUE_WIDTH} (= ${type.width})
* byte<#if type.width != 1>s</#if>.</li>
* <li>The equivalent Java primitive is '${minor.javaType!type.javaType}'.</li>
* </ul>
*
* NB: this class is automatically generated from ${.template_name} and
* ValueVectorTypes.tdd using FreeMarker.
*/
public final class ${minor.class}Vector extends BaseDataValueVector implements FixedWidthVector {
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(${minor.class}Vector.class);
/**
* Width of each fixed-width value.
*/
public static final int VALUE_WIDTH = ${type.width};
/**
* Maximum number of values that this fixed-width vector can hold
* and stay below the maximum vector size limit. This is the limit
* enforced when the vector is used to hold values in a repeated
* vector.
*/
public static final int MAX_VALUE_COUNT = MAX_BUFFER_SIZE / VALUE_WIDTH;
/**
* Maximum number of values that this fixed-width vector can hold
* and stay below the maximum vector size limit and/or stay below
* the maximum row count. This is the limit enforced when the
* vector is used to hold scalar (required or nullable) values.
* <p>
* Note: <tt>MAX_ROW_COUNT</tt> is defined in the parent <tt>ValueVector</tt>
* class as the maximum number of rows in a record batch (64K). Use this
* in place of the <tt>Character.MAX_SIZE</tt> value previously used.
*/
public static final int MAX_SCALAR_COUNT = Math.min(MAX_ROW_COUNT, MAX_VALUE_COUNT);
/**
* Actual maximum vector size, in bytes, given the number of fixed-width
* values that either fit in the maximum overall vector size, or that
* is no larger than the maximum vector item count.
*/
public static final int NET_MAX_SCALAR_SIZE = VALUE_WIDTH * MAX_SCALAR_COUNT;
private final FieldReader reader = new ${minor.class}ReaderImpl(${minor.class}Vector.this);
private final Accessor accessor = new Accessor();
private final Mutator mutator = new Mutator();
private int allocationSizeInBytes = Math.min(INITIAL_VALUE_ALLOCATION * VALUE_WIDTH, MAX_BUFFER_SIZE);
private int allocationMonitor = 0;
public ${minor.class}Vector(MaterializedField field, BufferAllocator allocator) {
super(field, allocator);
}
@Override
public FieldReader getReader() { return reader; }
@Override
public int getBufferSizeFor(int valueCount) {
if (valueCount == 0) {
return 0;
}
return valueCount * VALUE_WIDTH;
}
@Override
public int getValueCapacity() {
return data.capacity() / VALUE_WIDTH;
}
@Override
public Accessor getAccessor() { return accessor; }
@Override
public Mutator getMutator() { return mutator; }
@Override
public void setInitialCapacity(int valueCount) {
long size = (long) valueCount * VALUE_WIDTH;
// TODO: Replace this with MAX_BUFFER_SIZE once all
// code is aware of the maximum vector size.
if (size > MAX_ALLOCATION_SIZE) {
throw new OversizedAllocationException("Requested amount of memory is more than max allowed allocation size");
}
allocationSizeInBytes = (int) size;
}
@Override
public void allocateNew() {
if (!allocateNewSafe()) {
throw new OutOfMemoryException("Failure while allocating buffer.");
}
}
@Override
public boolean allocateNewSafe() {
long curAllocationSize = allocationSizeInBytes;
if (allocationMonitor > 10) {
curAllocationSize = Math.max(8, curAllocationSize / 2);
allocationMonitor = 0;
} else if (allocationMonitor < -2) {
curAllocationSize = allocationSizeInBytes * 2L;
allocationMonitor = 0;
}
try{
allocateBytes(curAllocationSize);
} catch (DrillRuntimeException ex) {
return false;
}
return true;
}
/**
* Allocate a new buffer that supports setting at least the provided number of
* values. May actually be sized bigger depending on underlying buffer
* rounding size. Must be called prior to using the ValueVector.
*
* Note that the maximum number of values a vector can allocate is
* Integer.MAX_VALUE / value width.
*
* @param valueCount
* @throws OutOfMemoryException
* if it can't allocate the new buffer
*/
@Override
public void allocateNew(int valueCount) {
allocateBytes(valueCount * VALUE_WIDTH);
}
@Override
public void reset() {
allocationSizeInBytes = INITIAL_VALUE_ALLOCATION;
allocationMonitor = 0;
zeroVector();
super.reset();
}
private void allocateBytes(long size) {
// TODO: Replace this with MAX_BUFFER_SIZE once all
// code is aware of the maximum vector size.
if (size > MAX_ALLOCATION_SIZE) {
throw new OversizedAllocationException("Requested amount of memory is more than max allowed allocation size");
}
int curSize = (int)size;
clear();
data = allocator.buffer(curSize);
data.readerIndex(0);
allocationSizeInBytes = curSize;
}
/**
* Allocate new buffer with double capacity, and copy data into the new
* buffer. Replace vector's buffer with new buffer, and release old one
*
* @throws org.apache.drill.exec.memory.OutOfMemoryException
* if it can't allocate the new buffer
*/
public void reAlloc() {
// Avoid an infinite loop if we try to double the size of
// a zero-length buffer. Instead, just allocate a 256 byte
// buffer if we start at 0.
long newAllocationSize = allocationSizeInBytes == 0
? 256
: allocationSizeInBytes * 2L;
int currentCapacity = data.capacity();
// Some operations, such as Value Vector#exchange, can be change DrillBuf data field without corresponding allocation size changes.
// Check that the size of the allocation is sufficient to copy the old buffer.
while (newAllocationSize < currentCapacity) {
newAllocationSize *= 2L;
}
// TODO: Replace this with MAX_BUFFER_SIZE once all
// code is aware of the maximum vector size.
if (newAllocationSize > MAX_ALLOCATION_SIZE) {
throw new OversizedAllocationException("Unable to expand the buffer. Max allowed buffer size is reached.");
}
reallocRaw((int) newAllocationSize);
data.setZero(currentCapacity, data.capacity() - currentCapacity);
}
@Override
public DrillBuf reallocRaw(int newAllocationSize) {
logger.debug("Reallocating vector [{}]. # of bytes: [{}] -> [{}]", field, allocationSizeInBytes, newAllocationSize);
if (newAllocationSize == 0) {
throw new IllegalStateException("Attempt to reAlloc a zero-sized vector");
}
DrillBuf newBuf = allocator.buffer(newAllocationSize);
newBuf.setBytes(0, data, 0, data.capacity());
newBuf.writerIndex(data.writerIndex());
data.release(1);
data = newBuf;
allocationSizeInBytes = newAllocationSize;
return newBuf;
}
/**
* {@inheritDoc}
*/
@Override
public void zeroVector() {
data.setZero(0, data.capacity());
}
@Override
public void load(SerializedField metadata, DrillBuf buffer) {
Preconditions.checkArgument(this.field.getName().equals(metadata.getNamePart().getName()),
"The field %s doesn't match the provided metadata %s.", this.field, metadata);
int actualLength = metadata.getBufferLength();
int valueCount = metadata.getValueCount();
int expectedLength = valueCount * VALUE_WIDTH;
assert actualLength == expectedLength : String.format("Expected to load %d bytes but actually loaded %d bytes", expectedLength, actualLength);
clear();
if (data != null) {
data.release(1);
}
data = buffer.slice(0, actualLength);
data.retain(1);
data.writerIndex(actualLength);
}
@Override
public TransferPair getTransferPair(BufferAllocator allocator) {
return new TransferImpl(getField(), allocator);
}
@Override
public TransferPair getTransferPair(String ref, BufferAllocator allocator) {
return new TransferImpl(getField().withPath(ref), allocator);
}
@Override
public TransferPair makeTransferPair(ValueVector to) {
return new TransferImpl((${minor.class}Vector) to);
}
public void transferTo(${minor.class}Vector target) {
target.clear();
target.data = data.transferOwnership(target.allocator).buffer;
target.data.writerIndex(data.writerIndex());
clear();
}
public void splitAndTransferTo(int startIndex, int length, ${minor.class}Vector target) {
int startPoint = startIndex * VALUE_WIDTH;
int sliceLength = length * VALUE_WIDTH;
target.clear();
target.data = data.slice(startPoint, sliceLength).transferOwnership(target.allocator).buffer;
target.data.writerIndex(sliceLength);
}
@Override
public int getPayloadByteCount(int valueCount) {
return valueCount * ${type.width};
}
@Override
public int getValueWidth() {
return ${type.width};
}
private class TransferImpl implements TransferPair {
private ${minor.class}Vector to;
public TransferImpl(MaterializedField field, BufferAllocator allocator) {
to = new ${minor.class}Vector(field, allocator);
}
public TransferImpl(${minor.class}Vector to) {
this.to = to;
}
@Override
public ${minor.class}Vector getTo() {
return to;
}
@Override
public void transfer() {
transferTo(to);
}
@Override
public void splitAndTransfer(int startIndex, int length) {
splitAndTransferTo(startIndex, length, to);
}
@Override
public void copyValueSafe(int fromIndex, int toIndex) {
to.copyFromSafe(fromIndex, toIndex, ${minor.class}Vector.this);
}
}
public void copyFrom(int fromIndex, int thisIndex, ${minor.class}Vector from) {
<#if (type.width > 8)>
from.data.getBytes(fromIndex * VALUE_WIDTH, data, thisIndex * VALUE_WIDTH, VALUE_WIDTH);
<#else> <#-- type.width <= 8 -->
data.set${(minor.javaType!type.javaType)?cap_first}(thisIndex * VALUE_WIDTH,
from.data.get${(minor.javaType!type.javaType)?cap_first}(fromIndex * VALUE_WIDTH)
);
</#if> <#-- type.width -->
}
public void copyFromSafe(int fromIndex, int thisIndex, ${minor.class}Vector from) {
while(thisIndex >= getValueCapacity()) {
reAlloc();
}
copyFrom(fromIndex, thisIndex, from);
}
@Override
public void copyEntry(int toIndex, ValueVector from, int fromIndex) {
copyFromSafe(fromIndex, toIndex, (${minor.class}Vector) from);
}
public void decrementAllocationMonitor() {
if (allocationMonitor > 0) {
allocationMonitor = 0;
}
--allocationMonitor;
}
private void incrementAllocationMonitor() {
++allocationMonitor;
}
@Override
public void toNullable(ValueVector nullableVector) {
Nullable${minor.class}Vector dest = (Nullable${minor.class}Vector) nullableVector;
dest.getMutator().fromNotNullable(this);
}
public final class Accessor extends BaseDataValueVector.BaseAccessor {
@Override
public int getValueCount() {
return data.writerIndex() / VALUE_WIDTH;
}
@Override
public boolean isNull(int index) {
return false;
}
<#if (type.width > 8)>
public ${minor.javaType!type.javaType} get(int index) {
return data.slice(index * VALUE_WIDTH, VALUE_WIDTH);
}
<#if (minor.class == "Interval")>
public void get(int index, ${minor.class}Holder holder) {
int offsetIndex = index * VALUE_WIDTH;
holder.months = data.getInt(offsetIndex);
holder.days = data.getInt(offsetIndex + ${minor.daysOffset});
holder.milliseconds = data.getInt(offsetIndex + ${minor.millisecondsOffset});
}
public void get(int index, Nullable${minor.class}Holder holder) {
int offsetIndex = index * VALUE_WIDTH;
holder.isSet = 1;
holder.months = data.getInt(offsetIndex);
holder.days = data.getInt(offsetIndex + ${minor.daysOffset});
holder.milliseconds = data.getInt(offsetIndex + ${minor.millisecondsOffset});
}
@Override
public ${friendlyType} getObject(int index) {
int offsetIndex = index * VALUE_WIDTH;
int months = data.getInt(offsetIndex);
int days = data.getInt(offsetIndex + ${minor.daysOffset});
int millis = data.getInt(offsetIndex + ${minor.millisecondsOffset});
return DateUtilities.fromInterval(months, days, millis);
}
public StringBuilder getAsStringBuilder(int index) {
int offsetIndex = index * VALUE_WIDTH;
int months = data.getInt(offsetIndex);
int days = data.getInt(offsetIndex + ${minor.daysOffset});
int millis = data.getInt(offsetIndex + ${minor.millisecondsOffset});
return DateUtilities.intervalStringBuilder(months, days, millis);
}
<#elseif (minor.class == "IntervalDay")>
public void get(int index, ${minor.class}Holder holder) {
int offsetIndex = index * VALUE_WIDTH;
holder.days = data.getInt(offsetIndex);
holder.milliseconds = data.getInt(offsetIndex + ${minor.millisecondsOffset});
}
public void get(int index, Nullable${minor.class}Holder holder) {
int offsetIndex = index * VALUE_WIDTH;
holder.isSet = 1;
holder.days = data.getInt(offsetIndex);
holder.milliseconds = data.getInt(offsetIndex + ${minor.millisecondsOffset});
}
@Override
public ${friendlyType} getObject(int index) {
int offsetIndex = index * VALUE_WIDTH;
int days = data.getInt(offsetIndex);
int millis = data.getInt(offsetIndex + ${minor.millisecondsOffset});
return DateUtilities.fromIntervalDay(days, millis);
}
public StringBuilder getAsStringBuilder(int index) {
int offsetIndex = index * VALUE_WIDTH;
int days = data.getInt(offsetIndex);
int millis = data.getInt(offsetIndex + ${minor.millisecondsOffset});
return DateUtilities.intervalDayStringBuilder(days, millis);
}
<#elseif minor.class == "Decimal28Sparse" || minor.class == "Decimal38Sparse" || minor.class == "Decimal28Dense" || minor.class == "Decimal38Dense">
public void get(int index, ${minor.class}Holder holder) {
holder.start = index * VALUE_WIDTH;
holder.buffer = data;
holder.scale = getField().getScale();
holder.precision = getField().getPrecision();
}
public void get(int index, Nullable${minor.class}Holder holder) {
holder.isSet = 1;
holder.start = index * VALUE_WIDTH;
holder.buffer = data;
holder.scale = getField().getScale();
holder.precision = getField().getPrecision();
}
@Override
public ${friendlyType} getObject(int index) {
<#if (minor.class == "Decimal28Sparse") || (minor.class == "Decimal38Sparse")>
// Get the BigDecimal object
return DecimalUtility.getBigDecimalFromSparse(data, index * VALUE_WIDTH, ${minor.nDecimalDigits}, getField().getScale());
<#else>
return DecimalUtility.getBigDecimalFromDense(data, index * VALUE_WIDTH,
${minor.nDecimalDigits}, getField().getScale(),
${minor.maxPrecisionDigits}, VALUE_WIDTH);
</#if>
}
<#else>
public void get(int index, ${minor.class}Holder holder) {
holder.buffer = data;
holder.start = index * VALUE_WIDTH;
}
public void get(int index, Nullable${minor.class}Holder holder) {
holder.isSet = 1;
holder.buffer = data;
holder.start = index * VALUE_WIDTH;
}
@Override
public ${friendlyType} getObject(int index) {
return data.slice(index * VALUE_WIDTH, VALUE_WIDTH)
}
</#if>
<#else> <#-- type.width <= 8 -->
public ${minor.javaType!type.javaType} get(int index) {
return data.get${(minor.javaType!type.javaType)?cap_first}(index * VALUE_WIDTH);
}
<#if type.width == 4>
public long getTwoAsLong(int index) {
return data.getLong(index * VALUE_WIDTH);
}
</#if>
<#if minor.class == "Date">
@Override
public ${friendlyType} getObject(int index) {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(get(index)), ZoneOffset.UTC).toLocalDate();
}
<#elseif minor.class == "TimeStamp">
@Override
public ${friendlyType} getObject(int index) {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(get(index)), ZoneOffset.UTC);
}
<#elseif minor.class == "IntervalYear">
@Override
public ${friendlyType} getObject(int index) {
return DateUtilities.fromIntervalYear(get(index));
}
public StringBuilder getAsStringBuilder(int index) {
int value = get(index);
return DateUtilities.intervalYearStringBuilder(value);
}
<#elseif minor.class == "Time">
@Override
public ${friendlyType} getObject(int index) {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(get(index)), ZoneOffset.UTC).toLocalTime();
}
<#elseif minor.class == "Decimal9" || minor.class == "Decimal18">
@Override
public ${friendlyType} getObject(int index) {
BigInteger value = BigInteger.valueOf(((${type.boxedType})get(index)).${type.javaType}Value());
return new BigDecimal(value, getField().getScale());
}
<#else>
@Override
public ${friendlyType} getObject(int index) {
return get(index);
}
public ${minor.javaType!type.javaType} getPrimitiveObject(int index) {
return get(index);
}
</#if>
public void get(int index, ${minor.class}Holder holder) {
<#if minor.class.startsWith("Decimal")>
holder.scale = getField().getScale();
holder.precision = getField().getPrecision();
</#if>
holder.value = data.get${(minor.javaType!type.javaType)?cap_first}(index * VALUE_WIDTH);
}
public void get(int index, Nullable${minor.class}Holder holder) {
holder.isSet = 1;
holder.value = data.get${(minor.javaType!type.javaType)?cap_first}(index * VALUE_WIDTH);
}
</#if> <#-- type.width -->
}
/**
* ${minor.class}.Mutator implements a mutable vector of fixed width values.
* Elements in the vector are accessed by position from the logical start of
* the vector. Values should be pushed onto the vector sequentially, but may
* be randomly accessed.
* <ul>
* <li>The width of each element is {@link #VALUE_WIDTH} (= ${type.width})
* byte(s).</li>
* <li>The equivalent Java primitive is '${minor.javaType!type.javaType}'</li>
* </ul>
*
* NB: this class is automatically generated from ValueVectorTypes.tdd using
* FreeMarker.
*/
public final class Mutator extends BaseDataValueVector.BaseMutator {
private Mutator() {};
/**
* Set the element at the given index to the given value. Note that widths
* smaller than 32 bits are handled by the DrillBuf interface.
*
* @param index
* position of the bit to set
* @param value
* value to set
*/
<#if (type.width > 8)>
public void set(int index, <#if (type.width > 4)>${minor.javaType!type.javaType}<#else>int</#if> value) {
data.setBytes(index * VALUE_WIDTH, value, 0, VALUE_WIDTH);
}
public void setSafe(int index, <#if (type.width > 4)>${minor.javaType!type.javaType}<#else>int</#if> value) {
while(index >= getValueCapacity()) {
reAlloc();
}
data.setBytes(index * VALUE_WIDTH, value, 0, VALUE_WIDTH);
}
<#if minor.class == "Interval">
public void set(int index, int months, int days, int milliseconds) {
final int offsetIndex = index * VALUE_WIDTH;
data.setInt(offsetIndex, months);
data.setInt((offsetIndex + ${minor.daysOffset}), days);
data.setInt((offsetIndex + ${minor.millisecondsOffset}), milliseconds);
}
public void setSafe(int index, int months, int days, int milliseconds) {
while(index >= getValueCapacity()) {
reAlloc();
}
set(index, months, days, milliseconds);
}
protected void set(int index, ${minor.class}Holder holder) {
set(index, holder.months, holder.days, holder.milliseconds);
}
public void setSafe(int index, ${minor.class}Holder holder) {
setSafe(index, holder.months, holder.days, holder.milliseconds);
}
protected void set(int index, Nullable${minor.class}Holder holder) {
set(index, holder.months, holder.days, holder.milliseconds);
}
public void setSafe(int index, Nullable${minor.class}Holder holder) {
setSafe(index, holder.months, holder.days, holder.milliseconds);
}
<#elseif minor.class == "IntervalDay">
public void set(int index, int days, int milliseconds) {
final int offsetIndex = index * VALUE_WIDTH;
data.setInt(offsetIndex, days);
data.setInt((offsetIndex + ${minor.millisecondsOffset}), milliseconds);
}
public void setSafe(int index, int days, int milliseconds) {
while(index >= getValueCapacity()) {
reAlloc();
}
set(index, days, milliseconds);
}
protected void set(int index, ${minor.class}Holder holder) {
set(index, holder.days, holder.milliseconds);
}
public void setSafe(int index, ${minor.class}Holder holder) {
setSafe(index, holder.days, holder.milliseconds);
}
protected void set(int index, Nullable${minor.class}Holder holder) {
set(index, holder.days, holder.milliseconds);
}
public void setSafe(int index, Nullable${minor.class}Holder holder) {
setSafe(index, holder.days, holder.milliseconds);
}
<#elseif minor.class == "Decimal28Sparse" || minor.class == "Decimal38Sparse" || minor.class == "Decimal28Dense" || minor.class == "Decimal38Dense">
public void setSafe(int index, int start, DrillBuf buffer) {
while(index >= getValueCapacity()) {
reAlloc();
}
set(index, start, buffer);
}
public void set(int index, ${minor.class}Holder holder) {
set(index, holder.start, holder.buffer);
}
public void setSafe(int index, ${minor.class}Holder holder) {
setSafe(index, holder.start, holder.buffer);
}
void set(int index, Nullable${minor.class}Holder holder) {
set(index, holder.start, holder.buffer);
}
public void setSafe(int index, Nullable${minor.class}Holder holder) {
setSafe(index, holder.start, holder.buffer);
}
<#if minor.class == "Decimal28Sparse" || minor.class == "Decimal38Sparse">
public void set(int index, BigDecimal value) {
DecimalUtility.getSparseFromBigDecimal(value, data, index * VALUE_WIDTH,
field.getScale(), ${minor.nDecimalDigits});
}
public void setSafe(int index, BigDecimal value) {
while(index >= getValueCapacity()) {
reAlloc();
}
set(index, value);
}
</#if>
public void set(int index, int start, DrillBuf buffer) {
data.setBytes(index * VALUE_WIDTH, buffer, start, VALUE_WIDTH);
}
</#if>
@Override
public void generateTestData(int count) {
setValueCount(count);
boolean even = true;
final int valueCount = getAccessor().getValueCount();
for(int i = 0; i < valueCount; i++, even = !even) {
final byte b = even ? Byte.MIN_VALUE : Byte.MAX_VALUE;
for(int w = 0; w < VALUE_WIDTH; w++) {
data.setByte(i + w, b);
}
}
}
<#else> <#-- type.width <= 8 -->
public void set(int index, <#if (type.width >= 4)>${minor.javaType!type.javaType}<#else>int</#if> value) {
data.set${(minor.javaType!type.javaType)?cap_first}(index * VALUE_WIDTH, value);
}
<#if (type.width == 1)>
public void set(int index, byte[] values, int startOff, int len) {
data.setBytes(index * VALUE_WIDTH, values, startOff, len);
}
</#if>
/**
* Set the value of a required or nullable vector. Grows the vector as needed.
* Does not enforce size limits; scalar fixed-width types can never overflow
* a vector.
* @param index item to write
*/
public void setSafe(int index, <#if (type.width >= 4)>${minor.javaType!type.javaType}<#else>int</#if> value) {
while(index >= getValueCapacity()) {
reAlloc();
}
set(index, value);
}
protected void set(int index, ${minor.class}Holder holder) {
data.set${(minor.javaType!type.javaType)?cap_first}(index * VALUE_WIDTH, holder.value);
}
public void setSafe(int index, ${minor.class}Holder holder) {
while(index >= getValueCapacity()) {
reAlloc();
}
set(index, holder);
}
protected void set(int index, Nullable${minor.class}Holder holder) {
data.set${(minor.javaType!type.javaType)?cap_first}(index * VALUE_WIDTH, holder.value);
}
public void setSafe(int index, Nullable${minor.class}Holder holder) {
while(index >= getValueCapacity()) {
reAlloc();
}
set(index, holder);
}
@Override
public void generateTestData(int size) {
setValueCount(size);
boolean even = true;
final int valueCount = getAccessor().getValueCount();
for(int i = 0; i < valueCount; i++, even = !even) {
if(even) {
set(i, ${minor.boxedType!type.boxedType}.MIN_VALUE);
} else {
set(i, ${minor.boxedType!type.boxedType}.MAX_VALUE);
}
}
}
public void generateTestDataAlt(int size) {
setValueCount(size);
boolean even = true;
final int valueCount = getAccessor().getValueCount();
for(int i = 0; i < valueCount; i++, even = !even) {
if(even) {
set(i, (${(minor.javaType!type.javaType)}) 1);
} else {
set(i, (${(minor.javaType!type.javaType)}) 0);
}
}
}
</#if> <#-- type.width -->
@Override
public void setValueCount(int valueCount) {
final int currentValueCapacity = getValueCapacity();
final int idx = VALUE_WIDTH * valueCount;
while(valueCount > getValueCapacity()) {
reAlloc();
}
if (valueCount > 0 && currentValueCapacity > valueCount * 2) {
incrementAllocationMonitor();
} else if (allocationMonitor > 0) {
allocationMonitor = 0;
}
data.writerIndex(idx);
}
}
<#if minor.class == "Int" || minor.class == "UInt4" || minor.class == "UInt1">
/**
* Helper class to buffer container mutation as a means to optimize native memory copy operations.
*
* NB: this class is automatically generated from ValueVectorTypes.tdd using FreeMarker.
*/
public static final class BufferedMutator {
/** The default buffer size */
private static final int DEFAULT_BUFF_SZ = 1024 << 2;
/** Byte buffer */
private final ByteBuffer buffer;
/** Tracks the index where to copy future values */
private int currentIdx;
/** Parent conatiner object */
private final ${minor.class}Vector parent;
/** @see {@link #BufferedMutator(int startIdx, int buffSz, ${minor.class}Vector parent)} */
public BufferedMutator(int startIdx, ${minor.class}Vector parent) {
this(startIdx, DEFAULT_BUFF_SZ, parent);
}
/**
* Buffered mutator to optimize bulk access to the underlying vector container
* @param startIdx start idex of the first value to be copied
* @param buffSz buffer length to us
* @param parent parent container object
*/
public BufferedMutator(int startIdx, int buffSz, ${minor.class}Vector parent) {
this.buffer = ByteBuffer.allocate(buffSz);
// set the buffer to the native byte order
buffer.order(ByteOrder.nativeOrder());
this.currentIdx = startIdx;
this.parent = parent;
}
<#if minor.class == "Int" || minor.class == "UInt4">
public void setSafe(int value) {
if (buffer.remaining() < 4) {
flush();
}
int tgtPos = buffer.position();
byte[] bufferArray = buffer.array();
writeInt(value, bufferArray, tgtPos);
buffer.position(tgtPos + 4);
}
public void setSafe(int[] values, int numValues) {
int remaining = numValues;
byte[] bufferArray = buffer.array();
int srcPos = 0;
do {
if (buffer.remaining() < 4) {
flush();
}
int toCopy = Math.min(remaining, buffer.remaining() / 4);
int tgtPos = buffer.position();
for (int idx = 0; idx < toCopy; idx++, tgtPos += 4, srcPos++) {
writeInt(values[srcPos], bufferArray, tgtPos);
}
// Update counters
buffer.position(tgtPos);
remaining -= toCopy;
} while (remaining > 0);
}
public static final void writeInt(int val, byte[] buffer, int pos) {
DrillBuf.putInt(buffer, pos, val);
}
</#if> <#-- minor.class -->
<#if minor.class == "UInt1">
public void setSafe(byte value) {
if (buffer.remaining() < 1) {
flush();
}
buffer.put(value);
}
public void setSafe(byte[] values, int numValues) {
int remaining = numValues;
byte[] bufferArray = buffer.array();
int srcPos = 0;
do {
if (buffer.remaining() < 1) {
flush();
}
int toCopy = Math.min(remaining, buffer.remaining());
int tgtPos = buffer.position();
for (int idx = 0; idx < toCopy; idx++) {
bufferArray[tgtPos++] = values[srcPos++];
}
// Update counters
buffer.position(tgtPos);
remaining -= toCopy;
} while (remaining > 0);
}
</#if> <#-- minor.class -->
/**
* @return the backing byte buffer; this is useful when the caller can infer the values to write but
* wants to avoid having to use yet another intermediary byte array; caller is responsible for
* flushing the buffer
*/
public ByteBuffer getByteBuffer() {
return buffer;
}
public void flush() {
int numElements = buffer.position() / ${minor.class}Vector.VALUE_WIDTH;
if (numElements == 0) {
return; // NOOP
}
while((currentIdx + numElements -1) >= parent.getValueCapacity()) {
parent.reAlloc();
}
parent.data.setBytes(currentIdx * ${minor.class}Vector.VALUE_WIDTH, buffer.array(), 0, buffer.position());
// Update the start index
currentIdx += numElements;
// Reset the byte buffer
buffer.clear();
}
}
</#if> <#-- minor.class -->
}
</#if> <#-- type.major -->
</#list>
</#list>