diff --git a/src/main/java/jp/co/yahoo/yosegi/binary/ColumnBinaryMakerConfig.java b/src/main/java/jp/co/yahoo/yosegi/binary/ColumnBinaryMakerConfig.java
index 6553d6ee..f9647c9f 100644
--- a/src/main/java/jp/co/yahoo/yosegi/binary/ColumnBinaryMakerConfig.java
+++ b/src/main/java/jp/co/yahoo/yosegi/binary/ColumnBinaryMakerConfig.java
@@ -20,6 +20,7 @@
import jp.co.yahoo.yosegi.binary.maker.DumpSpreadColumnBinaryMaker;
import jp.co.yahoo.yosegi.binary.maker.DumpUnionColumnBinaryMaker;
+import jp.co.yahoo.yosegi.binary.maker.FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker;
import jp.co.yahoo.yosegi.binary.maker.IColumnBinaryMaker;
import jp.co.yahoo.yosegi.binary.maker.MaxLengthBasedArrayColumnBinaryMaker;
import jp.co.yahoo.yosegi.binary.maker.OptimizedNullArrayDumpBooleanColumnBinaryMaker;
@@ -89,7 +90,7 @@ public ColumnBinaryMakerConfig() throws IOException {
spreadMakerClass = FindColumnBinaryMaker.get( DumpSpreadColumnBinaryMaker.class.getName() );
booleanMakerClass = FindColumnBinaryMaker.get(
- OptimizedNullArrayDumpBooleanColumnBinaryMaker.class.getName() );
+ FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker.class.getName() );
byteMakerClass = FindColumnBinaryMaker.get(
OptimizedNullArrayDumpLongColumnBinaryMaker.class.getName() );
doubleMakerClass = FindColumnBinaryMaker.get(
diff --git a/src/main/java/jp/co/yahoo/yosegi/binary/ColumnBinaryMakerNameShortCut.java b/src/main/java/jp/co/yahoo/yosegi/binary/ColumnBinaryMakerNameShortCut.java
index 18abeda6..40aeacf6 100644
--- a/src/main/java/jp/co/yahoo/yosegi/binary/ColumnBinaryMakerNameShortCut.java
+++ b/src/main/java/jp/co/yahoo/yosegi/binary/ColumnBinaryMakerNameShortCut.java
@@ -104,6 +104,9 @@ public final class ColumnBinaryMakerNameShortCut {
"jp.co.yahoo.yosegi.binary.maker.OptimizedNullArrayDumpBooleanColumnBinaryMaker" , "ND5" );
CLASS_NAME_PAIR.set(
"jp.co.yahoo.yosegi.binary.maker.OptimizedNullArrayDumpBytesColumnBinaryMaker" , "ND6" );
+ CLASS_NAME_PAIR.set(
+ "jp.co.yahoo.yosegi.binary.maker.FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker",
+ "ND7");
CLASS_NAME_PAIR.set(
"jp.co.yahoo.yosegi.binary.maker.OptimizedNullArrayFloatColumnBinaryMaker" , "N1" );
diff --git a/src/main/java/jp/co/yahoo/yosegi/binary/maker/FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker.java b/src/main/java/jp/co/yahoo/yosegi/binary/maker/FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker.java
new file mode 100644
index 00000000..cff660d7
--- /dev/null
+++ b/src/main/java/jp/co/yahoo/yosegi/binary/maker/FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker.java
@@ -0,0 +1,306 @@
+/**
+ * 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 jp.co.yahoo.yosegi.binary.maker;
+
+import jp.co.yahoo.yosegi.binary.ColumnBinary;
+import jp.co.yahoo.yosegi.binary.ColumnBinaryMakerConfig;
+import jp.co.yahoo.yosegi.binary.ColumnBinaryMakerCustomConfigNode;
+import jp.co.yahoo.yosegi.binary.CompressResultNode;
+import jp.co.yahoo.yosegi.binary.maker.index.FlagBooleanIndex;
+import jp.co.yahoo.yosegi.blockindex.BlockIndexNode;
+import jp.co.yahoo.yosegi.blockindex.BooleanBlockIndex;
+import jp.co.yahoo.yosegi.compressor.CompressResult;
+import jp.co.yahoo.yosegi.compressor.FindCompressor;
+import jp.co.yahoo.yosegi.compressor.ICompressor;
+import jp.co.yahoo.yosegi.inmemory.IMemoryAllocator;
+import jp.co.yahoo.yosegi.message.objects.BooleanObj;
+import jp.co.yahoo.yosegi.message.objects.PrimitiveObject;
+import jp.co.yahoo.yosegi.spread.analyzer.IColumnAnalizeResult;
+import jp.co.yahoo.yosegi.spread.column.ColumnType;
+import jp.co.yahoo.yosegi.spread.column.ICell;
+import jp.co.yahoo.yosegi.spread.column.IColumn;
+import jp.co.yahoo.yosegi.spread.column.PrimitiveCell;
+import jp.co.yahoo.yosegi.spread.column.PrimitiveColumn;
+import jp.co.yahoo.yosegi.util.io.nullencoder.NullBinaryEncoder;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker
+ implements IColumnBinaryMaker {
+
+ private static final BooleanObj TRUE = new BooleanObj(true);
+ private static final BooleanObj FALSE = new BooleanObj(false);
+
+ // Metadata layout
+ // ColumnStart, nullLength
+ private static final int META_LENGTH = Integer.BYTES * 2;
+
+ private static byte[] decompressBinary(final ColumnBinary columnBinary) throws IOException {
+ int start = columnBinary.binaryStart + BooleanBlockIndex.BitFlags.LENGTH;
+ int length = columnBinary.binaryLength - BooleanBlockIndex.BitFlags.LENGTH;
+ ICompressor compressor = FindCompressor.get(columnBinary.compressorClassName);
+ return compressor.decompress(columnBinary.binary, start, length);
+ }
+
+ private BooleanBlockIndex.BitFlags getBitFlags(final ColumnBinary columnBinary) {
+ ByteBuffer wrapBuffer =
+ ByteBuffer.wrap(
+ columnBinary.binary, columnBinary.binaryStart, BooleanBlockIndex.BitFlags.LENGTH);
+ // bitFlags: 001:hasTrue, 010:hasFalse, 100:hasNull
+ byte flags = wrapBuffer.get();
+ return new BooleanBlockIndex.BitFlags(flags);
+ }
+
+ @Override
+ public ColumnBinary toBinary(
+ final ColumnBinaryMakerConfig commonConfig,
+ final ColumnBinaryMakerCustomConfigNode currentConfigNode,
+ final CompressResultNode compressResultNode,
+ final IColumn column)
+ throws IOException {
+ ColumnBinaryMakerConfig currentConfig = commonConfig;
+ if (currentConfigNode != null) {
+ currentConfig = currentConfigNode.getCurrentConfig();
+ }
+
+ boolean[] isTrueArray = new boolean[column.size()];
+ int trueCount = 0;
+ int trueMax = 0;
+ int falseMax = 0;
+ boolean[] isNullArray = new boolean[column.size()];
+ int rowCount = 0;
+ int nullCount = 0;
+ int nullMaxIndex = 0;
+ int notNullMaxIndex = 0;
+
+ int startIndex = 0;
+ for (; startIndex < column.size(); startIndex++) {
+ ICell cell = column.get(startIndex);
+ if (cell.getType() != ColumnType.NULL) {
+ break;
+ }
+ }
+
+ for (int i = startIndex, nullIndex = 0; i < column.size(); i++, nullIndex++) {
+ ICell cell = column.get(i);
+ if (cell.getType() == ColumnType.NULL) {
+ nullCount++;
+ nullMaxIndex = nullIndex;
+ isNullArray[nullIndex] = true;
+ continue;
+ }
+ isTrueArray[rowCount] = ((PrimitiveCell) cell).getRow().getBoolean();
+ if (isTrueArray[rowCount]) {
+ trueCount++;
+ trueMax = rowCount;
+ } else {
+ falseMax = rowCount;
+ }
+
+ notNullMaxIndex = nullIndex;
+ rowCount++;
+ }
+
+ int nullLength =
+ NullBinaryEncoder.getBinarySize(nullCount, rowCount, nullMaxIndex, notNullMaxIndex);
+ int isTrueLength =
+ NullBinaryEncoder.getBinarySize(trueCount, rowCount - trueCount, trueMax, falseMax);
+
+ int binaryLength = META_LENGTH + nullLength + isTrueLength;
+ byte[] binaryRaw = new byte[binaryLength];
+ ByteBuffer wrapBuffer = ByteBuffer.wrap(binaryRaw, 0, binaryRaw.length);
+ wrapBuffer.putInt(startIndex);
+ wrapBuffer.putInt(nullLength);
+
+ NullBinaryEncoder.toBinary(
+ binaryRaw,
+ META_LENGTH,
+ nullLength,
+ isNullArray,
+ nullCount,
+ rowCount,
+ nullMaxIndex,
+ notNullMaxIndex);
+
+ NullBinaryEncoder.toBinary(
+ binaryRaw,
+ META_LENGTH + nullLength,
+ isTrueLength,
+ isTrueArray,
+ trueCount,
+ rowCount - trueCount,
+ trueMax,
+ falseMax);
+
+ CompressResult compressResult =
+ compressResultNode.getCompressResult(
+ this.getClass().getName(),
+ "c0",
+ currentConfig.compressionPolicy,
+ currentConfig.allowedRatio);
+ byte[] compressBinary =
+ currentConfig.compressorClass.compress(binaryRaw, 0, binaryRaw.length, compressResult);
+
+ byte[] binary = new byte[BooleanBlockIndex.BitFlags.LENGTH + compressBinary.length];
+ wrapBuffer = ByteBuffer.wrap(binary, 0, binary.length);
+
+ BooleanBlockIndex.BitFlags bitFlags =
+ new BooleanBlockIndex.BitFlags(
+ trueCount > 0, (rowCount - trueCount) > 0, startIndex > 0 || nullCount > 0);
+ wrapBuffer.put(bitFlags.getBitFlags());
+ wrapBuffer.put(compressBinary);
+
+ return new ColumnBinary(
+ this.getClass().getName(),
+ currentConfig.compressorClass.getClass().getName(),
+ column.getColumnName(),
+ ColumnType.BOOLEAN,
+ column.size(),
+ binaryRaw.length,
+ Byte.BYTES * rowCount,
+ -1,
+ binary,
+ 0,
+ binary.length,
+ null);
+ }
+
+ @Override
+ public int calcBinarySize(final IColumnAnalizeResult analizeResult) {
+ return analizeResult.getColumnSize();
+ }
+
+ @Override
+ public IColumn toColumn(final ColumnBinary columnBinary) throws IOException {
+ BooleanBlockIndex.BitFlags bitFlags = getBitFlags(columnBinary);
+
+ return new HeaderIndexLazyColumn(
+ columnBinary.columnName,
+ columnBinary.columnType,
+ new BooleanColumnManager(columnBinary),
+ new FlagBooleanIndex(bitFlags.hasTrue(), bitFlags.hasFalse(), bitFlags.hasNull()));
+ }
+
+ @Override
+ public void loadInMemoryStorage(final ColumnBinary columnBinary, final IMemoryAllocator allocator)
+ throws IOException {
+ byte[] binary =
+ FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker.decompressBinary(columnBinary);
+ ByteBuffer wrapBuffer = ByteBuffer.wrap(binary, 0, binary.length);
+ int startIndex = wrapBuffer.getInt();
+ int nullLength = wrapBuffer.getInt();
+ int isTrueLength = binary.length - META_LENGTH - nullLength;
+
+ boolean[] isNullArray = NullBinaryEncoder.toIsNullArray(binary, META_LENGTH, nullLength);
+
+ allocator.setValueCount(startIndex + isNullArray.length);
+
+ boolean[] isTrueArray =
+ NullBinaryEncoder.toIsNullArray(binary, META_LENGTH + nullLength, isTrueLength);
+
+ for (int i = 0; i < startIndex; i++) {
+ allocator.setNull(i);
+ }
+ int isTrueIndex = 0;
+ for (int i = 0; i < isNullArray.length; i++) {
+ if (isNullArray[i]) {
+ allocator.setNull(i + startIndex);
+ } else {
+ allocator.setBoolean(i + startIndex, isTrueArray[isTrueIndex]);
+ isTrueIndex++;
+ }
+ }
+ }
+
+ @Override
+ public void setBlockIndexNode(
+ final BlockIndexNode parentNode, final ColumnBinary columnBinary, final int spreadIndex)
+ throws IOException {
+ BooleanBlockIndex.BitFlags bitFlags = getBitFlags(columnBinary);
+
+ BlockIndexNode currentNode = parentNode.getChildNode(columnBinary.columnName);
+ currentNode.setBlockIndex(
+ new BooleanBlockIndex(bitFlags.hasTrue(), bitFlags.hasFalse(), bitFlags.hasNull()));
+ }
+
+ public class BooleanColumnManager implements IColumnManager {
+
+ private final ColumnBinary columnBinary;
+ private PrimitiveColumn column;
+ private boolean isCreate;
+
+ public BooleanColumnManager(final ColumnBinary columnBinary) throws IOException {
+ this.columnBinary = columnBinary;
+ }
+
+ private void create() throws IOException {
+ if (isCreate) {
+ return;
+ }
+ byte[] binary =
+ FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker.decompressBinary(columnBinary);
+ ByteBuffer wrapBuffer = ByteBuffer.wrap(binary, 0, binary.length);
+ int startIndex = wrapBuffer.getInt();
+ int nullLength = wrapBuffer.getInt();
+ int isTrueLength = binary.length - META_LENGTH - nullLength;
+
+ boolean[] isNullArray = NullBinaryEncoder.toIsNullArray(binary, META_LENGTH, nullLength);
+
+ boolean[] isTrueArray =
+ NullBinaryEncoder.toIsNullArray(binary, META_LENGTH + nullLength, isTrueLength);
+
+ PrimitiveObject[] valueArray = new PrimitiveObject[isNullArray.length];
+
+ int isTrueIndex = 0;
+ for (int i = 0; i < isNullArray.length; i++) {
+ if (!isNullArray[i]) {
+ valueArray[i] = (isTrueArray[isTrueIndex]) ? TRUE : FALSE;
+ isTrueIndex++;
+ }
+ }
+
+ column = new PrimitiveColumn(columnBinary.columnType, columnBinary.columnName);
+ column.setCellManager(
+ new OptimizedNullArrayCellManager(columnBinary.columnType, startIndex, valueArray));
+
+ isCreate = true;
+ }
+
+ @Override
+ public IColumn get() {
+ try {
+ create();
+ } catch (IOException ex) {
+ throw new UncheckedIOException(ex);
+ }
+ return column;
+ }
+
+ @Override
+ public List getColumnKeys() {
+ return new ArrayList();
+ }
+
+ @Override
+ public int getColumnSize() {
+ return 0;
+ }
+ }
+}
diff --git a/src/main/java/jp/co/yahoo/yosegi/binary/maker/index/FlagBooleanIndex.java b/src/main/java/jp/co/yahoo/yosegi/binary/maker/index/FlagBooleanIndex.java
new file mode 100644
index 00000000..8ca14774
--- /dev/null
+++ b/src/main/java/jp/co/yahoo/yosegi/binary/maker/index/FlagBooleanIndex.java
@@ -0,0 +1,61 @@
+/**
+ * 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 jp.co.yahoo.yosegi.binary.maker.index;
+
+import jp.co.yahoo.yosegi.spread.column.filter.BooleanFilter;
+import jp.co.yahoo.yosegi.spread.column.filter.FilterType;
+import jp.co.yahoo.yosegi.spread.column.filter.IFilter;
+import jp.co.yahoo.yosegi.spread.column.index.ICellIndex;
+
+import java.io.IOException;
+
+public class FlagBooleanIndex implements ICellIndex {
+
+ private final boolean hasTrue;
+ private final boolean hasFalse;
+ private final boolean hasNull;
+
+ /**
+ * FlagBooleanIndex constructor.
+ * @param hasTrue true when true values exist.
+ * @param hasFalse true when false values exist.
+ * @param hasNull true when null values exist.
+ */
+ public FlagBooleanIndex(final boolean hasTrue, final boolean hasFalse, final boolean hasNull) {
+ this.hasTrue = hasTrue;
+ this.hasFalse = hasFalse;
+ this.hasNull = hasNull;
+ }
+
+ @Override
+ public boolean[] filter(final IFilter filter, final boolean[] filterArray) throws IOException {
+ if (filter.getFilterType() == FilterType.BOOLEAN) {
+ BooleanFilter booleanFilter = (BooleanFilter) filter;
+ // NOTE: return filterArray filled with false when there is no target value
+ if (booleanFilter.getFlag()) {
+ if (!hasTrue) {
+ return filterArray;
+ }
+ } else {
+ if (!hasFalse) {
+ return filterArray;
+ }
+ }
+ }
+ // NOTE: return null when there are some target values
+ return null;
+ }
+}
diff --git a/src/main/java/jp/co/yahoo/yosegi/blockindex/RangeBlockIndexNameShortCut.java b/src/main/java/jp/co/yahoo/yosegi/blockindex/BlockIndexNameShortCut.java
similarity index 92%
rename from src/main/java/jp/co/yahoo/yosegi/blockindex/RangeBlockIndexNameShortCut.java
rename to src/main/java/jp/co/yahoo/yosegi/blockindex/BlockIndexNameShortCut.java
index cfd903c8..77507ad5 100644
--- a/src/main/java/jp/co/yahoo/yosegi/blockindex/RangeBlockIndexNameShortCut.java
+++ b/src/main/java/jp/co/yahoo/yosegi/blockindex/BlockIndexNameShortCut.java
@@ -20,7 +20,7 @@
import jp.co.yahoo.yosegi.util.Pair;
-public final class RangeBlockIndexNameShortCut {
+public final class BlockIndexNameShortCut {
private static final Pair CLASS_NAME_PAIR = new Pair();
@@ -34,9 +34,11 @@ public final class RangeBlockIndexNameShortCut {
CLASS_NAME_PAIR.set( "jp.co.yahoo.yosegi.blockindex.StringRangeBlockIndex" , "R6" );
CLASS_NAME_PAIR.set( "jp.co.yahoo.yosegi.blockindex.FullRangeBlockIndex" , "FR0" );
+
+ CLASS_NAME_PAIR.set( "jp.co.yahoo.yosegi.blockindex.BooleanBlockIndex" , "BI0" );
}
- private RangeBlockIndexNameShortCut() {}
+ private BlockIndexNameShortCut() {}
/**
* Get the shortcut name from the class name.
diff --git a/src/main/java/jp/co/yahoo/yosegi/blockindex/BlockIndexNode.java b/src/main/java/jp/co/yahoo/yosegi/blockindex/BlockIndexNode.java
index 0fae5be4..b8efb24d 100644
--- a/src/main/java/jp/co/yahoo/yosegi/blockindex/BlockIndexNode.java
+++ b/src/main/java/jp/co/yahoo/yosegi/blockindex/BlockIndexNode.java
@@ -120,7 +120,7 @@ public int getBinarySize() throws IOException {
length += Integer.BYTES;
if ( blockIndex != null ) {
length += Integer.BYTES;
- length += RangeBlockIndexNameShortCut.getShortCutName(
+ length += BlockIndexNameShortCut.getShortCutName(
blockIndex.getClass().getName() ).getBytes( "UTF-8" ).length;
length += Integer.BYTES;
length += blockIndex.getBinarySize();
@@ -154,13 +154,13 @@ public int toBinary( final byte[] buffer , final int start ) throws IOException
} else {
wrapBuffer.putInt( offset , 1 );
offset += Integer.BYTES;
- byte[] rangeClassNameBytes = RangeBlockIndexNameShortCut.getShortCutName(
+ byte[] blockIndexClassNameBytes = BlockIndexNameShortCut.getShortCutName(
blockIndex.getClass().getName() ).getBytes( "UTF-8" );
- wrapBuffer.putInt( offset , rangeClassNameBytes.length );
+ wrapBuffer.putInt( offset , blockIndexClassNameBytes.length );
offset += Integer.BYTES;
wrapBuffer.position( offset );
- wrapBuffer.put( rangeClassNameBytes );
- offset += rangeClassNameBytes.length;
+ wrapBuffer.put( blockIndexClassNameBytes );
+ offset += blockIndexClassNameBytes.length;
byte[] indexBinary = blockIndex.toBinary();
wrapBuffer.putInt( offset , indexBinary.length );
offset += Integer.BYTES;
@@ -228,7 +228,7 @@ public static BlockIndexNode createFromBinary(
wrapBuffer.get( indexBinary , 0 , indexBinaryLength );
offset += indexBinaryLength;
IBlockIndex blockIndex = FindBlockIndex.get(
- RangeBlockIndexNameShortCut.getClassName( new String( classNameBytes , "UTF-8" ) ) );
+ BlockIndexNameShortCut.getClassName( new String( classNameBytes , "UTF-8" ) ) );
blockIndex.setFromBinary( indexBinary , 0 , indexBinary.length );
result.setBlockIndex( blockIndex );
}
diff --git a/src/main/java/jp/co/yahoo/yosegi/blockindex/BlockIndexType.java b/src/main/java/jp/co/yahoo/yosegi/blockindex/BlockIndexType.java
index a6e38b00..4626546c 100644
--- a/src/main/java/jp/co/yahoo/yosegi/blockindex/BlockIndexType.java
+++ b/src/main/java/jp/co/yahoo/yosegi/blockindex/BlockIndexType.java
@@ -30,5 +30,6 @@ public enum BlockIndexType {
RANGE_LONG,
RANGE_FLOAT,
RANGE_DOUBLE,
+ BOOLEAN,
}
diff --git a/src/main/java/jp/co/yahoo/yosegi/blockindex/BooleanBlockIndex.java b/src/main/java/jp/co/yahoo/yosegi/blockindex/BooleanBlockIndex.java
new file mode 100644
index 00000000..3c46b690
--- /dev/null
+++ b/src/main/java/jp/co/yahoo/yosegi/blockindex/BooleanBlockIndex.java
@@ -0,0 +1,203 @@
+/**
+ * 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 jp.co.yahoo.yosegi.blockindex;
+
+import jp.co.yahoo.yosegi.spread.column.filter.BooleanFilter;
+import jp.co.yahoo.yosegi.spread.column.filter.FilterType;
+import jp.co.yahoo.yosegi.spread.column.filter.IFilter;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+public class BooleanBlockIndex implements IBlockIndex {
+
+ private boolean hasTrue;
+ private boolean hasFalse;
+ private boolean hasNull;
+
+ /**
+ * BooleanBlockIndex constructor.
+ */
+ public BooleanBlockIndex() {
+ hasTrue = false;
+ hasFalse = false;
+ hasNull = false;
+ }
+
+ /**
+ * BooleanBlockIndex constructor.
+ * @param hasTrue true when true values exist.
+ * @param hasFalse true when false values exist.
+ * @param hasNull true when null values exist.
+ */
+ public BooleanBlockIndex(final boolean hasTrue, final boolean hasFalse, final boolean hasNull) {
+ this.hasTrue = hasTrue;
+ this.hasFalse = hasFalse;
+ this.hasNull = hasNull;
+ }
+
+ @Override
+ public IBlockIndex clone() {
+ return new BooleanBlockIndex(hasTrue, hasFalse, hasNull);
+ }
+
+ @Override
+ public BlockIndexType getBlockIndexType() {
+ return BlockIndexType.BOOLEAN;
+ }
+
+ @Override
+ public boolean merge(final IBlockIndex blockIndex) {
+ if (!(blockIndex instanceof BooleanBlockIndex)) {
+ return false;
+ }
+ BooleanBlockIndex booleanBlockIndex = (BooleanBlockIndex) blockIndex;
+ if (booleanBlockIndex.hasTrue()) {
+ hasTrue = true;
+ }
+ if (booleanBlockIndex.hasFalse()) {
+ hasFalse = true;
+ }
+ if (booleanBlockIndex.hasNull()) {
+ hasNull = true;
+ }
+ return true;
+ }
+
+ @Override
+ public int getBinarySize() {
+ return BitFlags.LENGTH;
+ }
+
+ @Override
+ public byte[] toBinary() {
+ byte[] result = new byte[getBinarySize()];
+ ByteBuffer wrapBuffer = ByteBuffer.wrap(result);
+ BitFlags bitFlags = new BitFlags(hasTrue, hasFalse, hasNull);
+ wrapBuffer.put(bitFlags.getBitFlags());
+ return result;
+ }
+
+ @Override
+ public void setFromBinary(final byte[] buffer, final int start, final int length) {
+ ByteBuffer wrapBuffer = ByteBuffer.wrap(buffer, start, length);
+ byte flags = wrapBuffer.get();
+ BitFlags bitFlags = new BitFlags(flags);
+ hasTrue = bitFlags.hasTrue();
+ hasFalse = bitFlags.hasFalse();
+ hasNull = bitFlags.hasNull();
+ }
+
+ @Override
+ public List getBlockSpreadIndex(final IFilter filter) {
+ if (filter.getFilterType() == FilterType.BOOLEAN) {
+ BooleanFilter booleanFilter = (BooleanFilter) filter;
+ if (booleanFilter.getFlag()) {
+ if (!hasTrue) {
+ return new ArrayList();
+ }
+ } else {
+ if (!hasFalse) {
+ return new ArrayList();
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public IBlockIndex getNewInstance() {
+ return new BooleanBlockIndex();
+ }
+
+ public boolean hasTrue() {
+ return hasTrue;
+ }
+
+ public boolean hasFalse() {
+ return hasFalse;
+ }
+
+ public boolean hasNull() {
+ return hasNull;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "%s hasTrue=%b hasFalse=%b hasNull=%b",
+ this.getClass().getName(), hasTrue, hasFalse, hasNull);
+ }
+
+ public static class BitFlags {
+
+ public static final int LENGTH = Byte.BYTES;
+
+ private static final byte HAS_TRUE = 1;
+ private static final byte HAS_FALSE = 1 << 1;
+ private static final byte HAS_NULL = 1 << 2;
+
+ private boolean hasTrue;
+ private boolean hasFalse;
+ private boolean hasNull;
+
+ // bitFlags: 001:hasTrue, 010:hasFalse, 100:hasNull
+ private byte bitFlags;
+
+ /**
+ * BitFlags constructor.
+ * @param bitFlags 001:hasTrue, 010:hasFalse, 100:hasNull.
+ */
+ public BitFlags(final byte bitFlags) {
+ this.bitFlags = bitFlags;
+ hasTrue = (bitFlags & HAS_TRUE) != 0;
+ hasFalse = (bitFlags & HAS_FALSE) != 0;
+ hasNull = (bitFlags & HAS_NULL) != 0;
+ }
+
+ /**
+ * BitFlags constructor.
+ * @param hasTrue true when true values exist.
+ * @param hasFalse true when false values exist.
+ * @param hasNull true when null values exist.
+ */
+ public BitFlags(final boolean hasTrue, final boolean hasFalse, final boolean hasNull) {
+ this.hasTrue = hasTrue;
+ this.hasFalse = hasFalse;
+ this.hasNull = hasNull;
+ bitFlags = hasTrue ? HAS_TRUE : 0;
+ bitFlags |= hasFalse ? HAS_FALSE : 0;
+ bitFlags |= hasNull ? HAS_NULL : 0;
+ }
+
+ public byte getBitFlags() {
+ return bitFlags;
+ }
+
+ public boolean hasTrue() {
+ return hasTrue;
+ }
+
+ public boolean hasFalse() {
+ return hasFalse;
+ }
+
+ public boolean hasNull() {
+ return hasNull;
+ }
+ }
+}
diff --git a/src/main/java/jp/co/yahoo/yosegi/blockindex/EncryptionSupportedBlockIndexNode.java b/src/main/java/jp/co/yahoo/yosegi/blockindex/EncryptionSupportedBlockIndexNode.java
index caa32333..d36b1088 100644
--- a/src/main/java/jp/co/yahoo/yosegi/blockindex/EncryptionSupportedBlockIndexNode.java
+++ b/src/main/java/jp/co/yahoo/yosegi/blockindex/EncryptionSupportedBlockIndexNode.java
@@ -20,7 +20,6 @@
import jp.co.yahoo.yosegi.encryptor.AdditionalAuthenticationData;
import jp.co.yahoo.yosegi.encryptor.EncryptionSettingNode;
-import jp.co.yahoo.yosegi.encryptor.EncryptorFactoryNameShortCut;
import jp.co.yahoo.yosegi.encryptor.IEncryptor;
import jp.co.yahoo.yosegi.encryptor.IEncryptorFactory;
import jp.co.yahoo.yosegi.encryptor.Module;
@@ -94,12 +93,12 @@ public int getBinarySize(
length += Integer.BYTES;
} else {
byte[] nodeNameBytes = nodeName.getBytes( "UTF-8" );
- byte[] rangeClassNameBytes = RangeBlockIndexNameShortCut.getShortCutName(
+ byte[] blockIndexClassNameBytes = BlockIndexNameShortCut.getShortCutName(
blockIndex.getClass().getName() ).getBytes( "UTF-8" );
byte[] indexBinary = blockIndex.toBinary();
int newIndexBinarySize = Integer.BYTES * 3
+ nodeNameBytes.length
- + rangeClassNameBytes.length
+ + blockIndexClassNameBytes.length
+ indexBinary.length;
length += Integer.BYTES;
@@ -170,19 +169,19 @@ public int toBinary(
wrapBuffer.putInt( 0 );
} else {
byte[] nodeNameBinary = nodeName.getBytes( "UTF-8" );
- byte[] rangeClassNameBytes = RangeBlockIndexNameShortCut.getShortCutName(
+ byte[] blockIndexClassNameBytes = BlockIndexNameShortCut.getShortCutName(
blockIndex.getClass().getName() ).getBytes( "UTF-8" );
byte[] indexBinary = blockIndex.toBinary();
byte[] newIndexBinary = new byte[ Integer.BYTES * 3
+ nodeNameBinary.length
- + rangeClassNameBytes.length
+ + blockIndexClassNameBytes.length
+ indexBinary.length ];
ByteBuffer newIndexBuffer = ByteBuffer.wrap( newIndexBinary );
newIndexBuffer.putInt( nodeNameBinary.length );
newIndexBuffer.put( nodeNameBinary );
- newIndexBuffer.putInt( rangeClassNameBytes.length );
- newIndexBuffer.put( rangeClassNameBytes );
+ newIndexBuffer.putInt( blockIndexClassNameBytes.length );
+ newIndexBuffer.put( blockIndexClassNameBytes );
newIndexBuffer.putInt( indexBinary.length );
newIndexBuffer.put( indexBinary );
@@ -244,7 +243,7 @@ private static IBlockIndex createBlockIndexFromByteBuffer(
"UTF-8" );
decriptBuffer.position( decriptBuffer.position() + blockIndexClassNameBinaryLength );
IBlockIndex blockIndex = FindBlockIndex.get(
- RangeBlockIndexNameShortCut.getClassName( blockIndexClassName ) );
+ BlockIndexNameShortCut.getClassName( blockIndexClassName ) );
int indexBinaryLength = decriptBuffer.getInt();
blockIndex.setFromBinary(
decriptBuffer.array() , decriptBuffer.position() , indexBinaryLength );
diff --git a/src/test/java/jp/co/yahoo/yosegi/binary/TestColumnBinaryMakerConfig.java b/src/test/java/jp/co/yahoo/yosegi/binary/TestColumnBinaryMakerConfig.java
index 94db3efd..0ccdf3fa 100644
--- a/src/test/java/jp/co/yahoo/yosegi/binary/TestColumnBinaryMakerConfig.java
+++ b/src/test/java/jp/co/yahoo/yosegi/binary/TestColumnBinaryMakerConfig.java
@@ -39,7 +39,7 @@ private static Stream parametersForT_getColumnMaker_1(){
arguments( ColumnType.UNION , DumpUnionColumnBinaryMaker.class.getName() ),
arguments( ColumnType.ARRAY , MaxLengthBasedArrayColumnBinaryMaker.class.getName() ),
arguments( ColumnType.SPREAD , DumpSpreadColumnBinaryMaker.class.getName() ),
- arguments( ColumnType.BOOLEAN , OptimizedNullArrayDumpBooleanColumnBinaryMaker.class.getName() ),
+ arguments( ColumnType.BOOLEAN , FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker.class.getName() ),
arguments( ColumnType.BYTE , OptimizedNullArrayDumpLongColumnBinaryMaker.class.getName() ),
arguments( ColumnType.BYTES , OptimizedNullArrayDumpBytesColumnBinaryMaker.class.getName() ),
arguments( ColumnType.DOUBLE , OptimizedNullArrayDumpDoubleColumnBinaryMaker.class.getName() ),
diff --git a/src/test/java/jp/co/yahoo/yosegi/binary/maker/TestFlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker.java b/src/test/java/jp/co/yahoo/yosegi/binary/maker/TestFlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker.java
new file mode 100644
index 00000000..ec23190b
--- /dev/null
+++ b/src/test/java/jp/co/yahoo/yosegi/binary/maker/TestFlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker.java
@@ -0,0 +1,269 @@
+/**
+ * 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 jp.co.yahoo.yosegi.binary.maker;
+
+import jp.co.yahoo.yosegi.binary.ColumnBinary;
+import jp.co.yahoo.yosegi.binary.ColumnBinaryMakerConfig;
+import jp.co.yahoo.yosegi.binary.CompressResultNode;
+import jp.co.yahoo.yosegi.blockindex.BlockIndexNode;
+import jp.co.yahoo.yosegi.blockindex.BooleanBlockIndex;
+import jp.co.yahoo.yosegi.inmemory.IMemoryAllocator;
+import jp.co.yahoo.yosegi.message.objects.BooleanObj;
+import jp.co.yahoo.yosegi.message.objects.PrimitiveObject;
+import jp.co.yahoo.yosegi.spread.analyzer.BooleanColumnAnalizeResult;
+import jp.co.yahoo.yosegi.spread.analyzer.BooleanColumnAnalizer;
+import jp.co.yahoo.yosegi.spread.analyzer.IColumnAnalizeResult;
+import jp.co.yahoo.yosegi.spread.analyzer.IColumnAnalizer;
+import jp.co.yahoo.yosegi.spread.column.ColumnType;
+import jp.co.yahoo.yosegi.spread.column.IColumn;
+import jp.co.yahoo.yosegi.spread.column.PrimitiveColumn;
+import jp.co.yahoo.yosegi.spread.column.filter.BooleanFilter;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.params.provider.Arguments.arguments;
+
+class TestFlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker {
+
+ private IColumn makeColumn(final String columnName, Boolean[] values) throws IOException {
+ IColumn column = new PrimitiveColumn(ColumnType.BOOLEAN, columnName);
+ for (int i = 0; i < values.length; i++) {
+ if (values[i] != null) {
+ column.add(ColumnType.BOOLEAN, new BooleanObj(values[i]), i);
+ }
+ }
+ return column;
+ }
+
+ private ColumnBinary makeColumnBinary(final String columnName, Boolean[] values)
+ throws IOException {
+ IColumn column = makeColumn(columnName, values);
+ FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker maker =
+ new FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker();
+ ColumnBinaryMakerConfig defaultConfig = new ColumnBinaryMakerConfig();
+ ColumnBinary columnBinary =
+ maker.toBinary(defaultConfig, null, new CompressResultNode(), column);
+ return columnBinary;
+ }
+
+ private class TestMemorayAllocator implements IMemoryAllocator {
+ public final Map map;
+
+ public TestMemorayAllocator() {
+ map = new HashMap<>();
+ }
+
+ @Override
+ public void setNull(final int index) {
+ map.put(index, null);
+ }
+
+ @Override
+ public void setBoolean(final int index, final boolean value) {
+ map.put(index, value);
+ }
+ }
+
+ public static Stream D_toBinary_1() {
+ return Stream.of(
+ // columnName, columnValues
+ arguments("TEST1", new Boolean[] {true}),
+ arguments("TEST1", new Boolean[] {false}),
+ arguments("TEST1", new Boolean[] {null, true}),
+ arguments("TEST1", new Boolean[] {null, false}),
+ arguments("TEST1", new Boolean[] {true, false}),
+ arguments("TEST1", new Boolean[] {false, true}),
+ arguments("TEST1", new Boolean[] {true, null, false}));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_toBinary_1")
+ public void T_toBinary_1(final String columnName, final Boolean[] columnValues)
+ throws IOException {
+ ColumnBinary columnBinary = makeColumnBinary(columnName, columnValues);
+ assertEquals(columnName, columnBinary.columnName);
+ assertEquals(ColumnType.BOOLEAN, columnBinary.columnType);
+ assertEquals(columnValues.length, columnBinary.rowCount);
+ assertEquals(
+ FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker.class.getName(),
+ columnBinary.makerClassName);
+ }
+
+ public static Stream D_calcBinarySize_1() {
+ return Stream.of(
+ // columnName, columnValues
+ arguments("TEST1", new Boolean[] {true}, 1),
+ arguments("TEST1", new Boolean[] {false}, 1),
+ arguments("TEST1", new Boolean[] {null, true}, 2),
+ arguments("TEST1", new Boolean[] {null, false}, 2),
+ arguments("TEST1", new Boolean[] {true, false}, 2),
+ arguments("TEST1", new Boolean[] {false, true}, 2),
+ arguments("TEST1", new Boolean[] {true, null, false}, 3));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_calcBinarySize_1")
+ public void T_calcBinarySize_1(
+ final String columnName, final Boolean[] columnValues, final int expected)
+ throws IOException {
+ IColumn column = makeColumn(columnName, columnValues);
+ IColumnAnalizer analizer = new BooleanColumnAnalizer(column);
+ IColumnAnalizeResult analizeResult = analizer.analize();
+ FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker maker =
+ new FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker();
+ assertEquals(expected, maker.calcBinarySize(analizeResult));
+ }
+
+ public static Stream D_toColumn_1() {
+ return Stream.of(
+ // columnName, columnValues
+ arguments("TEST1", new Boolean[] {true}),
+ arguments("TEST1", new Boolean[] {false}),
+ arguments("TEST1", new Boolean[] {null, true}),
+ arguments("TEST1", new Boolean[] {null, false}),
+ arguments("TEST1", new Boolean[] {true, false}),
+ arguments("TEST1", new Boolean[] {false, true}),
+ arguments("TEST1", new Boolean[] {true, null, false}));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_toColumn_1")
+ public void T_toClumn_1(final String columnName, final Boolean[] columnValues)
+ throws IOException {
+ ColumnBinary columnBinary = makeColumnBinary(columnName, columnValues);
+ FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker maker =
+ new FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker();
+ IColumn newColumn = maker.toColumn(columnBinary);
+ assertEquals(ColumnType.BOOLEAN, newColumn.getColumnType());
+ assertEquals(columnName, newColumn.getColumnName());
+ assertEquals(columnValues.length, newColumn.size());
+ for (int i = 0; i < columnValues.length; i++) {
+ if (newColumn.get(i).getRow() == null) {
+ assertNull(newColumn.get(i).getRow());
+ } else {
+ assertEquals(columnValues[i], ((PrimitiveObject) newColumn.get(i).getRow()).getBoolean());
+ }
+ }
+ }
+
+ public static Stream D_columnFilter_1() {
+ return Stream.of(
+ // columnName, columnValues, filterFlag, expectedNull
+ arguments("TEST1", new Boolean[] {true}, true, true),
+ arguments("TEST1", new Boolean[] {true}, false, false),
+ arguments("TEST1", new Boolean[] {false}, true, false),
+ arguments("TEST1", new Boolean[] {false}, false, true),
+ arguments("TEST1", new Boolean[] {null, true}, true, true),
+ arguments("TEST1", new Boolean[] {null, true}, false, false),
+ arguments("TEST1", new Boolean[] {null, false}, true, false),
+ arguments("TEST1", new Boolean[] {null, false}, false, true),
+ arguments("TEST1", new Boolean[] {true, false}, true, true),
+ arguments("TEST1", new Boolean[] {true, false}, false, true),
+ arguments("TEST1", new Boolean[] {false, true}, true, true),
+ arguments("TEST1", new Boolean[] {false, true}, false, true),
+ arguments("TEST1", new Boolean[] {true, null, false}, true, true),
+ arguments("TEST1", new Boolean[] {true, null, false}, false, true));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_columnFilter_1")
+ public void T_columnFilter_1(
+ final String columnName,
+ final Boolean[] columnValues,
+ final boolean filterFlag,
+ final boolean expectedNull)
+ throws IOException {
+ ColumnBinary columnBinary = makeColumnBinary(columnName, columnValues);
+ FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker maker =
+ new FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker();
+ IColumn newColumn = maker.toColumn(columnBinary);
+ boolean[] bArray = new boolean[newColumn.size()];
+ if (expectedNull) {
+ assertNull(newColumn.filter(new BooleanFilter(filterFlag), bArray));
+ } else {
+ boolean[] expected = new boolean[newColumn.size()];
+ assertArrayEquals(expected, newColumn.filter(new BooleanFilter(filterFlag), bArray));
+ }
+ }
+
+ public static Stream D_loadInMemoryStorage_1() {
+ return Stream.of(
+ // columnName, columnValues
+ arguments("TEST1", new Boolean[] {true}),
+ arguments("TEST1", new Boolean[] {false}),
+ arguments("TEST1", new Boolean[] {null, true}),
+ arguments("TEST1", new Boolean[] {null, false}),
+ arguments("TEST1", new Boolean[] {true, false}),
+ arguments("TEST1", new Boolean[] {false, true}),
+ arguments("TEST1", new Boolean[] {true, null, false}));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_loadInMemoryStorage_1")
+ public void T_loadInMemoryStorage_1(final String columnName, final Boolean[] columnValues)
+ throws IOException {
+ ColumnBinary columnBinary = makeColumnBinary(columnName, columnValues);
+ FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker maker =
+ new FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker();
+ TestMemorayAllocator allocator = new TestMemorayAllocator();
+ maker.loadInMemoryStorage(columnBinary, allocator);
+ for (int i = 0; i < columnValues.length; i++) {
+ assertEquals(columnValues[i], allocator.map.get(i));
+ }
+ }
+
+ public static Stream D_setBlockIndexNode_1() {
+ return Stream.of(
+ // columnName, columnValues, expectedHasTrue, expectedHasFalse, expectedHasNull
+ arguments("TEST1", new Boolean[] {true}, true, false, false),
+ arguments("TEST1", new Boolean[] {false}, false, true, false),
+ arguments("TEST1", new Boolean[] {null, true}, true, false, true),
+ arguments("TEST1", new Boolean[] {null, false}, false, true, true),
+ arguments("TEST1", new Boolean[] {true, false}, true, true, false),
+ arguments("TEST1", new Boolean[] {false, true}, true, true, false),
+ arguments("TEST1", new Boolean[] {true, null, false}, true, true, true));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_setBlockIndexNode_1")
+ public void T_setBlockIndexNode_1(
+ final String columnName,
+ final Boolean[] columnValues,
+ final boolean expectedHasTrue,
+ final boolean expectedHasFalse,
+ final boolean expectedHasNull)
+ throws IOException {
+ ColumnBinary columnBinary = makeColumnBinary(columnName, columnValues);
+ FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker maker =
+ new FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker();
+ BlockIndexNode parentNode = new BlockIndexNode();
+ maker.setBlockIndexNode(parentNode, columnBinary, 0);
+ BlockIndexNode currentNode = parentNode.getChildNode(columnBinary.columnName);
+ BooleanBlockIndex blockIndex = (BooleanBlockIndex) currentNode.getBlockIndex();
+ assertEquals(expectedHasTrue, blockIndex.hasTrue());
+ assertEquals(expectedHasFalse, blockIndex.hasFalse());
+ assertEquals(expectedHasNull, blockIndex.hasNull());
+ }
+}
diff --git a/src/test/java/jp/co/yahoo/yosegi/binary/maker/index/TestFlagBooleanIndex.java b/src/test/java/jp/co/yahoo/yosegi/binary/maker/index/TestFlagBooleanIndex.java
new file mode 100644
index 00000000..42222e9d
--- /dev/null
+++ b/src/test/java/jp/co/yahoo/yosegi/binary/maker/index/TestFlagBooleanIndex.java
@@ -0,0 +1,66 @@
+/**
+ * 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 jp.co.yahoo.yosegi.binary.maker.index;
+
+import jp.co.yahoo.yosegi.spread.column.filter.BooleanFilter;
+import jp.co.yahoo.yosegi.spread.column.filter.IFilter;
+import jp.co.yahoo.yosegi.spread.column.index.ICellIndex;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.io.IOException;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.params.provider.Arguments.arguments;
+
+class TestFlagBooleanIndex {
+
+ private static final boolean[] dummy = new boolean[0];
+
+ public static Stream D_filter_1() {
+ return Stream.of(
+ arguments(new FlagBooleanIndex(true, false, false), new BooleanFilter(true), null),
+ arguments(new FlagBooleanIndex(true, false, false), new BooleanFilter(false), dummy),
+ arguments(new FlagBooleanIndex(true, true, false), new BooleanFilter(true), null),
+ arguments(new FlagBooleanIndex(true, true, false), new BooleanFilter(false), null),
+ arguments(new FlagBooleanIndex(true, false, true), new BooleanFilter(true), null),
+ arguments(new FlagBooleanIndex(true, false, true), new BooleanFilter(false), dummy),
+ arguments(new FlagBooleanIndex(true, true, true), new BooleanFilter(true), null),
+ arguments(new FlagBooleanIndex(true, true, true), new BooleanFilter(false), null),
+ arguments(new FlagBooleanIndex(false, true, false), new BooleanFilter(true), dummy),
+ arguments(new FlagBooleanIndex(false, true, false), new BooleanFilter(false), null),
+ arguments(new FlagBooleanIndex(false, false, true), new BooleanFilter(true), dummy),
+ arguments(new FlagBooleanIndex(false, false, true), new BooleanFilter(false), dummy),
+ arguments(new FlagBooleanIndex(false, true, true), new BooleanFilter(true), dummy),
+ arguments(new FlagBooleanIndex(false, true, true), new BooleanFilter(false), null),
+ arguments(new FlagBooleanIndex(false, false, false), new BooleanFilter(true), dummy),
+ arguments(new FlagBooleanIndex(false, false, false), new BooleanFilter(false), dummy));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_filter_1")
+ public void T_filter_1(final ICellIndex cellIndex, final IFilter filter, final boolean[] result)
+ throws IOException {
+ boolean[] r = cellIndex.filter(filter, new boolean[0]);
+ if (result == null) {
+ assertNull(r);
+ } else {
+ assertEquals(result.length, r.length);
+ }
+ }
+}
diff --git a/src/test/java/jp/co/yahoo/yosegi/blackbox/TestBooleanBlockIndex.java b/src/test/java/jp/co/yahoo/yosegi/blackbox/TestBooleanBlockIndex.java
new file mode 100644
index 00000000..89d7e6e1
--- /dev/null
+++ b/src/test/java/jp/co/yahoo/yosegi/blackbox/TestBooleanBlockIndex.java
@@ -0,0 +1,636 @@
+/**
+ * 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 jp.co.yahoo.yosegi.blackbox;
+
+import javafx.util.Pair;
+import jp.co.yahoo.yosegi.config.Configuration;
+import jp.co.yahoo.yosegi.message.objects.PrimitiveObject;
+import jp.co.yahoo.yosegi.message.parser.IParser;
+import jp.co.yahoo.yosegi.message.parser.json.JacksonMessageReader;
+import jp.co.yahoo.yosegi.reader.YosegiReader;
+import jp.co.yahoo.yosegi.spread.Spread;
+import jp.co.yahoo.yosegi.spread.column.ColumnType;
+import jp.co.yahoo.yosegi.spread.column.IColumn;
+import jp.co.yahoo.yosegi.spread.column.filter.BooleanFilter;
+import jp.co.yahoo.yosegi.spread.expression.AndExpressionNode;
+import jp.co.yahoo.yosegi.spread.expression.ExecuterNode;
+import jp.co.yahoo.yosegi.spread.expression.IExpressionNode;
+import jp.co.yahoo.yosegi.spread.expression.NotExpressionNode;
+import jp.co.yahoo.yosegi.spread.expression.OrExpressionNode;
+import jp.co.yahoo.yosegi.spread.expression.StringExtractNode;
+import jp.co.yahoo.yosegi.writer.YosegiWriter;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.params.provider.Arguments.arguments;
+
+public class TestBooleanBlockIndex {
+
+ /*
+ col1: true,true,true
+ col2: false,false,false
+ col3: true,true,false
+ col4: true,false,true
+ col5: false,false,true
+ col6: false,true,false
+ col7: true,(null),(null)
+ col8: false,(null),(null)
+ col9: true,true,(null)
+ col10: true,false,(null)
+ col11: false,false,(null)
+ col12: false, true,(null)
+ col13: true,(null),true
+ col14: true,(null),false
+ col15: false,(null),false
+ col16: false,(null),true
+ */
+ public byte[] getData() throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ Configuration writerConfig = new Configuration();
+
+ JacksonMessageReader messageReader = new JacksonMessageReader();
+ BufferedReader jsonIn =
+ new BufferedReader(
+ new InputStreamReader(
+ this.getClass()
+ .getClassLoader()
+ .getResource("blackbox/TestBooleanBlockIndex.json")
+ .openStream()));
+ String line = jsonIn.readLine();
+ Spread writeSpread = new Spread();
+ try (YosegiWriter writer = new YosegiWriter(out, writerConfig)) {
+ while (line != null) {
+ IParser parser = messageReader.create(line);
+ writeSpread.addParserRow(parser);
+ line = jsonIn.readLine();
+ }
+ writer.append(writeSpread);
+ }
+
+ return out.toByteArray();
+ }
+
+ public static Stream D_blackbox_1() {
+ return Stream.of(
+ // list{pair, pair ...}
+ arguments(
+ new ArrayList<>(
+ Arrays.asList(
+ new Pair<>("col1", new ArrayList<>(Arrays.asList(true, true, true))),
+ new Pair<>("col2", new ArrayList<>(Arrays.asList(false, false, false))),
+ new Pair<>("col3", new ArrayList<>(Arrays.asList(true, true, false))),
+ new Pair<>("col4", new ArrayList<>(Arrays.asList(true, false, true))),
+ new Pair<>("col5", new ArrayList<>(Arrays.asList(false, false, true))),
+ new Pair<>("col6", new ArrayList<>(Arrays.asList(false, true, false))),
+ new Pair<>("col7", new ArrayList<>(Arrays.asList(true, null, null))),
+ new Pair<>("col8", new ArrayList<>(Arrays.asList(false, null, null))),
+ new Pair<>("col9", new ArrayList<>(Arrays.asList(true, true, null))),
+ new Pair<>("col10", new ArrayList<>(Arrays.asList(true, false, null))),
+ new Pair<>("col11", new ArrayList<>(Arrays.asList(false, false, null))),
+ new Pair<>("col12", new ArrayList<>(Arrays.asList(false, true, null))),
+ new Pair<>("col13", new ArrayList<>(Arrays.asList(true, null, true))),
+ new Pair<>("col14", new ArrayList<>(Arrays.asList(true, null, false))),
+ new Pair<>("col15", new ArrayList<>(Arrays.asList(false, null, false))),
+ new Pair<>("col16", new ArrayList<>(Arrays.asList(false, null, true)))))));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_blackbox_1")
+ public void T_blackbox_1(final List>> expecteds) throws IOException {
+ try (YosegiReader reader = new YosegiReader()) {
+ Configuration readerConfig = new Configuration();
+ byte[] data = getData();
+ InputStream in = new ByteArrayInputStream(data);
+ reader.setNewStream(in, data.length, readerConfig);
+ while (reader.hasNext()) {
+ Spread spread = reader.next();
+ for (Pair> expected : expecteds) {
+ IColumn col = spread.getColumn(expected.getKey());
+ for (int i = 0; i < spread.size(); i++) {
+ List expectedValues = expected.getValue();
+ if (expectedValues.get(i) == null) {
+ assertEquals(ColumnType.NULL, col.get(i).getType());
+ } else {
+ assertEquals(
+ expectedValues.get(i), ((PrimitiveObject) col.get(i).getRow()).getBoolean());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public static Stream D_blackbox_2() {
+ return Stream.of(
+ // columnName, filterValue, expected(hasNext)
+ arguments("col1", true, true),
+ arguments("col1", false, false),
+ arguments("col2", true, false),
+ arguments("col2", false, true),
+ arguments("col3", true, true),
+ arguments("col3", false, true),
+ arguments("col4", true, true),
+ arguments("col4", false, true),
+ arguments("col5", true, true),
+ arguments("col6", false, true),
+ arguments("col7", true, true),
+ arguments("col7", false, false),
+ arguments("col8", true, false),
+ arguments("col8", false, true),
+ arguments("col9", true, true),
+ arguments("col9", false, false),
+ arguments("col10", true, true),
+ arguments("col10", false, true),
+ arguments("col11", true, false),
+ arguments("col11", false, true),
+ arguments("col12", true, true),
+ arguments("col12", false, true),
+ arguments("col13", true, true),
+ arguments("col13", false, false),
+ arguments("col14", true, true),
+ arguments("col14", false, true),
+ arguments("col15", true, false),
+ arguments("col15", false, true),
+ arguments("col16", true, true),
+ arguments("col16", false, true));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_blackbox_2")
+ public void T_blackbox_2(
+ final String columnName, final Boolean filterValue, final Boolean expected)
+ throws IOException {
+ try (YosegiReader reader = new YosegiReader()) {
+ IExpressionNode index = new AndExpressionNode();
+ index.addChildNode(
+ new ExecuterNode(new StringExtractNode(columnName), new BooleanFilter(filterValue)));
+ Configuration readerConfig = new Configuration();
+ byte[] data = getData();
+ InputStream in = new ByteArrayInputStream(data);
+ reader.setBlockSkipIndex(index);
+ reader.setNewStream(in, data.length, readerConfig);
+ assertEquals(expected, reader.hasNext());
+ }
+ }
+
+ public static Stream D_blackbox_3() {
+ return Stream.of(
+ // columnName1, filterValue1, columnName2, filterValue2, expected(hasNext)
+ arguments("col1", true, "col2", true, false),
+ arguments("col1", true, "col2", false, true),
+ arguments("col1", false, "col2", false, false),
+ arguments("col1", false, "col2", true, false));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_blackbox_3")
+ public void T_blackbox_3(
+ final String columnName1,
+ final Boolean filterValue1,
+ final String columnName2,
+ final Boolean filterValue2,
+ final Boolean expected)
+ throws IOException {
+ try (YosegiReader reader = new YosegiReader()) {
+ IExpressionNode index = new AndExpressionNode();
+ index.addChildNode(
+ new ExecuterNode(new StringExtractNode(columnName1), new BooleanFilter(filterValue1)));
+ index.addChildNode(
+ new ExecuterNode(new StringExtractNode(columnName2), new BooleanFilter(filterValue2)));
+ Configuration readerConfig = new Configuration();
+ byte[] data = getData();
+ InputStream in = new ByteArrayInputStream(data);
+ reader.setBlockSkipIndex(index);
+ reader.setNewStream(in, data.length, readerConfig);
+ assertEquals(expected, reader.hasNext());
+ }
+ }
+
+ public static Stream D_blackbox_4() {
+ return Stream.of(
+ // columnName1, filterValue1, columnName2, filterValue2, list{pair, pair ...}
+ arguments(
+ "col1",
+ true,
+ "col2",
+ false,
+ new ArrayList<>(
+ Arrays.asList(
+ new Pair<>("col1", new ArrayList<>(Arrays.asList(true, true, true))),
+ new Pair<>("col2", new ArrayList<>(Arrays.asList(false, false, false))),
+ new Pair<>("col3", new ArrayList<>(Arrays.asList(true, true, false))),
+ new Pair<>("col4", new ArrayList<>(Arrays.asList(true, false, true))),
+ new Pair<>("col5", new ArrayList<>(Arrays.asList(false, false, true))),
+ new Pair<>("col6", new ArrayList<>(Arrays.asList(false, true, false))),
+ new Pair<>("col7", new ArrayList<>(Arrays.asList(true, null, null))),
+ new Pair<>("col8", new ArrayList<>(Arrays.asList(false, null, null))),
+ new Pair<>("col9", new ArrayList<>(Arrays.asList(true, true, null))),
+ new Pair<>("col10", new ArrayList<>(Arrays.asList(true, false, null))),
+ new Pair<>("col11", new ArrayList<>(Arrays.asList(false, false, null))),
+ new Pair<>("col12", new ArrayList<>(Arrays.asList(false, true, null))),
+ new Pair<>("col13", new ArrayList<>(Arrays.asList(true, null, true))),
+ new Pair<>("col14", new ArrayList<>(Arrays.asList(true, null, false))),
+ new Pair<>("col15", new ArrayList<>(Arrays.asList(false, null, false))),
+ new Pair<>("col16", new ArrayList<>(Arrays.asList(false, null, true)))))));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_blackbox_4")
+ public void T_blackbox_4(
+ final String columnName1,
+ final Boolean filterValue1,
+ final String columnName2,
+ final Boolean filterValue2,
+ List>> expecteds)
+ throws IOException {
+ try (YosegiReader reader = new YosegiReader()) {
+ IExpressionNode index = new AndExpressionNode();
+ index.addChildNode(
+ new ExecuterNode(new StringExtractNode(columnName1), new BooleanFilter(filterValue1)));
+ index.addChildNode(
+ new ExecuterNode(new StringExtractNode(columnName2), new BooleanFilter(filterValue2)));
+ Configuration readerConfig = new Configuration();
+ byte[] data = getData();
+ InputStream in = new ByteArrayInputStream(data);
+ reader.setBlockSkipIndex(index);
+ reader.setNewStream(in, data.length, readerConfig);
+ while (reader.hasNext()) {
+ Spread spread = reader.next();
+ for (Pair> expected : expecteds) {
+ IColumn col = spread.getColumn(expected.getKey());
+ for (int i = 0; i < spread.size(); i++) {
+ List expectedValues = expected.getValue();
+ if (expectedValues.get(i) == null) {
+ assertEquals(ColumnType.NULL, col.get(i).getType());
+ } else {
+ assertEquals(
+ expectedValues.get(i), ((PrimitiveObject) col.get(i).getRow()).getBoolean());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public static Stream D_blackbox_5() {
+ return Stream.of(
+ // columnName, filterValue, expected(hasNext)
+ arguments("col1", true, true),
+ arguments("col1", false, false),
+ arguments("col2", true, false),
+ arguments("col2", false, true),
+ arguments("col3", true, true),
+ arguments("col3", false, true),
+ arguments("col4", true, true),
+ arguments("col4", false, true),
+ arguments("col5", true, true),
+ arguments("col6", false, true),
+ arguments("col7", true, true),
+ arguments("col7", false, false),
+ arguments("col8", true, false),
+ arguments("col8", false, true),
+ arguments("col9", true, true),
+ arguments("col9", false, false),
+ arguments("col10", true, true),
+ arguments("col10", false, true),
+ arguments("col11", true, false),
+ arguments("col11", false, true),
+ arguments("col12", true, true),
+ arguments("col12", false, true),
+ arguments("col13", true, true),
+ arguments("col13", false, false),
+ arguments("col14", true, true),
+ arguments("col14", false, true),
+ arguments("col15", true, false),
+ arguments("col15", false, true),
+ arguments("col16", true, true),
+ arguments("col16", false, true));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_blackbox_5")
+ public void T_blackbox_5(
+ final String columnName, final Boolean filterValue, final Boolean expected)
+ throws IOException {
+ try (YosegiReader reader = new YosegiReader()) {
+ IExpressionNode index = new OrExpressionNode();
+ index.addChildNode(
+ new ExecuterNode(new StringExtractNode(columnName), new BooleanFilter(filterValue)));
+ Configuration readerConfig = new Configuration();
+ byte[] data = getData();
+ InputStream in = new ByteArrayInputStream(data);
+ reader.setBlockSkipIndex(index);
+ reader.setNewStream(in, data.length, readerConfig);
+ assertEquals(expected, reader.hasNext());
+ }
+ }
+
+ public static Stream D_blackbox_6() {
+ return Stream.of(
+ // columnName1, filterValue1, columnName2, filterValue2, expected(hasNext)
+ arguments("col1", true, "col2", true, true),
+ arguments("col1", true, "col2", false, true),
+ arguments("col1", false, "col2", false, true),
+ arguments("col1", false, "col2", true, false));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_blackbox_6")
+ public void T_blackbox_6(
+ final String columnName1,
+ final Boolean filterValue1,
+ final String columnName2,
+ final Boolean filterValue2,
+ final Boolean expected)
+ throws IOException {
+ try (YosegiReader reader = new YosegiReader()) {
+ IExpressionNode index = new OrExpressionNode();
+ index.addChildNode(
+ new ExecuterNode(new StringExtractNode(columnName1), new BooleanFilter(filterValue1)));
+ index.addChildNode(
+ new ExecuterNode(new StringExtractNode(columnName2), new BooleanFilter(filterValue2)));
+ Configuration readerConfig = new Configuration();
+ byte[] data = getData();
+ InputStream in = new ByteArrayInputStream(data);
+ reader.setBlockSkipIndex(index);
+ reader.setNewStream(in, data.length, readerConfig);
+ assertEquals(expected, reader.hasNext());
+ }
+ }
+
+ public static Stream D_blackbox_7() {
+ return Stream.of(
+ // columnName1, filterValue1, columnName2, filterValue2, list{pair, pair ...}
+ arguments(
+ "col1",
+ true,
+ "col2",
+ false,
+ new ArrayList<>(
+ Arrays.asList(
+ new Pair<>("col1", new ArrayList<>(Arrays.asList(true, true, true))),
+ new Pair<>("col2", new ArrayList<>(Arrays.asList(false, false, false))),
+ new Pair<>("col3", new ArrayList<>(Arrays.asList(true, true, false))),
+ new Pair<>("col4", new ArrayList<>(Arrays.asList(true, false, true))),
+ new Pair<>("col5", new ArrayList<>(Arrays.asList(false, false, true))),
+ new Pair<>("col6", new ArrayList<>(Arrays.asList(false, true, false))),
+ new Pair<>("col7", new ArrayList<>(Arrays.asList(true, null, null))),
+ new Pair<>("col8", new ArrayList<>(Arrays.asList(false, null, null))),
+ new Pair<>("col9", new ArrayList<>(Arrays.asList(true, true, null))),
+ new Pair<>("col10", new ArrayList<>(Arrays.asList(true, false, null))),
+ new Pair<>("col11", new ArrayList<>(Arrays.asList(false, false, null))),
+ new Pair<>("col12", new ArrayList<>(Arrays.asList(false, true, null))),
+ new Pair<>("col13", new ArrayList<>(Arrays.asList(true, null, true))),
+ new Pair<>("col14", new ArrayList<>(Arrays.asList(true, null, false))),
+ new Pair<>("col15", new ArrayList<>(Arrays.asList(false, null, false))),
+ new Pair<>("col16", new ArrayList<>(Arrays.asList(false, null, true)))))),
+ arguments(
+ "col1",
+ true,
+ "col2",
+ true,
+ new ArrayList<>(
+ Arrays.asList(
+ new Pair<>("col1", new ArrayList<>(Arrays.asList(true, true, true))),
+ new Pair<>("col2", new ArrayList<>(Arrays.asList(false, false, false))),
+ new Pair<>("col3", new ArrayList<>(Arrays.asList(true, true, false))),
+ new Pair<>("col4", new ArrayList<>(Arrays.asList(true, false, true))),
+ new Pair<>("col5", new ArrayList<>(Arrays.asList(false, false, true))),
+ new Pair<>("col6", new ArrayList<>(Arrays.asList(false, true, false))),
+ new Pair<>("col7", new ArrayList<>(Arrays.asList(true, null, null))),
+ new Pair<>("col8", new ArrayList<>(Arrays.asList(false, null, null))),
+ new Pair<>("col9", new ArrayList<>(Arrays.asList(true, true, null))),
+ new Pair<>("col10", new ArrayList<>(Arrays.asList(true, false, null))),
+ new Pair<>("col11", new ArrayList<>(Arrays.asList(false, false, null))),
+ new Pair<>("col12", new ArrayList<>(Arrays.asList(false, true, null))),
+ new Pair<>("col13", new ArrayList<>(Arrays.asList(true, null, true))),
+ new Pair<>("col14", new ArrayList<>(Arrays.asList(true, null, false))),
+ new Pair<>("col15", new ArrayList<>(Arrays.asList(false, null, false))),
+ new Pair<>("col16", new ArrayList<>(Arrays.asList(false, null, true)))))),
+ arguments(
+ "col1",
+ false,
+ "col2",
+ false,
+ new ArrayList<>(
+ Arrays.asList(
+ new Pair<>("col1", new ArrayList<>(Arrays.asList(true, true, true))),
+ new Pair<>("col2", new ArrayList<>(Arrays.asList(false, false, false))),
+ new Pair<>("col3", new ArrayList<>(Arrays.asList(true, true, false))),
+ new Pair<>("col4", new ArrayList<>(Arrays.asList(true, false, true))),
+ new Pair<>("col5", new ArrayList<>(Arrays.asList(false, false, true))),
+ new Pair<>("col6", new ArrayList<>(Arrays.asList(false, true, false))),
+ new Pair<>("col7", new ArrayList<>(Arrays.asList(true, null, null))),
+ new Pair<>("col8", new ArrayList<>(Arrays.asList(false, null, null))),
+ new Pair<>("col9", new ArrayList<>(Arrays.asList(true, true, null))),
+ new Pair<>("col10", new ArrayList<>(Arrays.asList(true, false, null))),
+ new Pair<>("col11", new ArrayList<>(Arrays.asList(false, false, null))),
+ new Pair<>("col12", new ArrayList<>(Arrays.asList(false, true, null))),
+ new Pair<>("col13", new ArrayList<>(Arrays.asList(true, null, true))),
+ new Pair<>("col14", new ArrayList<>(Arrays.asList(true, null, false))),
+ new Pair<>("col15", new ArrayList<>(Arrays.asList(false, null, false))),
+ new Pair<>("col16", new ArrayList<>(Arrays.asList(false, null, true)))))));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_blackbox_7")
+ public void T_blackbox_7(
+ final String columnName1,
+ final Boolean filterValue1,
+ final String columnName2,
+ final Boolean filterValue2,
+ List>> expecteds)
+ throws IOException {
+ try (YosegiReader reader = new YosegiReader()) {
+ IExpressionNode index = new OrExpressionNode();
+ index.addChildNode(
+ new ExecuterNode(new StringExtractNode(columnName1), new BooleanFilter(filterValue1)));
+ index.addChildNode(
+ new ExecuterNode(new StringExtractNode(columnName2), new BooleanFilter(filterValue2)));
+ Configuration readerConfig = new Configuration();
+ byte[] data = getData();
+ InputStream in = new ByteArrayInputStream(data);
+ reader.setBlockSkipIndex(index);
+ reader.setNewStream(in, data.length, readerConfig);
+ while (reader.hasNext()) {
+ Spread spread = reader.next();
+ for (Pair> expected : expecteds) {
+ IColumn col = spread.getColumn(expected.getKey());
+ for (int i = 0; i < spread.size(); i++) {
+ List expectedValues = expected.getValue();
+ if (expectedValues.get(i) == null) {
+ assertEquals(ColumnType.NULL, col.get(i).getType());
+ } else {
+ assertEquals(
+ expectedValues.get(i), ((PrimitiveObject) col.get(i).getRow()).getBoolean());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public static Stream D_blackbox_8() {
+ return Stream.of(
+ // NOTE: NotExpressionNode does not work.
+ // columnName, filterValue, expected(hasNext)
+ arguments("col1", true, true), // false
+ arguments("col1", false, true),
+ arguments("col2", true, true),
+ arguments("col2", false, true), // false
+ arguments("col3", true, true), // false
+ arguments("col3", false, true), // false
+ arguments("col4", true, true), // false
+ arguments("col4", false, true), // false
+ arguments("col5", true, true), // false
+ arguments("col6", false, true), // false
+ arguments("col7", true, true), // false
+ arguments("col7", false, true),
+ arguments("col8", true, true),
+ arguments("col8", false, true),
+ arguments("col9", true, true), // false
+ arguments("col9", false, true),
+ arguments("col10", true, true), // false
+ arguments("col10", false, true), // false
+ arguments("col11", true, true),
+ arguments("col11", false, true), // false
+ arguments("col12", true, true), // false
+ arguments("col12", false, true), // false
+ arguments("col13", true, true), // false
+ arguments("col13", false, true),
+ arguments("col14", true, true), // false
+ arguments("col14", false, true), // false
+ arguments("col15", true, true),
+ arguments("col15", false, true), // false
+ arguments("col16", true, true), // false
+ arguments("col16", false, true)); // false
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_blackbox_8")
+ public void T_blackbox_8(
+ final String columnName, final Boolean filterValue, final Boolean expected)
+ throws IOException {
+ try (YosegiReader reader = new YosegiReader()) {
+ IExpressionNode index = new NotExpressionNode();
+ index.addChildNode(
+ new ExecuterNode(new StringExtractNode(columnName), new BooleanFilter(filterValue)));
+ Configuration readerConfig = new Configuration();
+ byte[] data = getData();
+ InputStream in = new ByteArrayInputStream(data);
+ reader.setBlockSkipIndex(index);
+ reader.setNewStream(in, data.length, readerConfig);
+ assertEquals(expected, reader.hasNext());
+ }
+ }
+
+ public static Stream D_blackbox_9() {
+ return Stream.of(
+ // columnName, filterValue, list{pair, pair ...}
+ arguments(
+ "col1",
+ true,
+ new ArrayList<>(
+ Arrays.asList(
+ new Pair<>("col1", new ArrayList<>(Arrays.asList(true, true, true))),
+ new Pair<>("col2", new ArrayList<>(Arrays.asList(false, false, false))),
+ new Pair<>("col3", new ArrayList<>(Arrays.asList(true, true, false))),
+ new Pair<>("col4", new ArrayList<>(Arrays.asList(true, false, true))),
+ new Pair<>("col5", new ArrayList<>(Arrays.asList(false, false, true))),
+ new Pair<>("col6", new ArrayList<>(Arrays.asList(false, true, false))),
+ new Pair<>("col7", new ArrayList<>(Arrays.asList(true, null, null))),
+ new Pair<>("col8", new ArrayList<>(Arrays.asList(false, null, null))),
+ new Pair<>("col9", new ArrayList<>(Arrays.asList(true, true, null))),
+ new Pair<>("col10", new ArrayList<>(Arrays.asList(true, false, null))),
+ new Pair<>("col11", new ArrayList<>(Arrays.asList(false, false, null))),
+ new Pair<>("col12", new ArrayList<>(Arrays.asList(false, true, null))),
+ new Pair<>("col13", new ArrayList<>(Arrays.asList(true, null, true))),
+ new Pair<>("col14", new ArrayList<>(Arrays.asList(true, null, false))),
+ new Pair<>("col15", new ArrayList<>(Arrays.asList(false, null, false))),
+ new Pair<>("col16", new ArrayList<>(Arrays.asList(false, null, true)))))),
+ arguments(
+ "col1",
+ false,
+ new ArrayList<>(
+ Arrays.asList(
+ new Pair<>("col1", new ArrayList<>(Arrays.asList(true, true, true))),
+ new Pair<>("col2", new ArrayList<>(Arrays.asList(false, false, false))),
+ new Pair<>("col3", new ArrayList<>(Arrays.asList(true, true, false))),
+ new Pair<>("col4", new ArrayList<>(Arrays.asList(true, false, true))),
+ new Pair<>("col5", new ArrayList<>(Arrays.asList(false, false, true))),
+ new Pair<>("col6", new ArrayList<>(Arrays.asList(false, true, false))),
+ new Pair<>("col7", new ArrayList<>(Arrays.asList(true, null, null))),
+ new Pair<>("col8", new ArrayList<>(Arrays.asList(false, null, null))),
+ new Pair<>("col9", new ArrayList<>(Arrays.asList(true, true, null))),
+ new Pair<>("col10", new ArrayList<>(Arrays.asList(true, false, null))),
+ new Pair<>("col11", new ArrayList<>(Arrays.asList(false, false, null))),
+ new Pair<>("col12", new ArrayList<>(Arrays.asList(false, true, null))),
+ new Pair<>("col13", new ArrayList<>(Arrays.asList(true, null, true))),
+ new Pair<>("col14", new ArrayList<>(Arrays.asList(true, null, false))),
+ new Pair<>("col15", new ArrayList<>(Arrays.asList(false, null, false))),
+ new Pair<>("col16", new ArrayList<>(Arrays.asList(false, null, true)))))));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_blackbox_9")
+ public void T_blackbox_9(
+ final String columnName,
+ final Boolean filterValue,
+ List>> expecteds)
+ throws IOException {
+ try (YosegiReader reader = new YosegiReader()) {
+ IExpressionNode index = new NotExpressionNode();
+ index.addChildNode(
+ new ExecuterNode(new StringExtractNode(columnName), new BooleanFilter(filterValue)));
+ Configuration readerConfig = new Configuration();
+ byte[] data = getData();
+ InputStream in = new ByteArrayInputStream(data);
+ reader.setBlockSkipIndex(index);
+ reader.setNewStream(in, data.length, readerConfig);
+ while (reader.hasNext()) {
+ Spread spread = reader.next();
+ for (Pair> expected : expecteds) {
+ IColumn col = spread.getColumn(expected.getKey());
+ for (int i = 0; i < spread.size(); i++) {
+ List expectedValues = expected.getValue();
+ if (expectedValues.get(i) == null) {
+ assertEquals(ColumnType.NULL, col.get(i).getType());
+ } else {
+ assertEquals(
+ expectedValues.get(i), ((PrimitiveObject) col.get(i).getRow()).getBoolean());
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/jp/co/yahoo/yosegi/blackbox/TestBooleanCellIndex.java b/src/test/java/jp/co/yahoo/yosegi/blackbox/TestBooleanCellIndex.java
index d2c64dd8..71dcfc2c 100644
--- a/src/test/java/jp/co/yahoo/yosegi/blackbox/TestBooleanCellIndex.java
+++ b/src/test/java/jp/co/yahoo/yosegi/blackbox/TestBooleanCellIndex.java
@@ -49,7 +49,8 @@ public static Stream data1() throws IOException{
return Stream.of(
arguments( createBooleanTestData( "jp.co.yahoo.yosegi.binary.maker.DumpBooleanColumnBinaryMaker" ) ),
arguments( createBooleanTestData( "jp.co.yahoo.yosegi.binary.maker.OptimizedNullArrayDumpBooleanColumnBinaryMaker" ) ),
- arguments( createBytesTestData( "jp.co.yahoo.yosegi.binary.maker.DumpBytesColumnBinaryMaker" ) )
+ arguments( createBytesTestData( "jp.co.yahoo.yosegi.binary.maker.DumpBytesColumnBinaryMaker" ) ),
+ arguments( createBooleanTestData( "jp.co.yahoo.yosegi.binary.maker.FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker" ) )
);
}
diff --git a/src/test/java/jp/co/yahoo/yosegi/blackbox/TestBooleanPrimitiveColumn.java b/src/test/java/jp/co/yahoo/yosegi/blackbox/TestBooleanPrimitiveColumn.java
index e7493511..97a96eff 100644
--- a/src/test/java/jp/co/yahoo/yosegi/blackbox/TestBooleanPrimitiveColumn.java
+++ b/src/test/java/jp/co/yahoo/yosegi/blackbox/TestBooleanPrimitiveColumn.java
@@ -48,7 +48,8 @@ public class TestBooleanPrimitiveColumn {
public static Stream data1() throws IOException{
return Stream.of(
arguments( "jp.co.yahoo.yosegi.binary.maker.DumpBooleanColumnBinaryMaker" ),
- arguments( "jp.co.yahoo.yosegi.binary.maker.OptimizedNullArrayDumpBooleanColumnBinaryMaker" )
+ arguments( "jp.co.yahoo.yosegi.binary.maker.OptimizedNullArrayDumpBooleanColumnBinaryMaker" ),
+ arguments( "jp.co.yahoo.yosegi.binary.maker.FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker" )
);
}
diff --git a/src/test/java/jp/co/yahoo/yosegi/blackbox/TestCalcLogicalDataSizeBoolean.java b/src/test/java/jp/co/yahoo/yosegi/blackbox/TestCalcLogicalDataSizeBoolean.java
index a4ecc0dd..37407494 100644
--- a/src/test/java/jp/co/yahoo/yosegi/blackbox/TestCalcLogicalDataSizeBoolean.java
+++ b/src/test/java/jp/co/yahoo/yosegi/blackbox/TestCalcLogicalDataSizeBoolean.java
@@ -39,7 +39,8 @@ public class TestCalcLogicalDataSizeBoolean {
public static Stream data1() throws IOException {
return Stream.of(
arguments( "jp.co.yahoo.yosegi.binary.maker.DumpBooleanColumnBinaryMaker" ),
- arguments( "jp.co.yahoo.yosegi.binary.maker.OptimizedNullArrayDumpBooleanColumnBinaryMaker" )
+ arguments( "jp.co.yahoo.yosegi.binary.maker.OptimizedNullArrayDumpBooleanColumnBinaryMaker" ),
+ arguments( "jp.co.yahoo.yosegi.binary.maker.FlagIndexedOptimizedNullArrayDumpBooleanColumnBinaryMaker" )
);
}
diff --git a/src/test/java/jp/co/yahoo/yosegi/blockindex/TestRangeBlockIndexNameShortCut.java b/src/test/java/jp/co/yahoo/yosegi/blockindex/TestBlockIndexNameShortCut.java
similarity index 84%
rename from src/test/java/jp/co/yahoo/yosegi/blockindex/TestRangeBlockIndexNameShortCut.java
rename to src/test/java/jp/co/yahoo/yosegi/blockindex/TestBlockIndexNameShortCut.java
index c30da31a..3b724300 100644
--- a/src/test/java/jp/co/yahoo/yosegi/blockindex/TestRangeBlockIndexNameShortCut.java
+++ b/src/test/java/jp/co/yahoo/yosegi/blockindex/TestBlockIndexNameShortCut.java
@@ -21,7 +21,6 @@
import java.util.stream.Stream;
-import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.Arguments;
@@ -29,7 +28,7 @@
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.params.provider.Arguments.arguments;
-public class TestRangeBlockIndexNameShortCut{
+public class TestBlockIndexNameShortCut {
public static Stream data1() {
return Stream.of(
@@ -39,15 +38,17 @@ public static Stream data1() {
arguments( "jp.co.yahoo.yosegi.blockindex.LongRangeBlockIndex" , "R3" ),
arguments( "jp.co.yahoo.yosegi.blockindex.FloatRangeBlockIndex" , "R4" ),
arguments( "jp.co.yahoo.yosegi.blockindex.DoubleRangeBlockIndex" , "R5" ),
- arguments( "jp.co.yahoo.yosegi.blockindex.StringRangeBlockIndex" , "R6" )
+ arguments( "jp.co.yahoo.yosegi.blockindex.StringRangeBlockIndex" , "R6" ),
+ arguments( "jp.co.yahoo.yosegi.blockindex.FullRangeBlockIndex" , "FR0" ),
+ arguments( "jp.co.yahoo.yosegi.blockindex.BooleanBlockIndex" , "BI0" )
);
}
@ParameterizedTest
@MethodSource( "data1" )
public void T_get_1( final String c , final String sc ) throws IOException{
- assertEquals( sc , RangeBlockIndexNameShortCut.getShortCutName( c ) );
- assertEquals( c , RangeBlockIndexNameShortCut.getClassName( sc ) );
+ assertEquals( sc , BlockIndexNameShortCut.getShortCutName( c ) );
+ assertEquals( c , BlockIndexNameShortCut.getClassName( sc ) );
}
}
diff --git a/src/test/java/jp/co/yahoo/yosegi/blockindex/TestBooleanBlockIndex.java b/src/test/java/jp/co/yahoo/yosegi/blockindex/TestBooleanBlockIndex.java
new file mode 100644
index 00000000..b330a78a
--- /dev/null
+++ b/src/test/java/jp/co/yahoo/yosegi/blockindex/TestBooleanBlockIndex.java
@@ -0,0 +1,235 @@
+/**
+ * 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 jp.co.yahoo.yosegi.blockindex;
+
+import jp.co.yahoo.yosegi.spread.column.filter.BooleanFilter;
+import jp.co.yahoo.yosegi.spread.column.filter.IFilter;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import static org.junit.jupiter.params.provider.Arguments.arguments;
+
+class TestBooleanBlockIndex {
+
+ @Test
+ public void T_newInstance_1() {
+ BooleanBlockIndex blockIndex = new BooleanBlockIndex();
+ assertFalse(blockIndex.hasTrue());
+ assertFalse(blockIndex.hasFalse());
+ assertFalse(blockIndex.hasNull());
+ }
+
+ public static Stream D_newInstance_2() {
+ // hasTrue, hasFalse, hasNull
+ return Stream.of(
+ arguments(true, true, true),
+ arguments(true, true, false),
+ arguments(true, false, true),
+ arguments(true, false, false),
+ arguments(false, false, false),
+ arguments(false, false, true),
+ arguments(false, true, false),
+ arguments(false, true, true));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_newInstance_2")
+ public void T_newInstance_2(
+ final boolean hasTrue, final boolean hasFalse, final boolean hasNull) {
+ BooleanBlockIndex blockIndex = new BooleanBlockIndex(hasTrue, hasFalse, hasNull);
+ assertEquals(hasTrue, blockIndex.hasTrue());
+ assertEquals(hasFalse, blockIndex.hasFalse());
+ assertEquals(hasNull, blockIndex.hasNull());
+ }
+
+ @Test
+ public void T_getBlockIndexType_1() {
+ BooleanBlockIndex blockIndex = new BooleanBlockIndex();
+ assertEquals(BlockIndexType.BOOLEAN, blockIndex.getBlockIndexType());
+ }
+
+ public static Stream D_merge_1() {
+ return Stream.of(
+ // initial values, merge values, expected values
+ arguments(
+ new Boolean[] {false, false, false},
+ new Boolean[] {true, false, false},
+ new Boolean[] {true, false, false}),
+ arguments(
+ new Boolean[] {false, false, false},
+ new Boolean[] {false, true, false},
+ new Boolean[] {false, true, false}),
+ arguments(
+ new Boolean[] {false, false, false},
+ new Boolean[] {false, false, true},
+ new Boolean[] {false, false, true}),
+ arguments(
+ new Boolean[] {true, false, false},
+ new Boolean[] {false, false, false},
+ new Boolean[] {true, false, false}),
+ arguments(
+ new Boolean[] {false, true, false},
+ new Boolean[] {false, false, false},
+ new Boolean[] {false, true, false}),
+ arguments(
+ new Boolean[] {true, true, true},
+ new Boolean[] {true, true, true},
+ new Boolean[] {true, true, true}),
+ arguments(
+ new Boolean[] {false, false, false},
+ new Boolean[] {false, false, false},
+ new Boolean[] {false, false, false}),
+ arguments(
+ new Boolean[] {false, false, false},
+ new Boolean[] {true, true, true},
+ new Boolean[] {true, true, true}),
+ arguments(
+ new Boolean[] {true, true, true},
+ new Boolean[] {false, false, false},
+ new Boolean[] {true, true, true}));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_merge_1")
+ public void T_merge_1(final Boolean[] initial, final Boolean[] merge, final Boolean[] expected) {
+ BooleanBlockIndex blockIndex = new BooleanBlockIndex(initial[0], initial[1], initial[2]);
+ assertTrue(blockIndex.merge(new BooleanBlockIndex(merge[0], merge[1], merge[2])));
+ assertEquals(expected[0], blockIndex.hasTrue());
+ assertEquals(expected[1], blockIndex.hasFalse());
+ assertEquals(expected[2], blockIndex.hasNull());
+ }
+
+ @Test
+ public void T_getBinarySize_1() {
+ BooleanBlockIndex blockIndex = new BooleanBlockIndex(true, true, true);
+ assertEquals(Byte.BYTES, blockIndex.getBinarySize());
+ }
+
+ public static Stream D_binary_1() {
+ return Stream.of(
+ arguments(true, true, true),
+ arguments(true, true, false),
+ arguments(true, false, true),
+ arguments(true, false, false),
+ arguments(false, false, false),
+ arguments(false, false, true),
+ arguments(false, true, false),
+ arguments(false, true, true));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_binary_1")
+ public void T_binary_0(final boolean hasTrue, final boolean hasFalse, final boolean hasNull) {
+ BooleanBlockIndex blockIndex = new BooleanBlockIndex(hasTrue, hasFalse, hasNull);
+ byte[] binary = blockIndex.toBinary();
+ assertEquals(binary.length, blockIndex.getBinarySize());
+ BooleanBlockIndex blockIndex2 = new BooleanBlockIndex();
+ assertFalse(blockIndex2.hasTrue());
+ assertFalse(blockIndex2.hasFalse());
+ assertFalse(blockIndex2.hasNull());
+ blockIndex2.setFromBinary(binary, 0, binary.length);
+ assertEquals(hasTrue, blockIndex2.hasTrue());
+ assertEquals(hasFalse, blockIndex2.hasFalse());
+ assertEquals(hasNull, blockIndex2.hasNull());
+ }
+
+ public static Stream D_canBlockSkip_1() {
+ return Stream.of(
+ arguments(new BooleanBlockIndex(true, false, false), new BooleanFilter(true), false),
+ arguments(new BooleanBlockIndex(true, false, false), new BooleanFilter(false), true),
+ arguments(new BooleanBlockIndex(false, true, false), new BooleanFilter(true), true),
+ arguments(new BooleanBlockIndex(false, true, false), new BooleanFilter(false), false),
+ arguments(new BooleanBlockIndex(false, false, true), new BooleanFilter(true), true),
+ arguments(new BooleanBlockIndex(false, false, true), new BooleanFilter(false), true),
+ arguments(new BooleanBlockIndex(true, true, false), new BooleanFilter(true), false),
+ arguments(new BooleanBlockIndex(true, true, false), new BooleanFilter(false), false),
+ arguments(new BooleanBlockIndex(true, false, true), new BooleanFilter(true), false),
+ arguments(new BooleanBlockIndex(true, false, true), new BooleanFilter(false), true),
+ arguments(new BooleanBlockIndex(false, true, true), new BooleanFilter(true), true),
+ arguments(new BooleanBlockIndex(false, true, true), new BooleanFilter(false), false),
+ arguments(new BooleanBlockIndex(true, true, true), new BooleanFilter(true), false),
+ arguments(new BooleanBlockIndex(true, true, true), new BooleanFilter(false), false));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_canBlockSkip_1")
+ public void T_canBlockSkip_1(
+ final IBlockIndex blockIndex, final IFilter filter, final boolean result) {
+ if (result) {
+ assertEquals(result, blockIndex.getBlockSpreadIndex(filter).isEmpty());
+ } else {
+ assertNull(blockIndex.getBlockSpreadIndex(filter));
+ }
+ }
+
+ public static Stream D_bitFlags_1() {
+ return Stream.of(
+ // bitFlags, hasTrue, hasFalse, hasNull
+ arguments((byte) 0b111, true, true, true),
+ arguments((byte) 0b110, false, true, true),
+ arguments((byte) 0b101, true, false, true),
+ arguments((byte) 0b100, false, false, true),
+ arguments((byte) 0b000, false, false, false),
+ arguments((byte) 0b001, true, false, false),
+ arguments((byte) 0b010, false, true, false),
+ arguments((byte) 0b011, true, true, false));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_bitFlags_1")
+ public void T_bitFlags_1(
+ final byte flags, final boolean hasTrue, final boolean hasFalse, final boolean hasNull) {
+ BooleanBlockIndex.BitFlags bitFlags = new BooleanBlockIndex.BitFlags(flags);
+ assertEquals(hasTrue, bitFlags.hasTrue());
+ assertEquals(hasFalse, bitFlags.hasFalse());
+ assertEquals(hasNull, bitFlags.hasNull());
+ assertEquals(flags, bitFlags.getBitFlags());
+ }
+
+ public static Stream D_bitFlags_2() {
+ return Stream.of(
+ // bitFlags, hasTrue, hasFalse, hasNull
+ arguments((byte) 0b111, true, true, true),
+ arguments((byte) 0b110, false, true, true),
+ arguments((byte) 0b101, true, false, true),
+ arguments((byte) 0b100, false, false, true),
+ arguments((byte) 0b000, false, false, false),
+ arguments((byte) 0b001, true, false, false),
+ arguments((byte) 0b010, false, true, false),
+ arguments((byte) 0b011, true, true, false));
+ }
+
+ @ParameterizedTest
+ @MethodSource("D_bitFlags_2")
+ public void T_bitFlags_2(
+ final byte flags, final boolean hasTrue, final boolean hasFalse, final boolean hasNull) {
+ BooleanBlockIndex.BitFlags bitFlags =
+ new BooleanBlockIndex.BitFlags(hasTrue, hasFalse, hasNull);
+ assertEquals(hasTrue, bitFlags.hasTrue());
+ assertEquals(hasFalse, bitFlags.hasFalse());
+ assertEquals(hasNull, bitFlags.hasNull());
+ assertEquals(flags, bitFlags.getBitFlags());
+ }
+}
diff --git a/src/test/resources/blackbox/TestBooleanBlockIndex.json b/src/test/resources/blackbox/TestBooleanBlockIndex.json
new file mode 100644
index 00000000..395cf1ba
--- /dev/null
+++ b/src/test/resources/blackbox/TestBooleanBlockIndex.json
@@ -0,0 +1,3 @@
+{"col1": true, "col2": false, "col3": true, "col4": true, "col5": false, "col6": false, "col7": true, "col8": false, "col9": true, "col10": true, "col11": false, "col12": false, "col13": true, "col14": true, "col15": false, "col16": false}
+{"col1": true, "col2": false, "col3": true, "col4": false, "col5": false, "col6": true, "col9": true, "col10": false, "col11": false, "col12": true}
+{"col1": true, "col2": false, "col3": false, "col4": true, "col5": true, "col6": false, "col13": true, "col14": false, "col15": false, "col16": true}