From 8f75d8cbc9dde074a9d691a0cc332f4676d080ea Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 25 Nov 2019 15:20:16 +1100 Subject: [PATCH] Remove allocation and bounds checks --- .../Formats/Png/Zlib/DeflaterHuffman.cs | 76 ++++++++++--------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs index 003e4fbb7..96ff6b657 100644 --- a/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs +++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs @@ -829,38 +829,42 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib private void BuildLength(ReadOnlySpan children) { + byte* lengthPtr = this.Length; + ref int childrenRef = ref MemoryMarshal.GetReference(children); + ref int bitLengthCountsRef = ref MemoryMarshal.GetReference(this.bitLengthCounts); + + int maxLen = this.maxLength; int numNodes = children.Length >> 1; int numLeafs = (numNodes + 1) >> 1; int overflow = 0; - for (int i = 0; i < this.maxLength; i++) - { - this.bitLengthCounts[i] = 0; - } + Array.Clear(this.bitLengthCounts, 0, maxLen); // First calculate optimal bit lengths - int[] lengths = new int[numNodes]; - lengths[numNodes - 1] = 0; - - for (int i = numNodes - 1; i >= 0; i--) + using (IMemoryOwner lengthsMemoryOwner = this.memoryAllocator.Allocate(numNodes, AllocationOptions.Clean)) { - 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 (bitLength > this.maxLength) + if (children[(2 * i) + 1] != -1) { - bitLength = this.maxLength; - overflow++; - } + int bitLength = Unsafe.Add(ref lengthsRef, i) + 1; + if (bitLength > maxLen) + { + bitLength = maxLen; + overflow++; + } - lengths[children[2 * i]] = lengths[children[(2 * i) + 1]] = bitLength; - } - else - { - // A leaf node - int bitLength = lengths[i]; - this.bitLengthCounts[bitLength - 1]++; - this.Length[children[2 * i]] = (byte)lengths[i]; + Unsafe.Add(ref lengthsRef, Unsafe.Add(ref childrenRef, 2 * i)) = Unsafe.Add(ref lengthsRef, Unsafe.Add(ref childrenRef, (2 * i) + 1)) = bitLength; + } + else + { + // A leaf node + int bitLength = Unsafe.Add(ref lengthsRef, i); + Unsafe.Add(ref bitLengthCountsRef, bitLength - 1)++; + lengthPtr[Unsafe.Add(ref childrenRef, 2 * i)] = (byte)Unsafe.Add(ref lengthsRef, i); + } } } @@ -869,11 +873,11 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib return; } - int incrBitLen = this.maxLength - 1; + int incrBitLen = maxLen - 1; do { // 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. do { - this.bitLengthCounts[incrBitLen]--; - this.bitLengthCounts[++incrBitLen]++; - overflow -= 1 << (this.maxLength - 1 - incrBitLen); + Unsafe.Add(ref bitLengthCountsRef, incrBitLen)--; + Unsafe.Add(ref bitLengthCountsRef, ++incrBitLen)++; + overflow -= 1 << (maxLen - 1 - incrBitLen); } - while (overflow > 0 && incrBitLen < this.maxLength - 1); + while (overflow > 0 && incrBitLen < maxLen - 1); } while (overflow > 0); // We may have overshot above. Move some nodes from maxLength to // maxLength-1 in that case. - this.bitLengthCounts[this.maxLength - 1] += overflow; - this.bitLengthCounts[this.maxLength - 2] -= overflow; + Unsafe.Add(ref bitLengthCountsRef, maxLen - 1) += overflow; + Unsafe.Add(ref bitLengthCountsRef, maxLen - 2) -= overflow; // Now recompute all bit lengths, scanning in increasing // 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 // array. - int nodePtr = 2 * numLeafs; - for (int bits = this.maxLength; bits != 0; bits--) + int nodeIndex = 2 * numLeafs; + for (int bits = maxLen; bits != 0; bits--) { - int n = this.bitLengthCounts[bits - 1]; + int n = Unsafe.Add(ref bitLengthCountsRef, bits - 1); while (n > 0) { - int childPtr = 2 * children[nodePtr++]; - if (children[childPtr + 1] == -1) + int childIndex = 2 * Unsafe.Add(ref childrenRef, nodeIndex++); + if (Unsafe.Add(ref childrenRef, childIndex + 1) == -1) { // We found another leaf - this.Length[children[childPtr]] = (byte)bits; + lengthPtr[Unsafe.Add(ref childrenRef, childIndex)] = (byte)bits; n--; } }