Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert MemoryBufferProtocolWrapper to generic #1906

Merged
merged 2 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/core/IronPython/Runtime/Binding/ConversionBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -734,8 +734,9 @@ private DynamicMetaObject ConvertFromMemoryToBufferProtocol(DynamicMetaObject se
return new DynamicMetaObject(
AstUtils.Convert(
Ast.New(
typeof(MemoryBufferProtocolWrapper).GetConstructor(new Type[] { fromType }),
AstUtils.Convert(self.Expression, fromType)
typeof(MemoryBufferProtocolWrapper<byte>).GetConstructor([fromType, typeof(string)]),
AstUtils.Convert(self.Expression, fromType),
AstUtils.Constant(null, typeof(string))
),
typeof(IBufferProtocol)
),
Expand Down
91 changes: 45 additions & 46 deletions src/core/IronPython/Runtime/ConversionWrappers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Runtime.InteropServices;

namespace IronPython.Runtime {

Expand Down Expand Up @@ -376,79 +377,77 @@ IEnumerator IEnumerable.GetEnumerator() {
#endregion
}

public sealed class MemoryBufferWrapper : IPythonBuffer {
private readonly ReadOnlyMemory<byte> _rom;
private readonly Memory<byte>? _memory;
private readonly BufferFlags _flags;
public sealed class MemoryBufferProtocolWrapper<T> : IBufferProtocol where T : unmanaged {
private readonly ReadOnlyMemory<T> _rom;
private readonly Memory<T>? _memory;
private readonly string? _format;

public MemoryBufferWrapper(ReadOnlyMemory<byte> memory, BufferFlags flags) {
public MemoryBufferProtocolWrapper(ReadOnlyMemory<T> memory, string? format = null) {
_rom = memory;
_memory = null;
_flags = flags;
_format = format;
}

public MemoryBufferWrapper(Memory<byte> memory, BufferFlags flags) {
public MemoryBufferProtocolWrapper(Memory<T> memory, string? format = null) {
_rom = memory;
_memory = memory;
_flags = flags;
_format = format;
}

public void Dispose() { }

public object Object => _memory ?? _rom;
public IPythonBuffer? GetBuffer(BufferFlags flags, bool throwOnError) {
if (_memory.HasValue) {
return new MemoryBufferWrapper(this, flags);
}

public bool IsReadOnly => !_memory.HasValue;
if (flags.HasFlag(BufferFlags.Writable)) {
if (throwOnError) {
throw Operations.PythonOps.BufferError("ReadOnlyMemory is not writable.");
}
return null;
}

public ReadOnlySpan<byte> AsReadOnlySpan() => _rom.Span;
return new MemoryBufferWrapper(this, flags);
}

public Span<byte> AsSpan() => _memory.HasValue ? _memory.Value.Span : throw new InvalidOperationException("ReadOnlyMemory is not writable");
private sealed unsafe class MemoryBufferWrapper : IPythonBuffer {
private readonly MemoryBufferProtocolWrapper<T> _wrapper;
private readonly BufferFlags _flags;

public MemoryHandle Pin() => _rom.Pin();
public MemoryBufferWrapper(MemoryBufferProtocolWrapper<T> wrapper, BufferFlags flags) {
_wrapper = wrapper;
_flags = flags;
}

public int Offset => 0;
public void Dispose() { }

public string? Format => _flags.HasFlag(BufferFlags.Format) ? "B" : null;
public object Object => _wrapper._memory ?? _wrapper._rom;

public int ItemCount => _rom.Length;
public bool IsReadOnly => !_wrapper._memory.HasValue;

public int ItemSize => 1;
public ReadOnlySpan<byte> AsReadOnlySpan() => MemoryMarshal.Cast<T, byte>(_wrapper._rom.Span);

public int NumOfDims => 1;
public Span<byte> AsSpan()
=> _wrapper._memory.HasValue
? MemoryMarshal.Cast<T, byte>(_wrapper._memory.Value.Span)
: throw new InvalidOperationException("ReadOnlyMemory is not writable");

public IReadOnlyList<int>? Shape => null;
public MemoryHandle Pin() => _wrapper._rom.Pin();

public IReadOnlyList<int>? Strides => null;
public int Offset => 0;

public IReadOnlyList<int>? SubOffsets => null;
}
public string? Format => _flags.HasFlag(BufferFlags.Format) ? _wrapper._format : null;

public class MemoryBufferProtocolWrapper : IBufferProtocol {
private readonly ReadOnlyMemory<byte> _rom;
private readonly Memory<byte>? _memory;
public int ItemCount => _wrapper._rom.Length;

public MemoryBufferProtocolWrapper(ReadOnlyMemory<byte> memory) {
_rom = memory;
_memory = null;
}
public int ItemSize => sizeof(T);

public MemoryBufferProtocolWrapper(Memory<byte> memory) {
_rom = memory;
_memory = memory;
}
public int NumOfDims => 1;

public IPythonBuffer? GetBuffer(BufferFlags flags, bool throwOnError) {
if (_memory.HasValue) {
return new MemoryBufferWrapper(_memory.Value, flags);
}
public IReadOnlyList<int>? Shape => null;

if (flags.HasFlag(BufferFlags.Writable)) {
if (throwOnError) {
throw Operations.PythonOps.BufferError("ReadOnlyMemory is not writable.");
}
return null;
}
public IReadOnlyList<int>? Strides => null;

return new MemoryBufferWrapper(_rom, flags);
public IReadOnlyList<int>? SubOffsets => null;
}
}
}