blob: 74597f5d995738af50420b8c3027ec5e72c3ae3a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cassandra.utils;
import java.util.List;
import com.google.common.collect.Ordering;
import net.nicoulaj.compilecommand.annotations.Inline;
public abstract class AsymmetricOrdering<T1, T2> extends Ordering<T1>
{
public abstract int compareAsymmetric(T1 left, T2 right);
public static enum Op
{
// maximum index < key; -1 if no such key. == CEIL - 1
LOWER,
// maximum index <= key; -1 if no such key. == HIGHER + 1
FLOOR,
// minimum index >= key; size() if no such key. == LOWER + 1
CEIL,
// minimum index > key; size() if no such key. == FLOOR - 1
HIGHER
}
/**
* @param searchIn sorted list to look in
* @param searchFor key to find
*/
public int binarySearchAsymmetric(List<? extends T1> searchIn, T2 searchFor, Op op)
{
final int strictnessOfLessThan = strictnessOfLessThan(op);
int lb = -1;
int ub = searchIn.size();
// a[-1] ^= -infinity
// a[search.size()] ^= +infinity
while (lb + 1 < ub)
{
int m = (lb + ub) / 2;
int c = compareAsymmetric(searchIn.get(m), searchFor);
if (c < strictnessOfLessThan) lb = m;
else ub = m;
}
return selectBoundary(op, lb, ub);
}
@Inline
// this value, used as the right operand to a less than operator for the result
// of a compare() makes its behaviour either strict (<) or not strict (<=).
// a value of 1 is not strict, whereas 0 is strict
private static int strictnessOfLessThan(Op op)
{
switch (op)
{
case FLOOR: case HIGHER:
// { a[lb] <= v ^ a[ub] > v }
return 1;
// { a[m] > v ==> a[ub] > v ==> a[lb] <= v ^ a[ub] > v }
// { a[m] <= v ==> a[lb] <= v ==> a[lb] <= v ^ a[ub] > v }
case CEIL: case LOWER:
// { a[lb] < v ^ a[ub] >= v }
return 0;
// { a[m] >= v ==> a[ub] >= v ==> a[lb] < v ^ a[ub] >= v }
// { a[m] < v ==> a[lb] < v ==> a[lb] < v ^ a[ub] >= v }
}
throw new IllegalStateException();
}
@Inline
private static int selectBoundary(Op op, int lb, int ub)
{
switch (op)
{
case CEIL:
// { a[lb] < v ^ a[ub] >= v }
case HIGHER:
// { a[lb] <= v ^ a[ub] > v }
return ub;
case FLOOR:
// { a[lb] <= v ^ a[ub] > v }
case LOWER:
// { a[lb] < v ^ a[ub] >= v }
return lb;
}
throw new IllegalStateException();
}
private class Reversed extends AsymmetricOrdering<T1, T2>
{
public int compareAsymmetric(T1 left, T2 right)
{
return -AsymmetricOrdering.this.compareAsymmetric(left, right);
}
public int compare(T1 left, T1 right)
{
return AsymmetricOrdering.this.compare(right, left);
}
public AsymmetricOrdering<T1, T2> reverse()
{
return AsymmetricOrdering.this;
}
}
public AsymmetricOrdering<T1, T2> reverse()
{
return new Reversed();
}
}