io.deephaven.engine.table.impl.hierarchical.RollupNodeKeySource Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of deephaven-engine-table Show documentation
Show all versions of deephaven-engine-table Show documentation
Engine Table: Implementation and closely-coupled utilities
/**
* Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending
*/
package io.deephaven.engine.table.impl.hierarchical;
import io.deephaven.chunk.*;
import io.deephaven.chunk.attributes.Values;
import io.deephaven.engine.rowset.RowSequence;
import io.deephaven.engine.table.*;
import io.deephaven.engine.table.impl.DefaultChunkSource;
import io.deephaven.engine.table.impl.by.AggregationRowLookup;
import io.deephaven.engine.table.impl.chunkboxer.ChunkBoxer;
import io.deephaven.engine.table.impl.sources.ReinterpretUtils;
import io.deephaven.util.SafeCloseable;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import static io.deephaven.engine.table.impl.by.AggregationRowLookup.EMPTY_KEY;
/**
* {@link ChunkSource} that produces rollup {@link AggregationRowLookup} keys from multiple {@link ColumnSource
* sources}, with special handling for the "root" node key.
*/
final class RollupNodeKeySource implements DefaultChunkSource.WithPrev {
/**
* Special sentinel node key that marks the root of a {@link RollupTableImpl}, at depth 0.
*/
static final Object ROOT_NODE_KEY = new Object();
/**
* The root node exists at depth 0, but by definition its always visited as an expanded node or not at all. For all
* other nodes, the node key width is (depth - 1).
*/
static final int ROOT_NODE_DEPTH = 0;
private final ColumnSource depthSource;
private final ColumnSource>[] groupByValueSources;
private final int maxMaxKeyWidth;
private final int maxDepth;
/**
* Construct a new RollupNodeKeySource backed by the supplied column sources.
*
* @param depthSource A source of {@code int} depths that determines how many of the {@code groupByValueSources}
* should have their values included in the result
* @param groupByValueSources Sources corresponding to the aggregation group-by values in the rollup
*/
RollupNodeKeySource(
@NotNull final ColumnSource depthSource,
@NotNull final ColumnSource>... groupByValueSources) {
this.depthSource = depthSource;
this.groupByValueSources = Stream.of(groupByValueSources)
.map(ReinterpretUtils::maybeConvertToPrimitive).toArray(ColumnSource[]::new);
maxMaxKeyWidth = groupByValueSources.length;
maxDepth = maxMaxKeyWidth + 1;
}
@Override
public ChunkType getChunkType() {
return ChunkType.Object;
}
@Override
public void fillChunk(
@NotNull final ChunkSource.FillContext context,
@NotNull final WritableChunk super Values> destination,
@NotNull final RowSequence rowSequence) {
fillChunkInternal(context, destination, rowSequence, false);
}
public void fillPrevChunk(
@NotNull final ChunkSource.FillContext context,
@NotNull final WritableChunk super Values> destination,
@NotNull final RowSequence rowSequence) {
fillChunkInternal(context, destination, rowSequence, true);
}
private void fillChunkInternal(
@NotNull final ChunkSource.FillContext context,
@NotNull final WritableChunk super Values> destination,
@NotNull final RowSequence rowSequence,
final boolean usePrev) {
if (rowSequence.isEmpty()) {
destination.setSize(0);
return;
}
final FillContext fc = (FillContext) context;
final IntChunk extends Values> depths = usePrev
? depthSource.getPrevChunk(fc.depthContext, rowSequence).asIntChunk()
: depthSource.getChunk(fc.depthContext, rowSequence).asIntChunk();
final int maxKeyWidth = getMaxKeyWidth(depths, maxMaxKeyWidth);
final ObjectChunk, ? extends Values>[] groupByValues =
getGroupByValuesChunks(fc, rowSequence, usePrev, maxKeyWidth);
fillFromGroupByValues(rowSequence, depths, groupByValues, destination.asWritableObjectChunk());
}
private static int getMaxKeyWidth(@NotNull final IntChunk extends Values> depths, final int maxMaxKeyWidth) {
final int size = depths.size();
int maxKeyWidth = 0;
for (int kwi = 0; kwi < size; ++kwi) {
// Key width is (depth - 1). No need to special case the root, since the implied key width of -1 is less
// than 0.
final int keyWidth = depths.get(kwi) - 1;
if (keyWidth >= maxMaxKeyWidth) {
return maxMaxKeyWidth;
}
if (keyWidth > maxKeyWidth) {
maxKeyWidth = keyWidth;
}
}
return maxKeyWidth;
}
private ObjectChunk, ? extends Values>[] getGroupByValuesChunks(
@NotNull final FillContext fillContext,
@NotNull final RowSequence rowSequence,
final boolean usePrev,
final int maxKeyWidth) {
// noinspection unchecked
final ObjectChunk, ? extends Values>[] groupByValuesChunks = new ObjectChunk[maxKeyWidth];
for (int ci = 0; ci < maxKeyWidth; ++ci) {
groupByValuesChunks[ci] = fillContext.groupByValueBoxers[ci].box(usePrev
? groupByValueSources[ci].getPrevChunk(fillContext.groupByValueContexts[ci], rowSequence)
: groupByValueSources[ci].getChunk(fillContext.groupByValueContexts[ci], rowSequence));
}
return groupByValuesChunks;
}
private void fillFromGroupByValues(
@NotNull final RowSequence rowSequence,
@NotNull final IntChunk extends Values> depths,
@NotNull final ObjectChunk, ? extends Values>[] groupByValues,
@NotNull final WritableObjectChunk
© 2015 - 2024 Weber Informatics LLC | Privacy Policy