| /* |
| * 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; |
| } |
| |
| } |