Skip to content

Commit c58b4db

Browse files
committed
avoids alloc in hash() functions
- avoids ToArray() - avoids Action<> closure
1 parent ff608c5 commit c58b4db

File tree

1 file changed

+35
-37
lines changed

1 file changed

+35
-37
lines changed

src/Peachpie.Library/Hash.cs

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,6 +1212,8 @@ protected void CloneHashState(HashPhpResource clone)
12121212
private byte[] buffer = null;
12131213
private int bufferUsage = 0;
12141214

1215+
internal delegate void ProcessBlockedDelegate(HashPhpResource self, ReadOnlySpan<byte> data);
1216+
12151217
/// <summary>
12161218
/// Returns blocks of data, using buffered data stored before.
12171219
/// Provided data can be too small to fit the block, so they are buffered and processed when more data comes.
@@ -1220,7 +1222,7 @@ protected void CloneHashState(HashPhpResource clone)
12201222
/// <param name="blockSize">Block size, when buffered data fits this, they are returned.</param>
12211223
/// <param name="callback">Called for each block.</param>
12221224
/// <returns>Packs of block, as a pair of byte array and index of first element.</returns>
1223-
internal void ProcessBlocked(ReadOnlySpan<byte>/*!*/newData, int blockSize, Action<byte[], int> callback)
1225+
internal void ProcessBlocked(ReadOnlySpan<byte>/*!*/newData, int blockSize, ProcessBlockedDelegate callback)
12241226
{
12251227
Debug.Assert(blockSize > 0);
12261228

@@ -1242,7 +1244,7 @@ internal void ProcessBlocked(ReadOnlySpan<byte>/*!*/newData, int blockSize, Acti
12421244
}
12431245

12441246
newData.Slice(0, bytesToFitBuffer).CopyTo(buffer.AsSpan(bufferUsage, bytesToFitBuffer));
1245-
callback(buffer, 0); // use the data from buffer
1247+
callback(this, buffer); // use the data from buffer
12461248

12471249
bufferUsage = 0; // buffer is empty now
12481250
index += bytesToFitBuffer; // part of newData was used
@@ -1251,7 +1253,7 @@ internal void ProcessBlocked(ReadOnlySpan<byte>/*!*/newData, int blockSize, Acti
12511253
// returns blocks from the newData
12521254
while (index + blockSize <= newData.Length)
12531255
{
1254-
callback(newData.ToArray(), index);
1256+
callback(this, newData.Slice(index));
12551257
index += blockSize;
12561258
}
12571259

@@ -1728,16 +1730,16 @@ public override void Init()
17281730
Array.Clear(this.checksum, 0, this.checksum.Length);
17291731
}
17301732

1731-
private void TransformBlock(byte[]/*!*//*byte[16+startIndex]*/block, int startIndex)
1733+
private void TransformBlock(ReadOnlySpan<byte>/*!*//*byte[16+startIndex]*/block)
17321734
{
17331735
Debug.Assert(block != null);
1734-
Debug.Assert(block.Length >= 16 + startIndex);
1736+
Debug.Assert(block.Length >= 16);
17351737

17361738
byte i, j, t = 0;
17371739

17381740
for (i = 0; i < 16; i++)
17391741
{
1740-
state[16 + i] = block[i + startIndex];
1742+
state[16 + i] = block[i];
17411743
state[32 + i] = (byte)(state[16 + i] ^ state[i]);
17421744
}
17431745

@@ -1757,15 +1759,15 @@ private void TransformBlock(byte[]/*!*//*byte[16+startIndex]*/block, int startIn
17571759
t = checksum[15];
17581760
for (i = 0; i < 16; i++)
17591761
{
1760-
t = checksum[i] ^= MD2_S[block[i + startIndex] ^ t];
1762+
t = checksum[i] ^= MD2_S[block[i] ^ t];
17611763
}
17621764
}
17631765

17641766
public override bool Update(ReadOnlySpan<byte> data)
17651767
{
1766-
ProcessBlocked(data, 16, (block, index) =>
1768+
ProcessBlocked(data, 16, (self, block) =>
17671769
{
1768-
TransformBlock(block, index);
1770+
((MD2)self).TransformBlock(block);
17691771
});
17701772

17711773
return true;
@@ -1785,8 +1787,8 @@ public override byte[] Final()
17851787
buffer[i] = remainingBytes;
17861788

17871789
//
1788-
TransformBlock(buffer, 0);
1789-
TransformBlock(checksum, 0);
1790+
TransformBlock(buffer.AsSpan());
1791+
TransformBlock(checksum.AsSpan());
17901792

17911793
//
17921794
byte[] hash = new byte[16];
@@ -1815,18 +1817,17 @@ public sealed class MD4 : HashPhpResource
18151817
private static void MD4_R1(ref uint a, uint b, uint c, uint d, uint xk, byte s) { unchecked { a = ROTL32(s, a + MD4_F(b, c, d) + xk); } }
18161818
private static void MD4_R2(ref uint a, uint b, uint c, uint d, uint xk, byte s) { unchecked { a = ROTL32(s, a + MD4_G(b, c, d) + xk + 0x5A827999); } }
18171819
private static void MD4_R3(ref uint a, uint b, uint c, uint d, uint xk, byte s) { unchecked { a = ROTL32(s, a + MD4_H(b, c, d) + xk + 0x6ED9EBA1); } }
1818-
private static uint[] Decode(byte[] block, int startIndex, int bytesCount)
1820+
private static uint[] Decode(ReadOnlySpan<byte> block)
18191821
{
1820-
Debug.Assert(bytesCount > 0);
1821-
Debug.Assert((bytesCount % 4) == 0);
1822+
Debug.Assert(block.Length > 0);
1823+
Debug.Assert((block.Length % 4) == 0);
18221824

1823-
uint[] result = new uint[bytesCount / 4];
1825+
uint[] result = new uint[block.Length / 4];
18241826
int index = 0;
1825-
while (bytesCount > 0)
1827+
while (block.Length > 0)
18261828
{
1827-
result[index++] = BitConverter.ToUInt32(block, startIndex);
1828-
startIndex += 4;
1829-
bytesCount -= 4;
1829+
result[index++] = BitConverter.ToUInt32(block);
1830+
block = block.Slice(4);
18301831
}
18311832

18321833
return result;
@@ -1847,11 +1848,10 @@ private static byte[] Encode(uint[] nums, int startIndex, int bytesCount)
18471848

18481849
return result;
18491850
}
1850-
private void MD4Transform(byte[] block, int startIndex)
1851+
private void MD4Transform(ReadOnlySpan<byte> block)
18511852
{
18521853
uint a = state[0], b = state[1], c = state[2], d = state[3];
1853-
uint[] x = Decode(block, startIndex, 64);
1854-
1854+
uint[] x = Decode(block.Slice(0, 64));
18551855

18561856
/* Round 1 */
18571857
MD4_R1(ref a, b, c, d, x[0], 3);
@@ -1948,9 +1948,9 @@ public override bool Update(ReadOnlySpan<byte> data)
19481948
++count[1];
19491949
count[1] += ((uint)data.Length >> 29);
19501950

1951-
ProcessBlocked(data, 64, (block, index) =>
1951+
ProcessBlocked(data, 64, (self, block) =>
19521952
{
1953-
MD4Transform(block, index);
1953+
((MD4)self).MD4Transform(block);
19541954
});
19551955

19561956
return true;
@@ -2075,18 +2075,17 @@ private static void II(ref uint a, uint b, uint c, uint d, uint x, byte s, uint
20752075
}
20762076
}
20772077

2078-
private static uint[] Decode(byte[] block, int startIndex, int bytesCount)
2078+
private static uint[] Decode(ReadOnlySpan<byte> block)
20792079
{
2080-
Debug.Assert(bytesCount > 0);
2081-
Debug.Assert((bytesCount % 4) == 0);
2080+
Debug.Assert(block.Length > 0);
2081+
Debug.Assert((block.Length % 4) == 0);
20822082

2083-
uint[] result = new uint[bytesCount / 4];
2083+
uint[] result = new uint[block.Length / 4];
20842084
int index = 0;
2085-
while (bytesCount > 0)
2085+
while (block.Length > 0)
20862086
{
2087-
result[index++] = BitConverter.ToUInt32(block, startIndex);
2088-
startIndex += 4;
2089-
bytesCount -= 4;
2087+
result[index++] = BitConverter.ToUInt32(block);
2088+
block = block.Slice(4);
20902089
}
20912090

20922091
return result;
@@ -2112,12 +2111,11 @@ private static byte[] Encode(uint[] nums, int startIndex, int bytesCount)
21122111
/// MD5 basic transformation. Transforms state based on block.
21132112
/// </summary>
21142113
/// <param name="block"></param>
2115-
/// <param name="startIndex"></param>
2116-
private void MD5Transform(byte[]/*[64]*/block, int startIndex)
2114+
private void MD5Transform(ReadOnlySpan<byte>/*[64]*/block)
21172115
{
21182116
uint a = state[0], b = state[1], c = state[2], d = state[3];
21192117

2120-
uint[] x = Decode(block, startIndex, 64); // [16]
2118+
uint[] x = Decode(block.Slice(0, 64)); // [16]
21212119
Debug.Assert(x.Length == 16);
21222120

21232121
/* Round 1 */
@@ -2234,9 +2232,9 @@ public override bool Update(ReadOnlySpan<byte>/*!*/data)
22342232
count[1] += ((uint)data.Length >> 29);
22352233

22362234
// Transform blocks of 64 bytes
2237-
ProcessBlocked(data, 64, (block, index) =>
2235+
ProcessBlocked(data, 64, (self, block) =>
22382236
{
2239-
MD5Transform(block, index);
2237+
((MD5)self).MD5Transform(block);
22402238
});
22412239

22422240
return true;

0 commit comments

Comments
 (0)