/*
* Copyright (C) 2014 Indeed Inc.
*
* Licensed 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 com.indeed.flamdex.search;
import com.indeed.flamdex.api.FlamdexOutOfMemoryException;
import com.indeed.flamdex.api.FlamdexReader;
import com.indeed.flamdex.datastruct.FastBitSet;
import com.indeed.flamdex.datastruct.FastBitSetPooler;
import com.indeed.flamdex.query.BooleanOp;
import java.util.List;
/**
* @author jsgroth
*/
class BooleanQueryEvaluator implements QueryEvaluator {
private final BooleanOp operator;
private final List<? extends QueryEvaluator> operands;
BooleanQueryEvaluator(BooleanOp operator, List<? extends QueryEvaluator> operands) {
if (operator == BooleanOp.NOT && operands.size() != 1) {
throw new IllegalArgumentException("bug, more than one operand is disallowed with NOT");
}
this.operator = operator;
this.operands = operands;
}
@Override
public void and(FlamdexReader r, FastBitSet bitSet, FastBitSetPooler bitSetPooler) throws FlamdexOutOfMemoryException {
if (operator == BooleanOp.AND) {
for (final QueryEvaluator operand : operands) {
operand.and(r, bitSet, bitSetPooler);
}
} else {
FastBitSet tmp = bitSetPooler.create(bitSet.size());
try {
if (operator == BooleanOp.OR) {
for (final QueryEvaluator operand : operands) {
operand.or(r, tmp, bitSetPooler);
}
} else {
operands.get(0).not(r, tmp, bitSetPooler);
}
bitSet.and(tmp);
} finally {
final long bytes = tmp.memoryUsage();
tmp = null;
bitSetPooler.release(bytes);
}
}
}
@Override
public void or(FlamdexReader r, FastBitSet bitSet, FastBitSetPooler bitSetPooler) throws FlamdexOutOfMemoryException {
if (operator == BooleanOp.OR) {
for (final QueryEvaluator operand : operands) {
operand.or(r, bitSet, bitSetPooler);
}
} else {
FastBitSet tmp = bitSetPooler.create(bitSet.size());
try {
if (operator == BooleanOp.AND) {
tmp.setAll();
for (final QueryEvaluator operand : operands) {
operand.and(r, tmp, bitSetPooler);
}
} else {
operands.get(0).not(r, tmp, bitSetPooler);
}
bitSet.or(tmp);
} finally {
final long bytes = tmp.memoryUsage();
tmp = null;
bitSetPooler.release(bytes);
}
}
}
@Override
public void not(FlamdexReader r, FastBitSet bitSet, FastBitSetPooler bitSetPooler) throws FlamdexOutOfMemoryException {
if (operator == BooleanOp.NOT) {
throw new IllegalArgumentException("invalid query tree, two NOTs in a row is not allowed");
} else if (operator == BooleanOp.AND) {
bitSet.setAll();
for (final QueryEvaluator operand : operands) {
operand.and(r, bitSet, bitSetPooler);
}
} else {
bitSet.clearAll();
for (final QueryEvaluator operand : operands) {
operand.or(r, bitSet, bitSetPooler);
}
}
bitSet.invertAll();
}
}