// 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. using System; using System.Runtime.CompilerServices; #if NETSTANDARD2_1_OR_GREATER using System.Runtime.InteropServices; #else using CommunityToolkit.HighPerformance.Helpers; #endif namespace CommunityToolkit.HighPerformance; /// /// A that can store a reference to a value of a specified type. /// /// The type of value to reference. public readonly ref struct Ref { #if NETSTANDARD2_1_OR_GREATER /// /// The 1-length instance used to track the target value. /// internal readonly Span Span; /// /// Initializes a new instance of the struct. /// /// The reference to the target value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ref(ref T value) { Span = MemoryMarshal.CreateSpan(ref value, 1); } /// /// Initializes a new instance of the struct. /// /// The pointer to the target value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe Ref(void* pointer) : this(ref Unsafe.AsRef(pointer)) { } /// /// Gets the reference represented by the current instance. /// public ref T Value { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => ref MemoryMarshal.GetReference(Span); } #else /// /// The owner the current instance belongs to /// internal readonly object Owner; /// /// The target offset within the current instance is pointing to /// /// /// Using an instead of to avoid the int to /// native int conversion in the generated asm (an extra movsxd on x64). /// internal readonly IntPtr Offset; /// /// Initializes a new instance of the struct. /// /// The owner to create a portable reference for. /// The target reference to point to (it must be within ). /// The parameter is not validated, and it's responsibility of the caller to ensure it's valid. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ref(object owner, ref T value) { Owner = owner; Offset = ObjectMarshal.DangerousGetObjectDataByteOffset(owner, ref value); } /// /// Gets the reference represented by the current instance. /// public ref T Value { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => ref ObjectMarshal.DangerousGetObjectDataReferenceAt(Owner, Offset); } #endif /// /// Implicitly gets the value from a given instance. /// /// The input instance. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator T(Ref reference) { return reference.Value; } }