将字符串转换为 IMemoryOwner / 将字符串复制到租用的缓冲区中
Convert string to IMemoryOwner / Copy string into a rented buffer
我有一个自定义记忆序列OwnedMemorySequence
。我想在里面放一根绳子。问题是我无法编译它。通常像 Encoding.UTF8.GetBytes
这样的东西,然后将该缓冲区复制到租用的缓冲区中应该可以工作,但在我的情况下存在编译时错误。
var message = "Hello";
var buffer = MemoryPool<byte>.Shared.Rent(Encoding.UTF8.GetByteCount(message));
Encoding.UTF8.Convert(message, buffer.Memory, true, out _, out _, out _); // no such overload
var seq = new OwnedMemorySequence<byte>();
seq.Append(buffer);
代码
public sealed class OwnedMemorySequence<T> : IDisposable
{
private readonly CollectionDisposable _disposable = new();
private readonly MemorySequence<T> _sequence = new();
public ReadOnlySequence<T> ReadOnlySequence => _sequence.ReadOnlySequence;
public void Dispose()
{
_disposable.Dispose();
}
public OwnedMemorySequence<T> Append(IMemoryOwner<T> memoryOwner)
{
_disposable.Add(memoryOwner);
_sequence.Append(memoryOwner.Memory);
return this;
}
public ReadOnlySequence<T> CreateReadOnlySequence(int firstBufferStartIndex, int lastBufferEndIndex)
{
return _sequence.CreateReadOnlySequence(firstBufferStartIndex, lastBufferEndIndex);
}
}
public sealed class MemorySequence<T>
{
private MemorySegment? _head;
private MemorySegment? _tail;
public ReadOnlySequence<T> ReadOnlySequence => CreateReadOnlySequence(0, _tail?.Memory.Length ?? 0);
public MemorySequence<T> Append(ReadOnlyMemory<T> buffer)
{
if (_tail == null)
_head = _tail = new MemorySegment(buffer, 0);
else
_tail = _tail.Append(buffer);
return this;
}
public ReadOnlySequence<T> CreateReadOnlySequence(int firstBufferStartIndex, int lastBufferEndIndex)
{
return _tail == null ? new ReadOnlySequence<T>(Array.Empty<T>()) : new ReadOnlySequence<T>(_head!, firstBufferStartIndex, _tail, lastBufferEndIndex);
}
private sealed class MemorySegment : ReadOnlySequenceSegment<T>
{
public MemorySegment(ReadOnlyMemory<T> memory, long runningIndex)
{
Memory = memory;
RunningIndex = runningIndex;
}
public MemorySegment Append(ReadOnlyMemory<T> nextMemory)
{
var next = new MemorySegment(nextMemory, RunningIndex + Memory.Length);
Next = next;
return next;
}
}
}
public static class MemoryOwnerExtensions
{
/// <summary>
/// Rent a buffer from a pool with an exact length.
/// </summary>
/// <param name="pool">The <see cref="MemoryPool{T}" /> instance.</param>
/// <param name="exactBufferSize">The exact size of the buffer.</param>
public static IMemoryOwner<T> RentExact<T>(this MemoryPool<T> pool, int exactBufferSize)
{
if (pool == null) throw new ArgumentNullException(nameof(pool));
var rented = pool.Rent(exactBufferSize);
if (exactBufferSize == rented.Memory.Length)
return rented;
return new SliceOwner<T>(rented, 0, exactBufferSize);
}
/// <summary>
/// Wrap an existing <see cref="IMemoryOwner{T}" /> instance in a lightweight manner, but allow
/// the <see cref="IMemoryOwner{T}.Memory" /> member to have a different length.
/// </summary>
/// <param name="owner">The original instance.</param>
/// <param name="start">The starting offset of the slice.</param>
/// <param name="length">The length of the slice.</param>
public static IMemoryOwner<T> Slice<T>(this IMemoryOwner<T> owner, int start, int length)
{
if (owner == null) throw new ArgumentNullException(nameof(owner));
if (start == 0 && length == owner.Memory.Length)
return owner;
if ((uint)start >= (uint)owner.Memory.Length) throw new ArgumentOutOfRangeException(nameof(start));
if ((uint)length > (uint)(owner.Memory.Length - start)) throw new ArgumentOutOfRangeException(nameof(length));
return new SliceOwner<T>(owner, start, length);
}
/// <summary>
/// Wrap an existing <see cref="IMemoryOwner{T}" /> instance in a lightweight manner, but allow
/// the <see cref="IMemoryOwner{T}.Memory" /> member to have a different length.
/// </summary>
/// <param name="owner">The original instance.</param>
/// <param name="start">The starting offset of the slice.</param>
public static IMemoryOwner<T> Slice<T>(this IMemoryOwner<T> owner, int start)
{
if (owner == null) throw new ArgumentNullException(nameof(owner));
if (start == 0)
return owner;
if ((uint)start >= (uint)owner.Memory.Length) throw new ArgumentOutOfRangeException(nameof(start));
return new SliceOwner<T>(owner, start);
}
private sealed class SliceOwner<T> : IMemoryOwner<T>
{
private IMemoryOwner<T> _owner;
public SliceOwner(IMemoryOwner<T> owner, int start, int length)
{
_owner = owner;
Memory = _owner.Memory.Slice(start, length);
}
public SliceOwner(IMemoryOwner<T> owner, int start)
{
_owner = owner;
Memory = _owner.Memory.Slice(start);
}
public Memory<T> Memory { get; private set; }
public void Dispose()
{
if (_owner != null)
{
_owner.Dispose();
_owner = null;
}
Memory = default;
}
}
}
的确,不存在这样的过载。您在文档中的哪个位置查看了该参数?
编码器有类似的方法。
EncodingExtensions.Convert Method
using System;
using System.Buffers;
using System.Text;
public class Program
{
public static void Main()
{
var message = "Hello";
var buffer = MemoryPool<byte>.Shared.Rent(Encoding.UTF8.GetByteCount(message));
Encoding.UTF8.GetEncoder().Convert(message, buffer.Memory.Span, true, out _, out _, out _);
Console.WriteLine(Encoding.UTF8.GetString(buffer.Memory.Span));
}
}
我有一个自定义记忆序列OwnedMemorySequence
。我想在里面放一根绳子。问题是我无法编译它。通常像 Encoding.UTF8.GetBytes
这样的东西,然后将该缓冲区复制到租用的缓冲区中应该可以工作,但在我的情况下存在编译时错误。
var message = "Hello";
var buffer = MemoryPool<byte>.Shared.Rent(Encoding.UTF8.GetByteCount(message));
Encoding.UTF8.Convert(message, buffer.Memory, true, out _, out _, out _); // no such overload
var seq = new OwnedMemorySequence<byte>();
seq.Append(buffer);
代码
public sealed class OwnedMemorySequence<T> : IDisposable
{
private readonly CollectionDisposable _disposable = new();
private readonly MemorySequence<T> _sequence = new();
public ReadOnlySequence<T> ReadOnlySequence => _sequence.ReadOnlySequence;
public void Dispose()
{
_disposable.Dispose();
}
public OwnedMemorySequence<T> Append(IMemoryOwner<T> memoryOwner)
{
_disposable.Add(memoryOwner);
_sequence.Append(memoryOwner.Memory);
return this;
}
public ReadOnlySequence<T> CreateReadOnlySequence(int firstBufferStartIndex, int lastBufferEndIndex)
{
return _sequence.CreateReadOnlySequence(firstBufferStartIndex, lastBufferEndIndex);
}
}
public sealed class MemorySequence<T>
{
private MemorySegment? _head;
private MemorySegment? _tail;
public ReadOnlySequence<T> ReadOnlySequence => CreateReadOnlySequence(0, _tail?.Memory.Length ?? 0);
public MemorySequence<T> Append(ReadOnlyMemory<T> buffer)
{
if (_tail == null)
_head = _tail = new MemorySegment(buffer, 0);
else
_tail = _tail.Append(buffer);
return this;
}
public ReadOnlySequence<T> CreateReadOnlySequence(int firstBufferStartIndex, int lastBufferEndIndex)
{
return _tail == null ? new ReadOnlySequence<T>(Array.Empty<T>()) : new ReadOnlySequence<T>(_head!, firstBufferStartIndex, _tail, lastBufferEndIndex);
}
private sealed class MemorySegment : ReadOnlySequenceSegment<T>
{
public MemorySegment(ReadOnlyMemory<T> memory, long runningIndex)
{
Memory = memory;
RunningIndex = runningIndex;
}
public MemorySegment Append(ReadOnlyMemory<T> nextMemory)
{
var next = new MemorySegment(nextMemory, RunningIndex + Memory.Length);
Next = next;
return next;
}
}
}
public static class MemoryOwnerExtensions
{
/// <summary>
/// Rent a buffer from a pool with an exact length.
/// </summary>
/// <param name="pool">The <see cref="MemoryPool{T}" /> instance.</param>
/// <param name="exactBufferSize">The exact size of the buffer.</param>
public static IMemoryOwner<T> RentExact<T>(this MemoryPool<T> pool, int exactBufferSize)
{
if (pool == null) throw new ArgumentNullException(nameof(pool));
var rented = pool.Rent(exactBufferSize);
if (exactBufferSize == rented.Memory.Length)
return rented;
return new SliceOwner<T>(rented, 0, exactBufferSize);
}
/// <summary>
/// Wrap an existing <see cref="IMemoryOwner{T}" /> instance in a lightweight manner, but allow
/// the <see cref="IMemoryOwner{T}.Memory" /> member to have a different length.
/// </summary>
/// <param name="owner">The original instance.</param>
/// <param name="start">The starting offset of the slice.</param>
/// <param name="length">The length of the slice.</param>
public static IMemoryOwner<T> Slice<T>(this IMemoryOwner<T> owner, int start, int length)
{
if (owner == null) throw new ArgumentNullException(nameof(owner));
if (start == 0 && length == owner.Memory.Length)
return owner;
if ((uint)start >= (uint)owner.Memory.Length) throw new ArgumentOutOfRangeException(nameof(start));
if ((uint)length > (uint)(owner.Memory.Length - start)) throw new ArgumentOutOfRangeException(nameof(length));
return new SliceOwner<T>(owner, start, length);
}
/// <summary>
/// Wrap an existing <see cref="IMemoryOwner{T}" /> instance in a lightweight manner, but allow
/// the <see cref="IMemoryOwner{T}.Memory" /> member to have a different length.
/// </summary>
/// <param name="owner">The original instance.</param>
/// <param name="start">The starting offset of the slice.</param>
public static IMemoryOwner<T> Slice<T>(this IMemoryOwner<T> owner, int start)
{
if (owner == null) throw new ArgumentNullException(nameof(owner));
if (start == 0)
return owner;
if ((uint)start >= (uint)owner.Memory.Length) throw new ArgumentOutOfRangeException(nameof(start));
return new SliceOwner<T>(owner, start);
}
private sealed class SliceOwner<T> : IMemoryOwner<T>
{
private IMemoryOwner<T> _owner;
public SliceOwner(IMemoryOwner<T> owner, int start, int length)
{
_owner = owner;
Memory = _owner.Memory.Slice(start, length);
}
public SliceOwner(IMemoryOwner<T> owner, int start)
{
_owner = owner;
Memory = _owner.Memory.Slice(start);
}
public Memory<T> Memory { get; private set; }
public void Dispose()
{
if (_owner != null)
{
_owner.Dispose();
_owner = null;
}
Memory = default;
}
}
}
的确,不存在这样的过载。您在文档中的哪个位置查看了该参数?
编码器有类似的方法。
EncodingExtensions.Convert Method
using System;
using System.Buffers;
using System.Text;
public class Program
{
public static void Main()
{
var message = "Hello";
var buffer = MemoryPool<byte>.Shared.Rent(Encoding.UTF8.GetByteCount(message));
Encoding.UTF8.GetEncoder().Convert(message, buffer.Memory.Span, true, out _, out _, out _);
Console.WriteLine(Encoding.UTF8.GetString(buffer.Memory.Span));
}
}