2023-03-04 13:19:01 +01:00
|
|
|
package nu.marginalia.array.algo;
|
2023-01-08 11:11:44 +01:00
|
|
|
|
2024-05-18 13:23:06 +02:00
|
|
|
import nu.marginalia.array.page.LongQueryBuffer;
|
2023-01-08 11:11:44 +01:00
|
|
|
|
|
|
|
public interface LongArraySearch extends LongArrayBase {
|
|
|
|
|
|
|
|
default long binarySearch(long key, long fromIndex, long toIndex) {
|
|
|
|
long low = 0;
|
|
|
|
long high = (toIndex - fromIndex) - 1;
|
2024-05-17 14:30:06 +02:00
|
|
|
long len = high - low;
|
2023-01-08 11:11:44 +01:00
|
|
|
|
2024-05-17 14:30:06 +02:00
|
|
|
while (len > 0) {
|
|
|
|
var half = len / 2;
|
|
|
|
if (get(fromIndex + low + half) < key) {
|
|
|
|
low += len - half;
|
|
|
|
}
|
|
|
|
len = half;
|
2023-01-08 11:11:44 +01:00
|
|
|
}
|
|
|
|
|
2024-05-17 14:30:06 +02:00
|
|
|
return fromIndex + low;
|
2023-01-08 11:11:44 +01:00
|
|
|
}
|
|
|
|
|
2024-05-17 14:30:06 +02:00
|
|
|
default long binarySearchN(int sz, long key, long fromIndex, long toIndex) {
|
2023-01-08 11:11:44 +01:00
|
|
|
long low = 0;
|
|
|
|
long high = (toIndex - fromIndex)/sz - 1;
|
2024-05-17 14:30:06 +02:00
|
|
|
long len = high - low;
|
2023-01-08 11:11:44 +01:00
|
|
|
|
2024-05-17 14:30:06 +02:00
|
|
|
while (len > 0) {
|
|
|
|
var half = len / 2;
|
|
|
|
if (get(fromIndex + sz * (low + half)) < key) {
|
|
|
|
low += len - half;
|
|
|
|
}
|
|
|
|
len = half;
|
2023-01-08 11:11:44 +01:00
|
|
|
}
|
|
|
|
|
2024-05-17 14:30:06 +02:00
|
|
|
return fromIndex + sz * low;
|
2023-01-08 11:11:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
default void retain(LongQueryBuffer buffer, long boundary, long searchStart, long searchEnd) {
|
|
|
|
|
|
|
|
if (searchStart >= searchEnd) return;
|
|
|
|
|
|
|
|
long bv = buffer.currentValue();
|
|
|
|
long av = get(searchStart);
|
|
|
|
long pos = searchStart;
|
|
|
|
|
|
|
|
while (bv <= boundary && buffer.hasMore()) {
|
|
|
|
if (bv < av) {
|
|
|
|
if (!buffer.rejectAndAdvance()) break;
|
|
|
|
bv = buffer.currentValue();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (bv == av) {
|
|
|
|
if (!buffer.retainAndAdvance()) break;
|
|
|
|
bv = buffer.currentValue();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (++pos < searchEnd) {
|
|
|
|
av = get(pos);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
default void retainN(LongQueryBuffer buffer, int sz, long boundary, long searchStart, long searchEnd) {
|
|
|
|
|
|
|
|
if (searchStart >= searchEnd) return;
|
|
|
|
|
|
|
|
long bv = buffer.currentValue();
|
|
|
|
long av = get(searchStart);
|
|
|
|
long pos = searchStart;
|
|
|
|
|
|
|
|
while (bv <= boundary && buffer.hasMore()) {
|
|
|
|
if (bv < av) {
|
|
|
|
if (!buffer.rejectAndAdvance()) break;
|
|
|
|
bv = buffer.currentValue();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (bv == av) {
|
|
|
|
if (!buffer.retainAndAdvance()) break;
|
|
|
|
bv = buffer.currentValue();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
pos += sz;
|
|
|
|
|
|
|
|
if (pos < searchEnd) {
|
|
|
|
av = get(pos);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default void reject(LongQueryBuffer buffer, long boundary, long searchStart, long searchEnd) {
|
|
|
|
|
|
|
|
if (searchStart >= searchEnd) return;
|
|
|
|
|
|
|
|
long bv = buffer.currentValue();
|
|
|
|
long av = get(searchStart);
|
|
|
|
long pos = searchStart;
|
|
|
|
|
|
|
|
while (bv <= boundary && buffer.hasMore()) {
|
|
|
|
if (bv < av) {
|
|
|
|
if (!buffer.retainAndAdvance()) break;
|
|
|
|
bv = buffer.currentValue();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (bv == av) {
|
|
|
|
if (!buffer.rejectAndAdvance()) break;
|
|
|
|
bv = buffer.currentValue();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (++pos < searchEnd) {
|
|
|
|
av = get(pos);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
default void rejectN(LongQueryBuffer buffer, int sz, long boundary, long searchStart, long searchEnd) {
|
|
|
|
|
|
|
|
if (searchStart >= searchEnd) return;
|
|
|
|
|
|
|
|
long bv = buffer.currentValue();
|
|
|
|
long av = get(searchStart);
|
|
|
|
long pos = searchStart;
|
|
|
|
|
|
|
|
while (bv <= boundary && buffer.hasMore()) {
|
|
|
|
if (bv < av) {
|
|
|
|
if (!buffer.retainAndAdvance()) break;
|
|
|
|
bv = buffer.currentValue();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (bv == av) {
|
|
|
|
if (!buffer.rejectAndAdvance()) break;
|
|
|
|
bv = buffer.currentValue();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
pos += sz;
|
|
|
|
if (pos < searchEnd) {
|
|
|
|
av = get(pos);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|