blob: af043856de5fdb0f178162e26ac2d5395a1da3c6 [file] [log] [blame]
using J2N.Numerics;
using Lucene.Net.Diagnostics;
using System;
namespace Lucene.Net.Util.Packed
{
/*
* 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.
*/
/// <summary>
/// Non-specialized <see cref="BulkOperation"/> for <see cref="PackedInt32s.Format.PACKED"/>.
/// </summary>
internal class BulkOperationPacked : BulkOperation
{
private readonly int bitsPerValue;
private readonly int longBlockCount;
private readonly int longValueCount;
private readonly int byteBlockCount;
private readonly int byteValueCount;
private readonly long mask;
private readonly int intMask;
public BulkOperationPacked(int bitsPerValue)
{
this.bitsPerValue = bitsPerValue;
if (Debugging.AssertsEnabled) Debugging.Assert(bitsPerValue > 0 && bitsPerValue <= 64);
int blocks = bitsPerValue;
while ((blocks & 1) == 0)
{
blocks = blocks.TripleShift(1);
}
this.longBlockCount = blocks;
this.longValueCount = 64 * longBlockCount / bitsPerValue;
int byteBlockCount = 8 * longBlockCount;
int byteValueCount = longValueCount;
while ((byteBlockCount & 1) == 0 && (byteValueCount & 1) == 0)
{
byteBlockCount = byteBlockCount.TripleShift(1);
byteValueCount = byteValueCount.TripleShift(1);
}
this.byteBlockCount = byteBlockCount;
this.byteValueCount = byteValueCount;
if (bitsPerValue == 64)
{
this.mask = ~0L;
}
else
{
this.mask = (1L << bitsPerValue) - 1;
}
this.intMask = (int)mask;
if (Debugging.AssertsEnabled) Debugging.Assert(longValueCount * bitsPerValue == 64 * longBlockCount);
}
/// <summary>
/// NOTE: This was longBlockCount() in Lucene.
/// </summary>
public override int Int64BlockCount => longBlockCount;
/// <summary>
/// NOTE: This was longValueCount() in Lucene.
/// </summary>
public override int Int64ValueCount => longValueCount;
public override int ByteBlockCount => byteBlockCount;
public override int ByteValueCount => byteValueCount;
public override 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].TripleShift(64 + bitsLeft));
bitsLeft += 64;
}
else
{
values[valuesOffset++] = (blocks[blocksOffset].TripleShift(bitsLeft)) & mask;
}
}
}
public override 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)
{
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.TripleShift(bits));
while (bits >= bitsPerValue)
{
bits -= bitsPerValue;
values[valuesOffset++] = (bytes.TripleShift(bits)) & mask;
}
// then buffer
bitsLeft = bitsPerValue - bits;
nextValue = (bytes & ((1L << bits) - 1)) << bitsLeft;
}
}
if (Debugging.AssertsEnabled) Debugging.Assert(bitsLeft == bitsPerValue);
}
public override void Decode(long[] blocks, int blocksOffset, int[] values, int valuesOffset, int iterations)
{
if (bitsPerValue > 32)
{
throw new NotSupportedException("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].TripleShift(64 + bitsLeft)));
bitsLeft += 64;
}
else
{
values[valuesOffset++] = (int)((blocks[blocksOffset].TripleShift(bitsLeft)) & mask);
}
}
}
public override 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)
{
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.TripleShift(bits));
while (bits >= bitsPerValue)
{
bits -= bitsPerValue;
values[valuesOffset++] = (bytes.TripleShift(bits)) & intMask;
}
// then buffer
bitsLeft = bitsPerValue - bits;
nextValue = (bytes & ((1 << bits) - 1)) << bitsLeft;
}
}
if (Debugging.AssertsEnabled) Debugging.Assert(bitsLeft == bitsPerValue);
}
public override 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;
} // bitsLeft < 0
else
{
nextBlock |= values[valuesOffset].TripleShift(-bitsLeft);
blocks[blocksOffset++] = nextBlock;
nextBlock = (values[valuesOffset++] & ((1L << -bitsLeft) - 1)) << (64 + bitsLeft);
bitsLeft += 64;
}
}
}
public override 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;
} // bitsLeft < 0
else
{
nextBlock |= (values[valuesOffset] & 0xFFFFFFFFL).TripleShift(-bitsLeft);
blocks[blocksOffset++] = nextBlock;
nextBlock = (values[valuesOffset++] & ((1L << -bitsLeft) - 1)) << (64 + bitsLeft);
bitsLeft += 64;
}
}
}
public override 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)
{
long v = values[valuesOffset++];
if (Debugging.AssertsEnabled) Debugging.Assert(bitsPerValue == 64 || PackedInt32s.BitsRequired(v) <= bitsPerValue);
if (bitsPerValue < bitsLeft)
{
// just buffer
nextBlock |= (int)(v << (bitsLeft - bitsPerValue));
bitsLeft -= bitsPerValue;
}
else
{
// flush as many blocks as possible
int bits = bitsPerValue - bitsLeft;
blocks[blocksOffset++] = (byte)((uint)nextBlock | (v.TripleShift(bits)));
while (bits >= 8)
{
bits -= 8;
blocks[blocksOffset++] = (byte)(v.TripleShift(bits));
}
// then buffer
bitsLeft = 8 - bits;
nextBlock = (int)((v & ((1L << bits) - 1)) << bitsLeft);
}
}
if (Debugging.AssertsEnabled) Debugging.Assert(bitsLeft == 8);
}
public override 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)
{
int v = values[valuesOffset++];
if (Debugging.AssertsEnabled) Debugging.Assert(PackedInt32s.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.TripleShift(bits)));
while (bits >= 8)
{
bits -= 8;
blocks[blocksOffset++] = (byte)(v.TripleShift(bits));
}
// then buffer
bitsLeft = 8 - bits;
nextBlock = (v & ((1 << bits) - 1)) << bitsLeft;
}
}
if (Debugging.AssertsEnabled) Debugging.Assert(bitsLeft == 8);
}
}
}