// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #if NETSTANDARD2_1_OR_GREATER using System; using System.Buffers; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using CommunityToolkit.HighPerformance.Helpers; namespace CommunityToolkit.HighPerformance.Buffers.Internals; /// /// A custom that can wrap arbitrary instances. /// /// The type of elements in the target memory area. internal sealed class RawObjectMemoryManager : MemoryManager { /// /// The target instance. /// private readonly object instance; /// /// The initial offset within . /// private readonly IntPtr offset; /// /// The length of the target memory area. /// private readonly int length; /// /// Initializes a new instance of the class. /// /// The target instance. /// The starting offset within . /// The usable length within . public RawObjectMemoryManager(object instance, IntPtr offset, int length) { this.instance = instance; this.offset = offset; this.length = length; } /// public override Span GetSpan() { ref T r0 = ref ObjectMarshal.DangerousGetObjectDataReferenceAt(this.instance, this.offset); return MemoryMarshal.CreateSpan(ref r0, this.length); } /// public override unsafe MemoryHandle Pin(int elementIndex = 0) { if ((uint)elementIndex >= (uint)this.length) { ThrowArgumentOutOfRangeExceptionForInvalidElementIndex(); } // Allocating a pinned handle for the array with fail and throw an exception // if the array contains non blittable data. This is the expected behavior and // the same happens when trying to pin a Memory instance obtained through // traditional means (eg. via the implicit T[] array conversion), if T is a // reference type or a type containing some references. GCHandle handle = GCHandle.Alloc(this.instance, GCHandleType.Pinned); ref T r0 = ref ObjectMarshal.DangerousGetObjectDataReferenceAt(this.instance, this.offset); ref T r1 = ref Unsafe.Add(ref r0, (nint)(uint)elementIndex); void* p = Unsafe.AsPointer(ref r1); return new(p, handle); } /// public override void Unpin() { } /// protected override void Dispose(bool disposing) { } /// /// Throws an when the input index for is not valid. /// private static void ThrowArgumentOutOfRangeExceptionForInvalidElementIndex() { throw new ArgumentOutOfRangeException("elementIndex", "The input element index was not in the valid range"); } } #endif