
org.apache.lucene.util.FixedLengthBytesRefArray Maven / Gradle / Ivy
Show all versions of org.apache.servicemix.bundles.lucene
/*
* 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.lucene.util;
import java.util.Comparator;
import java.util.Objects;
/**
* Just like {@link BytesRefArray} except all values have the same length.
*
* Note: This class is not Thread-Safe!
*
* @lucene.internal
* @lucene.experimental
*/
public final class FixedLengthBytesRefArray implements SortableBytesRefArray {
private final int valueLength;
private final int valuesPerBlock;
/** How many values have been appended */
private int size;
/** How many blocks are used */
private int currentBlock = -1;
private int nextEntry;
private byte[][] blocks;
/** Creates a new {@link BytesRefArray} with a counter to track allocated bytes */
public FixedLengthBytesRefArray(int valueLength) {
this.valueLength = valueLength;
// ~32K per page, unless each value is > 32K:
valuesPerBlock = Math.max(1, 32768 / valueLength);
nextEntry = valuesPerBlock;
blocks = new byte[0][];
}
/** Clears this {@link BytesRefArray} */
@Override
public void clear() {
size = 0;
blocks = new byte[0][];
currentBlock = -1;
nextEntry = valuesPerBlock;
}
/**
* Appends a copy of the given {@link BytesRef} to this {@link BytesRefArray}.
*
* @param bytes the bytes to append
* @return the index of the appended bytes
*/
@Override
public int append(BytesRef bytes) {
if (bytes.length != valueLength) {
throw new IllegalArgumentException(
"value length is " + bytes.length + " but is supposed to always be " + valueLength);
}
if (nextEntry == valuesPerBlock) {
currentBlock++;
if (currentBlock == blocks.length) {
int size = ArrayUtil.oversize(currentBlock + 1, RamUsageEstimator.NUM_BYTES_OBJECT_REF);
byte[][] next = new byte[size][];
System.arraycopy(blocks, 0, next, 0, blocks.length);
blocks = next;
}
blocks[currentBlock] = new byte[valuesPerBlock * valueLength];
nextEntry = 0;
}
System.arraycopy(
bytes.bytes, bytes.offset, blocks[currentBlock], nextEntry * valueLength, valueLength);
nextEntry++;
return size++;
}
/**
* Returns the n'th element of this {@link FixedLengthBytesRefArray}
*
* @param spare a spare {@link BytesRef} instance. The length of this spare should be equal to the
* fixed length.
* @param index the elements index to retrieve
* @return the n'th element of this {@link FixedLengthBytesRefArray}
*/
public BytesRef get(BytesRef spare, int index) {
Objects.checkIndex(index, size);
assert spare.length == valueLength;
final int block = index / valuesPerBlock;
final int pos = index % valuesPerBlock;
spare.bytes = blocks[block];
spare.offset = pos * valueLength;
return spare;
}
/**
* Returns the current size of this {@link FixedLengthBytesRefArray}
*
* @return the current size of this {@link FixedLengthBytesRefArray}
*/
@Override
public int size() {
return size;
}
private int[] sort(final Comparator comp) {
final int[] orderedEntries = new int[size()];
for (int i = 0; i < orderedEntries.length; i++) {
orderedEntries[i] = i;
}
new StringSorter(comp) {
{
scratchBytes1.length = valueLength;
scratchBytes2.length = valueLength;
pivot.length = valueLength;
}
@Override
protected void get(BytesRefBuilder builder, BytesRef result, int i) {
final int index = orderedEntries[i];
result.bytes = blocks[index / valuesPerBlock];
result.offset = (index % valuesPerBlock) * valueLength;
}
@Override
protected void swap(int i, int j) {
int o = orderedEntries[i];
orderedEntries[i] = orderedEntries[j];
orderedEntries[j] = o;
}
}.sort(0, size());
return orderedEntries;
}
/**
* Returns a {@link BytesRefIterator} with point in time semantics. The iterator provides access
* to all so far appended {@link BytesRef} instances.
*
* The iterator will iterate the byte values in the order specified by the comparator.
*
*
This is a non-destructive operation.
*/
@Override
public BytesRefIterator iterator(final Comparator comp) {
final BytesRef result = new BytesRef();
result.length = valueLength;
final int size = size();
final int[] indices = sort(comp);
return new BytesRefIterator() {
int pos = 0;
@Override
public BytesRef next() {
if (pos < size) {
int index = indices[pos];
pos++;
result.bytes = blocks[index / valuesPerBlock];
result.offset = (index % valuesPerBlock) * valueLength;
return result;
}
return null;
}
};
}
}