Browse Source

Remove allocation and bounds checks

af/merge-core
James Jackson-South 7 years ago
parent
commit
8f75d8cbc9
  1. 76
      src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs

76
src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs

@ -829,38 +829,42 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
private void BuildLength(ReadOnlySpan<int> children) private void BuildLength(ReadOnlySpan<int> children)
{ {
byte* lengthPtr = this.Length;
ref int childrenRef = ref MemoryMarshal.GetReference(children);
ref int bitLengthCountsRef = ref MemoryMarshal.GetReference<int>(this.bitLengthCounts);
int maxLen = this.maxLength;
int numNodes = children.Length >> 1; int numNodes = children.Length >> 1;
int numLeafs = (numNodes + 1) >> 1; int numLeafs = (numNodes + 1) >> 1;
int overflow = 0; int overflow = 0;
for (int i = 0; i < this.maxLength; i++) Array.Clear(this.bitLengthCounts, 0, maxLen);
{
this.bitLengthCounts[i] = 0;
}
// First calculate optimal bit lengths // First calculate optimal bit lengths
int[] lengths = new int[numNodes]; using (IMemoryOwner<int> lengthsMemoryOwner = this.memoryAllocator.Allocate<int>(numNodes, AllocationOptions.Clean))
lengths[numNodes - 1] = 0;
for (int i = numNodes - 1; i >= 0; i--)
{ {
if (children[(2 * i) + 1] != -1) ref int lengthsRef = ref MemoryMarshal.GetReference(lengthsMemoryOwner.Memory.Span);
for (int i = numNodes - 1; i >= 0; i--)
{ {
int bitLength = lengths[i] + 1; if (children[(2 * i) + 1] != -1)
if (bitLength > this.maxLength)
{ {
bitLength = this.maxLength; int bitLength = Unsafe.Add(ref lengthsRef, i) + 1;
overflow++; if (bitLength > maxLen)
} {
bitLength = maxLen;
overflow++;
}
lengths[children[2 * i]] = lengths[children[(2 * i) + 1]] = bitLength; Unsafe.Add(ref lengthsRef, Unsafe.Add(ref childrenRef, 2 * i)) = Unsafe.Add(ref lengthsRef, Unsafe.Add(ref childrenRef, (2 * i) + 1)) = bitLength;
} }
else else
{ {
// A leaf node // A leaf node
int bitLength = lengths[i]; int bitLength = Unsafe.Add(ref lengthsRef, i);
this.bitLengthCounts[bitLength - 1]++; Unsafe.Add(ref bitLengthCountsRef, bitLength - 1)++;
this.Length[children[2 * i]] = (byte)lengths[i]; lengthPtr[Unsafe.Add(ref childrenRef, 2 * i)] = (byte)Unsafe.Add(ref lengthsRef, i);
}
} }
} }
@ -869,11 +873,11 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
return; return;
} }
int incrBitLen = this.maxLength - 1; int incrBitLen = maxLen - 1;
do do
{ {
// Find the first bit length which could increase: // Find the first bit length which could increase:
while (this.bitLengthCounts[--incrBitLen] == 0) while (Unsafe.Add(ref bitLengthCountsRef, --incrBitLen) == 0)
{ {
} }
@ -881,18 +885,18 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
// number of overflow nodes. // number of overflow nodes.
do do
{ {
this.bitLengthCounts[incrBitLen]--; Unsafe.Add(ref bitLengthCountsRef, incrBitLen)--;
this.bitLengthCounts[++incrBitLen]++; Unsafe.Add(ref bitLengthCountsRef, ++incrBitLen)++;
overflow -= 1 << (this.maxLength - 1 - incrBitLen); overflow -= 1 << (maxLen - 1 - incrBitLen);
} }
while (overflow > 0 && incrBitLen < this.maxLength - 1); while (overflow > 0 && incrBitLen < maxLen - 1);
} }
while (overflow > 0); while (overflow > 0);
// We may have overshot above. Move some nodes from maxLength to // We may have overshot above. Move some nodes from maxLength to
// maxLength-1 in that case. // maxLength-1 in that case.
this.bitLengthCounts[this.maxLength - 1] += overflow; Unsafe.Add(ref bitLengthCountsRef, maxLen - 1) += overflow;
this.bitLengthCounts[this.maxLength - 2] -= overflow; Unsafe.Add(ref bitLengthCountsRef, maxLen - 2) -= overflow;
// Now recompute all bit lengths, scanning in increasing // Now recompute all bit lengths, scanning in increasing
// frequency. It is simpler to reconstruct all lengths instead of // frequency. It is simpler to reconstruct all lengths instead of
@ -901,17 +905,17 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
// //
// The nodes were inserted with decreasing frequency into the childs // The nodes were inserted with decreasing frequency into the childs
// array. // array.
int nodePtr = 2 * numLeafs; int nodeIndex = 2 * numLeafs;
for (int bits = this.maxLength; bits != 0; bits--) for (int bits = maxLen; bits != 0; bits--)
{ {
int n = this.bitLengthCounts[bits - 1]; int n = Unsafe.Add(ref bitLengthCountsRef, bits - 1);
while (n > 0) while (n > 0)
{ {
int childPtr = 2 * children[nodePtr++]; int childIndex = 2 * Unsafe.Add(ref childrenRef, nodeIndex++);
if (children[childPtr + 1] == -1) if (Unsafe.Add(ref childrenRef, childIndex + 1) == -1)
{ {
// We found another leaf // We found another leaf
this.Length[children[childPtr]] = (byte)bits; lengthPtr[Unsafe.Add(ref childrenRef, childIndex)] = (byte)bits;
n--; n--;
} }
} }

Loading…
Cancel
Save