/**
* Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com)
*
* Licensed 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 com.linkedin.pinot.core.indexsegment.utils;
import com.linkedin.pinot.common.utils.MmapUtils;
import java.nio.ByteBuffer;
/**
* Sept 15, 2012
*
*/
public class OffHeapCompressedIntArray implements IntArray {
private final ByteBuffer buf;
private int capacity;
private final int numOfBitsPerElement;
private byte[] tempBuf;
public OffHeapCompressedIntArray(int numOfElements, int numOfBitsPerElement) {
this.numOfBitsPerElement = numOfBitsPerElement;
capacity = numOfElements;
long requiredBufferSize = getRequiredBufferSize(numOfElements, numOfBitsPerElement);
assert (requiredBufferSize <= Integer.MAX_VALUE);
buf = MmapUtils.allocateDirectByteBuffer((int) requiredBufferSize, null, this.getClass().getSimpleName() + " buf");
tempBuf = getByteBuf();
}
public static int getRequiredBufferSize(int numOfElements, int numOfBitsPerElement) {
return ((int) numOfElements * numOfBitsPerElement + 7) / 8;
}
public static int getNumOfBits(int dictionarySize) {
int ret = (int) Math.ceil(Math.log(dictionarySize) / Math.log(2));
if (ret == 0) {
ret = 1;
}
return ret;
}
public OffHeapCompressedIntArray(int numOfElements, int numOfBitsPerElement, ByteBuffer byteBuffer) {
this.numOfBitsPerElement = numOfBitsPerElement;
capacity = numOfElements;
buf = byteBuffer;
tempBuf = getByteBuf();
}
/**
* We can reuse this buffer for multiple calls
*/
public byte[] getByteBuf() {
return new byte[numOfBitsPerElement / 8 + (numOfBitsPerElement % 8 < 2 ? 1 : 2)];
}
/**
* This method is not threadsafe
* @param position
* @param number
*/
public void setInt(int position, int number) {
addInt(position, number, tempBuf);
}
public void addInt(int position, int number, byte[] tempBuf) {
int bytePosition = position * numOfBitsPerElement / 8;
int startBitOffset = (position * numOfBitsPerElement) % 8;
int endBitOffset = (8 - ((startBitOffset + numOfBitsPerElement) % 8)) % 8;
int numberOfBytesUsed =
(startBitOffset + numOfBitsPerElement) / 8 + ((startBitOffset + numOfBitsPerElement) % 8 != 0 ? 1 : 0);
buf.position(bytePosition);
buf.get(tempBuf, 0, numberOfBytesUsed);
long newNumber = tempBuf[0];
if (startBitOffset > 0) {
newNumber >>= 8 - startBitOffset;
}
newNumber <<= numOfBitsPerElement;
newNumber |= number;
if (endBitOffset != 0) {
newNumber <<= endBitOffset;
newNumber |= tempBuf[numberOfBytesUsed - 1] & 0xFF >>> (8 - endBitOffset);
}
for (int i = numberOfBytesUsed - 1; i >= 0; i--) {
tempBuf[i] = (byte) (newNumber & 0xFF);
newNumber = newNumber >> 8;
}
buf.position(bytePosition);
buf.put(tempBuf, 0, numberOfBytesUsed);
}
public int getInt(int position) {
/*
* int bytePosition = position * numOfBitsPerElement / 8; int startBitOffset
* = (position * numOfBitsPerElement) % 8; int endBitOffset = (8 -
* ((startBitOffset + numOfBitsPerElement) % 8)) % 8; int numberOfBytesUsed
* = (startBitOffset + numOfBitsPerElement) / 8 + ((startBitOffset +
* numOfBitsPerElement) % 8 != 0 ? 1 : 0);buf.position(bytePosition);
*/
int mult = position * numOfBitsPerElement;
int bytePosition = mult >>> 3;
int startBitOffset = mult & 7;
int sum = startBitOffset + numOfBitsPerElement;
int endBitOffset = (8 - (sum & 7)) & 7;
// int numberOfBytesUsed = (sum >>> 3) + ((sum & 7) != 0 ? 1 : 0);
int numberOfBytesUsed = ((sum + 7) >>> 3);
int i = -1;
long number = 0;
while (true) {
number |= (buf.get(bytePosition)) & 0xFF;
i++;
bytePosition++;
if (i == numberOfBytesUsed - 1) {
break;
}
number <<= 8;
}
number >>= endBitOffset;
number &= (0xFFFFFFFF >>> (32 - numOfBitsPerElement));
return (int) number;
}
public int size() {
return capacity;
}
public ByteBuffer getStorage() {
return buf;
}
public int getNumOfBitsPerElement() {
return numOfBitsPerElement;
}
}