001/* 002 * Copyright 2013 Alex Kasko (alexkasko.com) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.alexkasko.unsafe.offheapstruct; 018 019import java.util.Comparator; 020 021/** 022 * Binary search implementation borrowed from {@code https://android.googlesource.com/platform/libcore/+/android-4.2.2_r1/luni/src/main/java/java/util/Arrays.java} 023 * and adapted to {@link com.alexkasko.unsafe.offheapstruct.OffHeapStructCollection} with comparators. 024 * Search methods are not static in this class to prevent internal comparator wrapper object creation on each search call. 025 * All operations on instances of this class are NOT thread-safe. 026 * 027 * @author alexkasko 028 * Date: 9/13/13 029 */ 030public class OffHeapStructBinarySearchWithComparator { 031 private final OffHeapStructCollection col; 032 private final OffHeapStructComparator comp; 033 034 /** 035 * Constructor 036 * 037 * @param collection collection to search over 038 * @param comparator comparator to use for comparing provided structure while searching 039 */ 040 public OffHeapStructBinarySearchWithComparator(OffHeapStructCollection collection, Comparator<OffHeapStructAccessor> comparator) { 041 if(null == collection) throw new IllegalArgumentException("Provided collection is null"); 042 if(null == comparator) throw new IllegalArgumentException("Provided comparator is null"); 043 this.col = collection; 044 this.comp = new OffHeapStructComparator(collection, comparator); 045 } 046 047 /** 048 * Performs a binary search for {@code value} in the ascending sorted off-heap struct collection 049 * comparing provided struct using comparator (both collection and comparator are bound to searcher instance). 050 * Searching in an unsorted collection has an undefined result. It's also undefined which element 051 * is found if there are multiple occurrences of the same element. 052 * 053 * @param struct the structure to find 054 * @return the non-negative index of the element, or a negative index which 055 * is {@code -index - 1} where the element would be inserted. 056 */ 057 public long binarySearch(byte[] struct) { 058 return binarySearch(0, col.size(), struct); 059 } 060 061 /** 062 * Performs a binary search for {@code value} in the ascending sorted off-heap struct collection 063 * comparing provided struct using comparator (both collection and comparator are bound to searcher instance). 064 * in the range specified by fromIndex (inclusive) and toIndex (exclusive). 065 * Searching in an unsorted collection has an undefined result. It's also undefined which element 066 * is found if there are multiple occurrences of the same element. 067 * 068 * @param startIndex the inclusive start index. 069 * @param endIndex the exclusive end index. 070 * @param struct the structure to find 071 * @return the non-negative index of the element, or a negative index which 072 * is {@code -index - 1} where the element would be inserted. 073 * @throws IllegalArgumentException {@code if (startIndex < 0 || startIndex > endIndex || endIndex > collection.size()} 074 */ 075 public long binarySearch(long startIndex, long endIndex, byte[] struct) { 076 if (startIndex < 0 || startIndex > endIndex || endIndex > col.size()) { 077 throw new IllegalArgumentException("Illegal input, collection size: [" + col.size() + "], " + 078 "startIndex: [" + startIndex + "], endIndex: [" + endIndex + "]"); 079 } 080 if(null == struct) throw new IllegalArgumentException("Provided struct is null"); 081 082 int compres; 083 long lo = startIndex; 084 long hi = endIndex - 1; 085 while (lo <= hi) { 086 long mid = (lo + hi) >>> 1; 087 compres = comp.compare(mid, struct); 088 if (compres < 0) { 089 lo = mid + 1; 090 } else if (compres > 0) { 091 hi = mid - 1; 092 } else { 093 return mid; // value found 094 } 095 } 096 return ~lo; // value not present 097 } 098 099 /** 100 * Performs a binary search for {@code value} in the ascending sorted off-heap struct collection 101 * comparing provided struct using comparator (both collection and comparator are bound to searcher instance). 102 * Returns range of indices having given value or empty range. 103 * Searching in an unsorted collection has an undefined result. It's also undefined which element 104 * is found if there are multiple occurrences of the same element. 105 * 106 * @param struct the structure to find 107 * @param out range instance, will be set with start/end indices having given value or with empty value 108 */ 109 public void binarySearchRange(byte[] struct, OffHeapStructBinarySearch.IndexRange out) { 110 binarySearchRange(0, col.size(), struct, out); 111 } 112 113 /** 114 * Performs a binary search for {@code value} in the ascending sorted off-heap struct collection 115 * comparing provided struct using comparator (both collection and comparator are bound to searcher instance). 116 * Returns range of indices having given value or empty range. 117 * Searching in an unsorted collection has an undefined result. It's also undefined which element 118 * is found if there are multiple occurrences of the same element. 119 * 120 * @param startIndex the inclusive start index. 121 * @param endIndex the exclusive end index. 122 * @param struct the structure to find 123 * @param out range instance, will be set with start/end indices having given value or with empty value 124 */ 125 public void binarySearchRange(long startIndex, long endIndex, byte[] struct, OffHeapStructBinarySearch.IndexRange out) { 126 long ind = binarySearch(startIndex, endIndex, struct); 127 if(ind < 0) { 128 out.setEmpty(ind); 129 return; 130 } 131 long from = ind; 132 while (from >= startIndex && comp.eq(from, struct)) { 133 from -= 1; 134 } 135 from += 1; 136 long to = ind; 137 while (to < endIndex && comp.eq(to, struct)) { 138 to += 1; 139 } 140 to -= 1; 141 out.set(from, to); 142 } 143 144 /** 145 * {@inheritDoc} 146 */ 147 @Override 148 public String toString() { 149 final StringBuilder sb = new StringBuilder(); 150 sb.append("OffHeapStructBinarySearchWithComparator"); 151 sb.append("{col=").append(col); 152 sb.append(", comp=").append(comp); 153 sb.append('}'); 154 return sb.toString(); 155 } 156}