/**
* 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.hadoop.hive.ql.exec.vector;
import java.util.Arrays;
/**
* The representation of a vectorized column of multi-valued objects, such
* as lists and maps.
*
* Each object is composed of a range of elements in the underlying child
* ColumnVector. The range for list i is
* offsets[i]..offsets[i]+lengths[i]-1 inclusive.
*/
public abstract class MultiValuedColumnVector extends ColumnVector {
public long[] offsets;
public long[] lengths;
// the number of children slots used
public int childCount;
/**
* Constructor for MultiValuedColumnVector.
*
* @param len Vector length
*/
public MultiValuedColumnVector(int len) {
super(len);
childCount = 0;
offsets = new long[len];
lengths = new long[len];
}
protected abstract void childFlatten(boolean useSelected, int[] selected,
int size);
@Override
public void flatten(boolean selectedInUse, int[] sel, int size) {
flattenPush();
if (isRepeating) {
if (noNulls || !isNull[0]) {
if (selectedInUse) {
for (int i = 0; i < size; ++i) {
int row = sel[i];
offsets[row] = offsets[0];
lengths[row] = lengths[0];
isNull[row] = false;
}
} else {
Arrays.fill(offsets, 0, size, offsets[0]);
Arrays.fill(lengths, 0, size, lengths[0]);
Arrays.fill(isNull, 0, size, false);
}
// We optimize by assuming that a repeating list/map will run from
// from 0 .. lengths[0] in the child vector.
// Sanity check the assumption that we can start at 0.
if (offsets[0] != 0) {
throw new IllegalArgumentException("Repeating offset isn't 0, but " +
offsets[0]);
}
childFlatten(false, null, (int) lengths[0]);
} else {
if (selectedInUse) {
for(int i=0; i < size; ++i) {
isNull[sel[i]] = true;
}
} else {
Arrays.fill(isNull, 0, size, true);
}
}
isRepeating = false;
noNulls = false;
} else {
if (selectedInUse) {
int childSize = 0;
for(int i=0; i < size; ++i) {
childSize += lengths[sel[i]];
}
int[] childSelection = new int[childSize];
int idx = 0;
for(int i=0; i < size; ++i) {
int row = sel[i];
for(int elem=0; elem < lengths[row]; ++elem) {
childSelection[idx++] = (int) (offsets[row] + elem);
}
}
childFlatten(true, childSelection, childSize);
} else {
childFlatten(false, null, childCount);
}
flattenNoNulls(selectedInUse, sel, size);
}
}
@Override
public void ensureSize(int size, boolean preserveData) {
super.ensureSize(size, preserveData);
if (size > offsets.length) {
long[] oldOffsets = offsets;
offsets = new long[size];
long oldLengths[] = lengths;
lengths = new long[size];
if (preserveData) {
if (isRepeating) {
offsets[0] = oldOffsets[0];
lengths[0] = oldLengths[0];
} else {
System.arraycopy(oldOffsets, 0, offsets, 0 , oldOffsets.length);
System.arraycopy(oldLengths, 0, lengths, 0, oldLengths.length);
}
}
}
}
/**
* Initializee the vector
*/
@Override
public void init() {
super.init();
childCount = 0;
}
/**
* Reset the vector for the next batch.
*/
@Override
public void reset() {
super.reset();
childCount = 0;
}
@Override
public void shallowCopyTo(ColumnVector otherCv) {
throw new UnsupportedOperationException(); // Implement in future, if needed.
}
}