private void WriteBlock(int[] array, int index, int endIndex) { int length = endIndex - index; if (length == 0) { return; } // Choose how to encode IntBlock block = IntBlock.Plan(array, index, endIndex); Stats?.Add(block); // Write the block markers block.Write(_writer); _writer.EnsureSpace(block.TotalBytes); // Write adjustment bits if (block.BitsPerAdjustment > 0) { int bitsLeftToWrite = 0; ulong toWrite = 0; for (int i = 0; i < block.AdjustmentCount; ++i) { // Calculate adjustment (zero once out of real values) ulong adjustment = unchecked ((uint)(i >= block.Count ? 0 : array[index + i] - (block.Base + block.Slope * i))); // Add new value to bits left to write at top of long toWrite += adjustment << (64 - block.BitsPerAdjustment - bitsLeftToWrite); // Write all whole bytes built bitsLeftToWrite += block.BitsPerAdjustment; while (bitsLeftToWrite >= 8) { // Write top byte byte nextByte = (byte)(toWrite >> 56); _writer.Buffer[_writer.Index++] = nextByte; // Shift to next byte toWrite = toWrite << 8; bitsLeftToWrite -= 8; } } } // Clear buffer; it's been written _bufferCount = 0; }
private void WriteComponent(BufferedWriter writer, int component, byte componentMarkerBase) { if (component == 0) { return; } byte byteLength = IntBlock.ByteLength(component); writer.Buffer[writer.Index++] = (byte)(componentMarkerBase + byteLength - 1); for (byte i = 0; i < byteLength; ++i) { writer.Buffer[writer.Index++] = (byte)(component & 0xFF); component = component >> 8; } }
public int Next(out int[] buffer) { buffer = _buffer; if (_reader.EndOfStream) { return(0); } // Read markers IntBlock block = IntBlock.Read(_reader); // Read adjustments //ReadScalar(block); IntBlockVectorReader.ReadVector(block, _reader, _buffer); return(block.Count); }
private void ReadScalar(IntBlock block) { if (block.BitsPerAdjustment == 0) { // If no adjustments, calculate each value int unadjusted = block.Base; for (int i = 0; i < block.Count; ++i) { _buffer[i] = unadjusted; unadjusted += block.Slope; } } else { // Build a mask to get the low adjustmentBitLength bits byte bitsPerAdjustment = block.BitsPerAdjustment; ulong mask = ulong.MaxValue >> (64 - bitsPerAdjustment); byte bitsLeftToRead = 0; ulong pending = 0; int countWritten = IntBlock.RequiredCount(block.Count); int unadjusted = block.Base; for (int i = 0; i < countWritten; ++i) { // Read enough bits to get value while (bitsLeftToRead < bitsPerAdjustment) { pending = pending << 8; pending += _reader.Buffer[_reader.Index++]; bitsLeftToRead += 8; } // Extract correct bits and build value int adjustment = unchecked ((int)(((pending >> (bitsLeftToRead - bitsPerAdjustment)) & mask))); _buffer[i] = unadjusted + adjustment; bitsLeftToRead -= bitsPerAdjustment; unadjusted += block.Slope; } } }
public void Add(IntBlock block) { TotalBlockCount++; if (block.Slope != 0) { BaseAndSlopeCount++; } else if (block.Base != 0) { BaseCount++; } else { AdjustmentOnlyCount++; } CountPerLength[block.BitsPerAdjustment]++; }
public static unsafe void ReadVector(IntBlock block, BufferedReader reader, int[] buffer) { // Build first unadjusted vector and per-vector increment Vector128 <int> unadjusted = SetIncrement(block.Base, block.Slope); Vector128 <int> increment = Set1(block.Slope * 4); if (block.BitsPerAdjustment == 0) { // If no adjustments, calculate in blocks and return fixed(int *resultPtr = buffer) { for (int i = 0; i < block.Count; i += 4) { Unsafe.WriteUnaligned(&resultPtr[i], unadjusted); unadjusted = Sse2.Add(unadjusted, increment); } } return; } fixed(byte *bufferPtr = reader.Buffer) fixed(int *resultPtr = buffer) fixed(sbyte *shuffleMaskPtr = ShuffleMasks) fixed(int *multiplyMaskPtr = MultiplyMasks) { byte bitsPerAdjustment = block.BitsPerAdjustment; int index = reader.Index; int count = block.Count; // Calculate bytes consumed for the first and second four ints decoded (different for odd bit lengths) byte bytesPerEight = bitsPerAdjustment; byte bytes1 = (byte)(bytesPerEight / 2); // Calculate how much to shift values (from top of each int to bottom) byte shiftRightBits = (byte)(32 - bitsPerAdjustment); // Get shuffle mask (to get correct bits) and multiply value (to shift to top of each int) for halves Vector128 <sbyte> shuffle1 = Unsafe.ReadUnaligned <Vector128 <sbyte> >(&shuffleMaskPtr[32 * bitsPerAdjustment]); Vector128 <int> multiply1 = Unsafe.ReadUnaligned <Vector128 <int> >(&multiplyMaskPtr[8 * bitsPerAdjustment]); Vector128 <sbyte> shuffle2 = Unsafe.ReadUnaligned <Vector128 <sbyte> >(&shuffleMaskPtr[32 * bitsPerAdjustment + 16]); Vector128 <int> multiply2 = Unsafe.ReadUnaligned <Vector128 <int> >(&multiplyMaskPtr[8 * bitsPerAdjustment + 4]); for (int i = 0; i < count; i += 8, index += bytesPerEight) { // Read source bytes Vector128 <int> vector1 = Unsafe.ReadUnaligned <Vector128 <int> >(&bufferPtr[index]); Vector128 <int> vector2 = Unsafe.ReadUnaligned <Vector128 <int> >(&bufferPtr[index + bytes1]); // Shuffle to get the right bytes in each integer vector1 = Sse.StaticCast <sbyte, int>(Ssse3.Shuffle(Sse.StaticCast <int, sbyte>(vector1), shuffle1)); vector2 = Sse.StaticCast <sbyte, int>(Ssse3.Shuffle(Sse.StaticCast <int, sbyte>(vector2), shuffle2)); // Multiply to shift each int so the desired bits are at the top vector1 = Sse41.MultiplyLow(vector1, multiply1); vector2 = Sse41.MultiplyLow(vector2, multiply2); // Shift the desired bits to the bottom and zero the top vector1 = Sse2.ShiftRightLogical(vector1, shiftRightBits); vector2 = Sse2.ShiftRightLogical(vector2, shiftRightBits); // Add the delta base value vector1 = Sse2.Add(vector1, unadjusted); unadjusted = Sse2.Add(unadjusted, increment); vector2 = Sse2.Add(vector2, unadjusted); unadjusted = Sse2.Add(unadjusted, increment); // Write the decoded integers Unsafe.WriteUnaligned(&resultPtr[i], vector1); Unsafe.WriteUnaligned(&resultPtr[i + 4], vector2); } reader.Index = index; } }
public static IntBlock Plan(int[] values, int index, int endIndex) { byte count = (byte)(endIndex - index); // If only one value, write base only if (count == 1) { return(new IntBlock(count, values[index], 0, 0)); } int first = values[index]; // Compute overall slope and consider values around exact (non-int) slope int slopeL = (values[index + count - 1] - first) / (count - 1); int slopeH = slopeL + 1; int min = first; int max = first; int minL = first; int maxL = first; int minH = first; int maxH = first; // Find absolute and slope-relative min and max int line = 0; for (int i = 1; i < count; ++i) { int value = values[index + i]; if (value < min) { min = value; } if (value > max) { max = value; } line += slopeL; int adjustment = value - line; if (adjustment < minL) { minL = adjustment; } if (adjustment > maxL) { maxL = adjustment; } adjustment = value - (line + i); if (adjustment < minH) { minH = adjustment; } if (adjustment > maxH) { maxH = adjustment; } } // Measure adjustments from slope and identify ideal base IntBlock adjustmentOnly = new IntBlock(count, 0, 0, (min < 0 ? (byte)32 : BitLength(max))); IntBlock withBase = new IntBlock(count, min, 0, BitLength(max - min)); IntBlock baseAndSlopeL = new IntBlock(count, minL, slopeL, BitLength(maxL - minL)); IntBlock baseAndSlopeH = new IntBlock(count, minH, slopeH, BitLength(maxH - minH)); IntBlock plan = adjustmentOnly; if (withBase.TotalBytes < plan.TotalBytes) { plan = withBase; } if (baseAndSlopeL.TotalBytes < plan.TotalBytes) { plan = baseAndSlopeL; } if (baseAndSlopeH.TotalBytes < plan.TotalBytes) { plan = baseAndSlopeH; } return(plan); }