package edu.washington.escience.myria.column.builder; import java.nio.BufferOverflowException; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Arrays; import java.util.BitSet; import com.almworks.sqlite4java.SQLiteException; import com.almworks.sqlite4java.SQLiteStatement; import com.google.common.base.Preconditions; import edu.washington.escience.myria.Schema; import edu.washington.escience.myria.Type; import edu.washington.escience.myria.column.BooleanColumn; import edu.washington.escience.myria.column.mutable.BooleanMutableColumn; import edu.washington.escience.myria.proto.DataProto.ColumnMessage; import edu.washington.escience.myria.storage.TupleBatch; import edu.washington.escience.myria.storage.TupleUtils; import edu.washington.escience.myria.util.MyriaUtils; /** * A column of Boolean values. To save space, this implementation uses a BitSet as the internal representation. * */ public final class BooleanColumnBuilder extends ColumnBuilder<Boolean> { /** Internal representation of the column data. */ private final BitSet data; /** Number of valid elements. */ private int numBits; /** * max possible size. * */ private final int capacity; /** * If the builder has built the column. * */ private boolean built = false; /** Constructs an empty column that can hold up to TupleBatch.BATCH_SIZE elements. */ public BooleanColumnBuilder() { data = new BitSet(); numBits = 0; int batchSize = TupleUtils.getBatchSize(Type.BOOLEAN_TYPE); capacity = batchSize; } /** * Copy. * * @param capacity the required capacity * @param data the data * @param numBits numBits * */ private BooleanColumnBuilder(final int capacity, final BitSet data, final int numBits) { this.data = data; this.numBits = numBits; this.capacity = capacity; } /** * Constructs a BooleanColumn by deserializing the given ColumnMessage. * * @param message a ColumnMessage containing the contents of this column. * @param numTuples num tuples in the column message * @return the built column */ public static BooleanColumn buildFromProtobuf(final ColumnMessage message, final int numTuples) { if (message.getType().ordinal() != ColumnMessage.Type.BOOLEAN_VALUE) { throw new IllegalArgumentException( "Trying to construct BooleanColumn from non-BOOLEAN ColumnMessage"); } if (!message.hasBooleanColumn()) { throw new IllegalArgumentException("ColumnMessage has type BOOLEAN but no BooleanColumn"); } BooleanColumnBuilder builder = new BooleanColumnBuilder( numTuples, BitSet.valueOf(message.getBooleanColumn().getData().asReadOnlyByteBuffer()), numTuples); return builder.build(); } @Override public Type getType() { return Type.BOOLEAN_TYPE; } @Override public BooleanColumnBuilder appendBoolean(final boolean value) throws BufferOverflowException { Preconditions.checkArgument( !built, "No further changes are allowed after the builder has built the column."); if (numBits >= TupleUtils.getBatchSize(Type.BOOLEAN_TYPE)) { throw new BufferOverflowException(); } data.set(numBits++, value); return this; } @Deprecated @Override public BooleanColumnBuilder appendObject(final Object value) throws BufferOverflowException { Preconditions.checkArgument( !built, "No further changes are allowed after the builder has built the column."); return appendBoolean((Boolean) MyriaUtils.ensureObjectIsValidType(value)); } @Override public BooleanColumnBuilder appendFromJdbc(final ResultSet resultSet, final int jdbcIndex) throws SQLException, BufferOverflowException { Preconditions.checkArgument( !built, "No further changes are allowed after the builder has built the column."); return appendBoolean(resultSet.getBoolean(jdbcIndex)); } @Override public BooleanColumnBuilder appendFromSQLite(final SQLiteStatement statement, final int index) throws SQLiteException, BufferOverflowException { Preconditions.checkArgument( !built, "No further changes are allowed after the builder has built the column."); return appendBoolean(0 != statement.columnInt(index)); } @Override public int size() { return numBits; } @Override public BooleanColumn build() { built = true; return new BooleanColumn(data, numBits); } @Override public BooleanMutableColumn buildMutable() { built = true; return new BooleanMutableColumn(data, numBits); } @Override public void replaceBoolean(final boolean value, final int row) throws IndexOutOfBoundsException { Preconditions.checkArgument( !built, "No further changes are allowed after the builder has built the column."); Preconditions.checkElementIndex(row, numBits); data.set(row, value); } @Override public BooleanColumnBuilder expand(final int size) throws BufferOverflowException { Preconditions.checkArgument( !built, "No further changes are allowed after the builder has built the column."); Preconditions.checkArgument(size >= 0); if (numBits + size > capacity) { throw new BufferOverflowException(); } numBits = numBits + size; return this; } @Override public BooleanColumnBuilder expandAll() { Preconditions.checkArgument( !built, "No further changes are allowed after the builder has built the column."); numBits = capacity; return this; } @Override @Deprecated public Boolean getObject(final int row) { Preconditions.checkArgument(row >= 0 && row < numBits); return data.get(row); } @Override public boolean getBoolean(final int row) { Preconditions.checkArgument(row >= 0 && row < numBits); return data.get(row); } @Override public BooleanColumnBuilder forkNewBuilder() { return new BooleanColumnBuilder(capacity, BitSet.valueOf(data.toByteArray()), numBits); } }