Skip to content

Commit ba22d22

Browse files
committed
Optimized [ReadOnly]Memory<T> cast to source T
1 parent db31e98 commit ba22d22

File tree

4 files changed

+24
-8
lines changed

4 files changed

+24
-8
lines changed

Microsoft.Toolkit.HighPerformance/Buffers/Internals/ArrayMemoryManager{TFrom,TTo}.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,18 @@ protected override void Dispose(bool disposing)
9999
}
100100

101101
/// <inheritdoc/>
102-
public MemoryManager<T> Cast<T>(int offset, int length)
102+
public Memory<T> GetMemory<T>(int offset, int length)
103103
where T : unmanaged
104104
{
105-
return new ArrayMemoryManager<TFrom, T>(this.array, this.offset + offset, length);
105+
// We have a special handling in cases where the user is circling back to the original type
106+
// of the wrapped array. In this case we can just return a memory wrapping that array directly,
107+
// with offset and length being adjusted, without the memory manager indirection.
108+
if (typeof(T) == typeof(TFrom))
109+
{
110+
return (Memory<T>)(object)this.array.AsMemory(this.offset + offset, length);
111+
}
112+
113+
return new ArrayMemoryManager<TFrom, T>(this.array, this.offset + offset, length).Memory;
106114
}
107115

108116
/// <summary>

Microsoft.Toolkit.HighPerformance/Buffers/Internals/Interfaces/IMemoryManager.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System;
56
using System.Buffers;
67

78
namespace Microsoft.Toolkit.HighPerformance.Buffers.Internals.Interfaces
@@ -12,13 +13,13 @@ namespace Microsoft.Toolkit.HighPerformance.Buffers.Internals.Interfaces
1213
internal interface IMemoryManager
1314
{
1415
/// <summary>
15-
/// Creates a new <see cref="MemoryManager{T}"/> that reinterprets the underlying data for the current instance.
16+
/// Creates a new <see cref="Memory{T}"/> that reinterprets the underlying data for the current instance.
1617
/// </summary>
1718
/// <typeparam name="T">The target type to cast the items to.</typeparam>
1819
/// <param name="offset">The starting offset within the data store.</param>
1920
/// <param name="length">The original used length for the data store.</param>
20-
/// <returns>A new <see cref="MemoryManager{T}"/> instance of the specified type, reinterpreting the current items.</returns>
21-
MemoryManager<T> Cast<T>(int offset, int length)
21+
/// <returns>A new <see cref="Memory{T}"/> instance of the specified type, reinterpreting the current items.</returns>
22+
Memory<T> GetMemory<T>(int offset, int length)
2223
where T : unmanaged;
2324
}
2425
}

Microsoft.Toolkit.HighPerformance/Buffers/Internals/ProxyMemoryManager{TFrom,TTo}.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,17 @@ protected override void Dispose(bool disposing)
9494
}
9595

9696
/// <inheritdoc/>
97-
public MemoryManager<T> Cast<T>(int offset, int length)
97+
public Memory<T> GetMemory<T>(int offset, int length)
9898
where T : unmanaged
9999
{
100-
return new ProxyMemoryManager<TFrom, T>(this.memoryManager, this.offset + offset, length);
100+
// Like in the other memory manager, we can skip one level of indirection in cases
101+
// where the user is just going back to the original memory type, reusing the manager.
102+
if (typeof(T) == typeof(TFrom))
103+
{
104+
return (Memory<T>)(object)this.memoryManager.Memory.Slice(offset, length);
105+
}
106+
107+
return new ProxyMemoryManager<TFrom, T>(this.memoryManager, this.offset + offset, length).Memory;
101108
}
102109

103110
/// <summary>

Microsoft.Toolkit.HighPerformance/Extensions/ReadOnlyMemoryExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public static ReadOnlyMemory<TTo> Cast<TFrom, TTo>(this ReadOnlyMemory<TFrom> me
6868
// indirection level in the chain of memory managers needed to access the target data buffer to use.
6969
if (memoryManager is IMemoryManager wrappingManager)
7070
{
71-
return wrappingManager.Cast<TTo>(start, length).Memory;
71+
return wrappingManager.GetMemory<TTo>(start, length);
7272
}
7373

7474
return new ProxyMemoryManager<TFrom, TTo>(memoryManager, start, length).Memory;

0 commit comments

Comments
 (0)