/* * 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.packed; /** * Non-specialized {@link BulkOperation} for {@link PackedInts.Format#PACKED}. */ class BulkOperationPacked extends BulkOperation { private final int bitsPerValue; private final int longBlockCount; private final int longValueCount; private final int byteBlockCount; private final int byteValueCount; private final long mask; private final int intMask; public BulkOperationPacked(int bitsPerValue) { this.bitsPerValue = bitsPerValue; assert bitsPerValue > 0 && bitsPerValue <= 64; int blocks = bitsPerValue; while ((blocks & 1) == 0) { blocks >>>= 1; } this.longBlockCount = blocks; this.longValueCount = 64 * longBlockCount / bitsPerValue; int byteBlockCount = 8 * longBlockCount; int byteValueCount = longValueCount; while ((byteBlockCount & 1) == 0 && (byteValueCount & 1) == 0) { byteBlockCount >>>= 1; byteValueCount >>>= 1; } this.byteBlockCount = byteBlockCount; this.byteValueCount = byteValueCount; if (bitsPerValue == 64) { this.mask = ~0L; } else { this.mask = (1L << bitsPerValue) - 1; } this.intMask = (int) mask; assert longValueCount * bitsPerValue == 64 * longBlockCount; } @Override public int longBlockCount() { return longBlockCount; } @Override public int longValueCount() { return longValueCount; } @Override public int byteBlockCount() { return byteBlockCount; } @Override public int byteValueCount() { return byteValueCount; } @Override public void decode(long[] blocks, int blocksOffset, long[] values, int valuesOffset, int iterations) { int bitsLeft = 64; for (int i = 0; i < longValueCount * iterations; ++i) { bitsLeft -= bitsPerValue; if (bitsLeft < 0) { values[valuesOffset++] = ((blocks[blocksOffset++] & ((1L << (bitsPerValue + bitsLeft)) - 1)) << -bitsLeft) | (blocks[blocksOffset] >>> (64 + bitsLeft)); bitsLeft += 64; } else { values[valuesOffset++] = (blocks[blocksOffset] >>> bitsLeft) & mask; } } } @Override public void decode(byte[] blocks, int blocksOffset, long[] values, int valuesOffset, int iterations) { long nextValue = 0L; int bitsLeft = bitsPerValue; for (int i = 0; i < iterations * byteBlockCount; ++i) { final long bytes = blocks[blocksOffset++] & 0xFFL; if (bitsLeft > 8) { // just buffer bitsLeft -= 8; nextValue |= bytes << bitsLeft; } else { // flush int bits = 8 - bitsLeft; values[valuesOffset++] = nextValue | (bytes >>> bits); while (bits >= bitsPerValue) { bits -= bitsPerValue; values[valuesOffset++] = (bytes >>> bits) & mask; } // then buffer bitsLeft = bitsPerValue - bits; nextValue = (bytes & ((1L << bits) - 1)) << bitsLeft; } } assert bitsLeft == bitsPerValue; } @Override public void decode(long[] blocks, int blocksOffset, int[] values, int valuesOffset, int iterations) { if (bitsPerValue > 32) { throw new UnsupportedOperationException("Cannot decode " + bitsPerValue + "-bits values into an int[]"); } int bitsLeft = 64; for (int i = 0; i < longValueCount * iterations; ++i) { bitsLeft -= bitsPerValue; if (bitsLeft < 0) { values[valuesOffset++] = (int) (((blocks[blocksOffset++] & ((1L << (bitsPerValue + bitsLeft)) - 1)) << -bitsLeft) | (blocks[blocksOffset] >>> (64 + bitsLeft))); bitsLeft += 64; } else { values[valuesOffset++] = (int) ((blocks[blocksOffset] >>> bitsLeft) & mask); } } } @Override public void decode(byte[] blocks, int blocksOffset, int[] values, int valuesOffset, int iterations) { int nextValue = 0; int bitsLeft = bitsPerValue; for (int i = 0; i < iterations * byteBlockCount; ++i) { final int bytes = blocks[blocksOffset++] & 0xFF; if (bitsLeft > 8) { // just buffer bitsLeft -= 8; nextValue |= bytes << bitsLeft; } else { // flush int bits = 8 - bitsLeft; values[valuesOffset++] = nextValue | (bytes >>> bits); while (bits >= bitsPerValue) { bits -= bitsPerValue; values[valuesOffset++] = (bytes >>> bits) & intMask; } // then buffer bitsLeft = bitsPerValue - bits; nextValue = (bytes & ((1 << bits) - 1)) << bitsLeft; } } assert bitsLeft == bitsPerValue; } @Override public void encode(long[] values, int valuesOffset, long[] blocks, int blocksOffset, int iterations) { long nextBlock = 0; int bitsLeft = 64; for (int i = 0; i < longValueCount * iterations; ++i) { bitsLeft -= bitsPerValue; if (bitsLeft > 0) { nextBlock |= values[valuesOffset++] << bitsLeft; } else if (bitsLeft == 0) { nextBlock |= values[valuesOffset++]; blocks[blocksOffset++] = nextBlock; nextBlock = 0; bitsLeft = 64; } else { // bitsLeft < 0 nextBlock |= values[valuesOffset] >>> -bitsLeft; blocks[blocksOffset++] = nextBlock; nextBlock = (values[valuesOffset++] & ((1L << -bitsLeft) - 1)) << (64 + bitsLeft); bitsLeft += 64; } } } @Override public void encode(int[] values, int valuesOffset, long[] blocks, int blocksOffset, int iterations) { long nextBlock = 0; int bitsLeft = 64; for (int i = 0; i < longValueCount * iterations; ++i) { bitsLeft -= bitsPerValue; if (bitsLeft > 0) { nextBlock |= (values[valuesOffset++] & 0xFFFFFFFFL) << bitsLeft; } else if (bitsLeft == 0) { nextBlock |= (values[valuesOffset++] & 0xFFFFFFFFL); blocks[blocksOffset++] = nextBlock; nextBlock = 0; bitsLeft = 64; } else { // bitsLeft < 0 nextBlock |= (values[valuesOffset] & 0xFFFFFFFFL) >>> -bitsLeft; blocks[blocksOffset++] = nextBlock; nextBlock = (values[valuesOffset++] & ((1L << -bitsLeft) - 1)) << (64 + bitsLeft); bitsLeft += 64; } } } @Override public void encode(long[] values, int valuesOffset, byte[] blocks, int blocksOffset, int iterations) { int nextBlock = 0; int bitsLeft = 8; for (int i = 0; i < byteValueCount * iterations; ++i) { final long v = values[valuesOffset++]; assert PackedInts.unsignedBitsRequired(v) <= bitsPerValue; if (bitsPerValue < bitsLeft) { // just buffer nextBlock |= v << (bitsLeft - bitsPerValue); bitsLeft -= bitsPerValue; } else { // flush as many blocks as possible int bits = bitsPerValue - bitsLeft; blocks[blocksOffset++] = (byte) (nextBlock | (v >>> bits)); while (bits >= 8) { bits -= 8; blocks[blocksOffset++] = (byte) (v >>> bits); } // then buffer bitsLeft = 8 - bits; nextBlock = (int) ((v & ((1L << bits) - 1)) << bitsLeft); } } assert bitsLeft == 8; } @Override public void encode(int[] values, int valuesOffset, byte[] blocks, int blocksOffset, int iterations) { int nextBlock = 0; int bitsLeft = 8; for (int i = 0; i < byteValueCount * iterations; ++i) { final int v = values[valuesOffset++]; assert PackedInts.bitsRequired(v & 0xFFFFFFFFL) <= bitsPerValue; if (bitsPerValue < bitsLeft) { // just buffer nextBlock |= v << (bitsLeft - bitsPerValue); bitsLeft -= bitsPerValue; } else { // flush as many blocks as possible int bits = bitsPerValue - bitsLeft; blocks[blocksOffset++] = (byte) (nextBlock | (v >>> bits)); while (bits >= 8) { bits -= 8; blocks[blocksOffset++] = (byte) (v >>> bits); } // then buffer bitsLeft = 8 - bits; nextBlock = (v & ((1 << bits) - 1)) << bitsLeft; } } assert bitsLeft == 8; } }