Skip to content

Commit 13ff1d6

Browse files
authored
Use IBufferProtocol in zlib (#979)
* Use IBufferProtocol in zlib * Update help strings
1 parent eea88db commit 13ff1d6

File tree

3 files changed

+47
-30
lines changed

3 files changed

+47
-30
lines changed

Src/IronPython.Modules/binascii.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -374,20 +374,19 @@ private static int crc_hqx_impl(IList<byte> data, int crc) {
374374

375375
#region crc32
376376

377-
[Documentation("crc32(string[, value]) -> string\n\nComputes a CRC (Cyclic Redundancy Check) checksum of string.")]
378-
public static object crc32([NotNull]IBufferProtocol data, uint crc = 0)
379-
=> crc32_impl(data.ToBytes(), crc);
380-
381-
private static object crc32_impl(IList<byte> bytes, uint crc) {
382-
var res = crc32(bytes, 0, bytes.Count, crc);
377+
[Documentation("crc32(data[, crc]) -> string\n\nComputes a CRC (Cyclic Redundancy Check) checksum of data.")]
378+
public static object crc32([NotNull]IBufferProtocol data, uint crc = 0) {
379+
// TODO: [PythonIndex(overflow=mask)] uint crc = 0
380+
using var buffer = data.GetBuffer();
381+
var res = crc32(buffer.AsReadOnlySpan(), crc);
383382
if (res <= int.MaxValue) return (int)res;
384383
return (BigInteger)res;
385384
}
386385

387-
internal static uint crc32(IList<byte> buffer, int offset, int count, uint baseValue) {
386+
private static uint crc32(ReadOnlySpan<byte> buffer, uint baseValue) {
388387
uint remainder = (baseValue ^ 0xffffffff);
389-
for (int i = offset; i < offset + count; i++) {
390-
remainder ^= buffer[i];
388+
foreach (byte val in buffer) {
389+
remainder ^= val;
391390
for (int j = 0; j < 8; j++) {
392391
if ((remainder & 0x01) != 0) {
393392
remainder = (remainder >> 1) ^ 0xEDB88320;

Src/IronPython.Modules/zlib/ZlibModule.cs

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ public static class ZlibModule
2727
public const string __doc__ = @"The functions in this module allow compression and decompression using the
2828
zlib library, which is based on GNU zip.
2929
30-
adler32(string[, start]) -- Compute an Adler-32 checksum.
31-
compress(string[, level]) -- Compress string, with compression level in 1-9.
30+
adler32(data[, value]) -- Compute an Adler-32 checksum.
31+
compress(data[, level]) -- Compress data, with compression level 1-9.
3232
compressobj([level]) -- Return a compressor object.
33-
crc32(string[, start]) -- Compute a CRC-32 checksum.
34-
decompress(string,[wbits],[bufsize]) -- Decompresses a compressed string.
33+
crc32(data[, value]) -- Compute a CRC-32 checksum.
34+
decompress(data,[wbits],[bufsize]) -- Decompresses compressed data.
3535
decompressobj([wbits]) -- Return a decompressor object.
3636
3737
'wbits' is window buffer size.
@@ -69,34 +69,32 @@ public static class ZlibModule
6969

7070
internal const int DEFAULTALLOC = 16 * 1024;
7171

72-
[Documentation(@"adler32(string[, start]) -- Compute an Adler-32 checksum of string.
72+
[Documentation(@"adler32(data[, value]) -- Compute an Adler-32 checksum of data.
7373
7474
An optional starting value can be specified. The returned checksum is
7575
a signed integer.")]
76-
public static int adler32([BytesLike]IList<byte> data, long baseValue=1L)
76+
public static int adler32([NotNull] IBufferProtocol data, long value=1L)
7777
{
78-
return (int)Adler32.GetAdler32Checksum(baseValue, data.ToArray(), 0, data.Count);
78+
using var buffer = data.GetBuffer();
79+
return (int)Adler32.GetAdler32Checksum(value, buffer.AsUnsafeArray() ?? buffer.ToArray(), 0, buffer.NumBytes());
7980
}
8081

81-
[Documentation(@"crc32(string[, start]) -- Compute a CRC-32 checksum of string.
82+
[Documentation(@"crc32(data[, value]) -- Compute a CRC-32 checksum of data.
8283
8384
An optional starting value can be specified. The returned checksum is
8485
a signed integer.")]
85-
public static BigInteger crc32([BytesLike]IList<byte> data, long baseValue=0L)
86-
{
87-
if(baseValue < int.MinValue || baseValue > uint.MaxValue)
88-
throw new ArgumentOutOfRangeException(nameof(baseValue));
89-
90-
return IronPython.Modules.PythonBinaryAscii.crc32(data, 0, data.Count, (uint)baseValue);
91-
}
86+
public static object crc32([NotNull] IBufferProtocol data, uint value = 0)
87+
// TODO: [PythonIndex(overflow=mask)] uint value = 0
88+
=> IronPython.Modules.PythonBinaryAscii.crc32(data, value);
9289

93-
[Documentation(@"compress(string[, level]) -- Returned compressed string.
90+
[Documentation(@"compress(data[, level]) -- Returns a bytes object containing compressed data.
9491
9592
Optional arg level is the compression level, in 1-9.")]
96-
public static Bytes compress([BytesLike]IList<byte> data,
93+
public static Bytes compress([NotNull] IBufferProtocol data,
9794
int level=Z_DEFAULT_COMPRESSION)
9895
{
99-
byte[] input = data.ToArray();
96+
using var buffer = data.GetBuffer();
97+
byte[] input = buffer.AsUnsafeArray() ?? buffer.ToArray();
10098
byte[] output = new byte[input.Length + input.Length / 1000 + 12 + 1];
10199

102100
ZStream zst = new ZStream();
@@ -154,15 +152,16 @@ public static Compress compressobj(
154152
return new Compress(level, method, wbits, memlevel, strategy);
155153
}
156154

157-
[Documentation(@"decompress(string[, wbits[, bufsize]]) -- Return decompressed string.
155+
[Documentation(@"decompress(data[, wbits[, bufsize]]) -- Returns a bytes object containing the uncompressed data.
158156
159157
Optional arg wbits is the window buffer size. Optional arg bufsize is
160158
the initial output buffer size.")]
161-
public static Bytes decompress([BytesLike]IList<byte> data,
159+
public static Bytes decompress([NotNull] IBufferProtocol data,
162160
int wbits=MAX_WBITS,
163161
int bufsize=DEFAULTALLOC)
164162
{
165-
var bytes = Decompress(data.ToArray(), wbits, bufsize);
163+
using var buffer = data.GetBuffer();
164+
var bytes = Decompress(buffer.AsUnsafeArray() ?? buffer.ToArray(), wbits, bufsize);
166165
return Bytes.Make(bytes);
167166
}
168167

Src/IronPython/Runtime/BufferProtocol.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System;
88
using System.Collections.Generic;
99
using System.Diagnostics;
10+
using System.Runtime.InteropServices;
1011

1112
using IronPython.Runtime.Exceptions;
1213

@@ -272,6 +273,24 @@ public static void CopyTo(this IPythonBuffer buffer, Span<byte> dest) {
272273
}
273274
}
274275
}
276+
277+
internal static byte[]? AsUnsafeArray(this IPythonBuffer buffer) {
278+
if (!buffer.IsCContiguous())
279+
return null;
280+
281+
if (buffer.Object is Bytes b)
282+
return b.UnsafeByteArray;
283+
284+
if (buffer.Object is Memory<byte> mem) {
285+
if (MemoryMarshal.TryGetArray(mem, out ArraySegment<byte> seg) && seg.Array != null && seg.Offset == 0 && seg.Count == seg.Array.Length)
286+
return seg.Array;
287+
} else if (buffer.Object is ReadOnlyMemory<byte> rom) {
288+
if (MemoryMarshal.TryGetArray(rom, out ArraySegment<byte> seg) && seg.Array != null && seg.Offset == 0 && seg.Count == seg.Array.Length)
289+
return seg.Array;
290+
}
291+
292+
return null;
293+
}
275294
}
276295

277296
public ref struct BufferBytesEnumerator {

0 commit comments

Comments
 (0)