/** * 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; /** * Sept 15, 2012 * */ public class HeapCompressedIntArray implements IntArray { static final int BLOCK_SIZE = 64; // 32 = int, 64 = long static final int BLOCK_BITS = 6; // The #bits representing BLOCK_SIZE static final int MOD_MASK = BLOCK_SIZE - 1; // x % BLOCK_SIZE /** * Values are stores contiguously in the blocks array. */ private final long[] blocks; /** * A right-aligned mask of width BitsPerValue used by {@link #getInt(int)}. */ private final long maskRight; /** * Optimization: Saves one lookup in {@link #getInt(int)}. */ private final int bpvMinusBlockSize; private final int bitsPerValue; private final int valueCount; /** * Creates an array with the internal structures adjusted for the given limits * and initialized to 0. * * @param valueCount * the number of elements. * @param bitsPerValue * the number of bits available for any given value. */ public HeapCompressedIntArray(int valueCount, int bitsPerValue) { // NOTE: block-size was previously calculated as // valueCount * bitsPerValue / BLOCK_SIZE + 1 // due to memory layout requirements dictated by non-branching code this(new long[size(valueCount, bitsPerValue)], valueCount, bitsPerValue); } /** * <p>Creates an array backed by the given blocks. </p> * * Note: The blocks are used directly, so changes to the given block will * affect the Packed64-structure. * * @param blocks * used as the internal backing array. Not that the last element * cannot be addressed directly. * @param valueCount * the number of values. * @param bitsPerValue * the number of bits available for any given value. */ public HeapCompressedIntArray(long[] blocks, int valueCount, int bitsPerValue) { this.blocks = blocks; this.valueCount = valueCount; this.bitsPerValue = bitsPerValue; maskRight = ~0L << (BLOCK_SIZE - bitsPerValue) >>> (BLOCK_SIZE - bitsPerValue); bpvMinusBlockSize = bitsPerValue - BLOCK_SIZE; } public int size() { return valueCount; } public static int size(int valueCount, int bitsPerValue) { final long totBitCount = (long) valueCount * bitsPerValue; return (int) (totBitCount / 64 + ((totBitCount % 64 == 0) ? 0 : 1)); } /** * @param index * the position of the value. * @return the value at the given index. */ public int getInt(final int index) { // The abstract index in a bit stream final long majorBitPos = (long) index * bitsPerValue; // The index in the backing long-array final int elementPos = (int) (majorBitPos >>> BLOCK_BITS); // The number of value-bits in the second long final long endBits = (majorBitPos & MOD_MASK) + bpvMinusBlockSize; if (endBits <= 0) { // Single block return (int) ((blocks[elementPos] >>> -endBits) & maskRight); } // Two blocks return (int) (((blocks[elementPos] << endBits) | (blocks[elementPos + 1] >>> (BLOCK_SIZE - endBits))) & maskRight); } public void setInt(final int index, final int val) { final long value = val; // The abstract index in a contiguous bit stream final long majorBitPos = (long) index * bitsPerValue; // The index in the backing long-array final int elementPos = (int) (majorBitPos >>> BLOCK_BITS); // / BLOCK_SIZE // The number of value-bits in the second long final long endBits = (majorBitPos & MOD_MASK) + bpvMinusBlockSize; if (endBits <= 0) { // Single block blocks[elementPos] = blocks[elementPos] & ~(maskRight << -endBits) | (value << -endBits); return; } // Two blocks blocks[elementPos] = blocks[elementPos] & ~(maskRight >>> endBits) | (value >>> endBits); blocks[elementPos + 1] = blocks[elementPos + 1] & (~0L >>> endBits) | (value << (BLOCK_SIZE - endBits)); } public long[] getBlocks() { return blocks; } public int getBitsPerValue() { return bitsPerValue; } public int getApproximateSizeInBits() { int bits = blocks.length * 64; return bits; } }