1
1
mirror of https://github.com/MarginaliaSearch/MarginaliaSearch.git synced 2025-10-06 07:32:38 +02:00
Files
MarginaliaSearch/code/libraries/array/java/nu/marginalia/array/page/LongQueryBuffer.java

204 lines
5.3 KiB
Java

package nu.marginalia.array.page;
import nu.marginalia.array.LongArray;
import nu.marginalia.array.LongArrayFactory;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout;
import java.nio.ByteBuffer;
import java.util.Arrays;
/** A buffer for long values that can be used to filter and manipulate the data.
* It is central to the query processing in the index service.
* <p></p>
* The class contains both a read pointer, write pointer, and a buffer end pointer.
* <p></p>
* The read and write pointers are used for filtering the data in the buffer, and
* the end pointer is used to keep track of the length of the data in the buffer.
* <p></p>
* Filtering is done via the methods {@link #rejectAndAdvance()}, {@link #retainAndAdvance()},
* and {@link #finalizeFiltering()}.
*
*/
public class LongQueryBuffer {
/** Direct access to the data in the buffer,
* guaranteed to be populated until `end` */
public final LongArray data;
/** Number of items in the data buffer */
public int end;
private int read = 0;
private int write = 0;
private LongQueryBuffer(LongArray array, int size) {
this.data = array;
this.end = size;
}
public LongQueryBuffer(int size) {
this.data = LongArrayFactory.onHeapConfined(size);
this.end = 0;
}
public LongQueryBuffer(long[] data, int size) {
this.data = LongArrayFactory.onHeapConfined(size);
this.data.set(0, data);
this.end = size;
}
public long[] copyData() {
long[] copy = new long[end];
data.forEach(0, end, (pos, val) -> copy[(int)pos]=val );
return copy;
}
public long[] copyFilterData() {
long[] copy = new long[write];
data.forEach(0, write, (pos, val) -> copy[(int)pos]=val );
return copy;
}
public boolean fitsMore() {
return end < data.size();
}
public int addData(MemorySegment source, long sourceOffset, int nMax) {
int n = Math.min(nMax, (int) data.size() - end);
MemorySegment.copy(source, ValueLayout.JAVA_LONG, sourceOffset, data.getMemorySegment(), ValueLayout.JAVA_LONG, 8L * end, n);
end += n;
return n;
}
/** Dispose of the buffer and release resources */
public void dispose() {
data.close();
}
public boolean isEmpty() {
return end == 0;
}
public int size() {
return end;
}
public void reset() {
end = (int) data.size();
read = 0;
write = 0;
}
public void zero() {
end = 0;
read = 0;
write = 0;
}
public LongQueryBuffer slice(int start, int end) {
return new LongQueryBuffer(data.range(start, end), end - start);
}
/* == Filtering methods == */
/** Returns the current value at the read pointer.
*/
public long currentValue() {
return data.get(read);
}
/** Advances the read pointer and returns true if there are more values to read. */
public boolean rejectAndAdvance() {
return ++read < end;
}
/** Retains the current value at the read pointer and advances the read and write pointers.
* Returns true if there are more values to read.
* <p></p> To enable "or" style criterias, the method swaps the current value with the value
* at the write pointer, so that it's retained at the end of the buffer.
*/
public boolean retainAndAdvance() {
if (read != write) {
long tmp = data.get(write);
data.set(write, data.get(read));
data.set(read, tmp);
}
write++;
return ++read < end;
}
/** Retains all values in the buffer, and updates
* the read and write pointer to the end pointer,
* as though all values were retained.
*/
public void retainAll() {
write = end;
read = end;
}
public boolean hasMore() {
return read < end;
}
public boolean hasRetainedData() {
return write > 0;
}
/** Finalizes the filtering by setting the end pointer to the write pointer,
* and resetting the read and write pointers to zero.
* <p></p>
* At this point the buffer can either be read, or additional filtering can be applied.
*/
public void finalizeFiltering() {
end = write;
read = 0;
write = 0;
}
/** Retain only unique values in the buffer, and update the end pointer to the new length.
* <p></p>
* The buffer is assumed to be sorted up until the end pointer.
*/
public void uniq() {
if (end <= 1) return;
long prev = currentValue();
retainAndAdvance();
while (hasMore()) {
long val = currentValue();
if (prev == val) {
rejectAndAdvance();
} else {
retainAndAdvance();
prev = val;
}
}
finalizeFiltering();
}
@SuppressWarnings("preview")
public ByteBuffer asByteBuffer() {
return data.getMemorySegment().asByteBuffer();
}
public String toString() {
return getClass().getSimpleName() + "[" +
"read = " + read +
",write = " + write +
",end = " + end +
",data = [" + Arrays.toString(copyData()) + "]]";
}
}