org.codelibs.elasticsearch.common.bytes.CompositeBytesReference Maven / Gradle / Ivy
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.codelibs.elasticsearch.common.bytes;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefBuilder;
import org.apache.lucene.util.BytesRefIterator;
import org.apache.lucene.util.RamUsageEstimator;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
/**
* A composite {BytesReference} that allows joining multiple bytes references
* into one without copying.
*
* Note, {#toBytesRef()} will materialize all pages in this BytesReference.
*/
public final class CompositeBytesReference extends BytesReference {
private final BytesReference[] references;
private final int[] offsets;
private final int length;
private final long ramBytesUsed;
public CompositeBytesReference(BytesReference... references) {
this.references = Objects.requireNonNull(references, "references must not be null");
this.offsets = new int[references.length];
long ramBytesUsed = 0;
int offset = 0;
for (int i = 0; i < references.length; i++) {
BytesReference reference = references[i];
if (reference == null) {
throw new IllegalArgumentException("references must not be null");
}
offsets[i] = offset; // we use the offsets to seek into the right BytesReference for random access and slicing
offset += reference.length();
ramBytesUsed += reference.ramBytesUsed();
}
this.ramBytesUsed = ramBytesUsed
+ (Integer.BYTES * offsets.length + RamUsageEstimator.NUM_BYTES_ARRAY_HEADER) // offsets
+ (references.length * RamUsageEstimator.NUM_BYTES_OBJECT_REF + RamUsageEstimator.NUM_BYTES_ARRAY_HEADER) // references
+ Integer.BYTES // length
+ Long.BYTES; // ramBytesUsed
length = offset;
}
@Override
public byte get(int index) {
final int i = getOffsetIndex(index);
return references[i].get(index - offsets[i]);
}
@Override
public int length() {
return length;
}
@Override
public BytesReference slice(int from, int length) {
// for slices we only need to find the start and the end reference
// adjust them and pass on the references in between as they are fully contained
final int to = from + length;
final int limit = getOffsetIndex(from + length);
final int start = getOffsetIndex(from);
final BytesReference[] inSlice = new BytesReference[1 + (limit - start)];
for (int i = 0, j = start; i < inSlice.length; i++) {
inSlice[i] = references[j++];
}
int inSliceOffset = from - offsets[start];
if (inSlice.length == 1) {
return inSlice[0].slice(inSliceOffset, length);
}
// now adjust slices in front and at the end
inSlice[0] = inSlice[0].slice(inSliceOffset, inSlice[0].length() - inSliceOffset);
inSlice[inSlice.length-1] = inSlice[inSlice.length-1].slice(0, to - offsets[limit]);
return new CompositeBytesReference(inSlice);
}
private int getOffsetIndex(int offset) {
final int i = Arrays.binarySearch(offsets, offset);
return i < 0 ? (-(i + 1)) - 1 : i;
}
@Override
public BytesRef toBytesRef() {
BytesRefBuilder builder = new BytesRefBuilder();
builder.grow(length());
BytesRef spare;
BytesRefIterator iterator = iterator();
try {
while ((spare = iterator.next()) != null) {
builder.append(spare);
}
} catch (IOException ex) {
throw new AssertionError("won't happen", ex); // this is really an error since we don't do IO in our bytesreferences
}
return builder.toBytesRef();
}
@Override
public BytesRefIterator iterator() {
if (references.length > 0) {
return new BytesRefIterator() {
int index = 0;
private BytesRefIterator current = references[index++].iterator();
@Override
public BytesRef next() throws IOException {
BytesRef next = current.next();
if (next == null) {
while (index < references.length) {
current = references[index++].iterator();
next = current.next();
if (next != null) {
break;
}
}
}
return next;
}
};
} else {
return () -> null;
}
}
@Override
public long ramBytesUsed() {
return ramBytesUsed;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy