From 0055195d1c8fdf2fa2f165e4ce6faa792488d699 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 11 Sep 2019 07:02:21 -0700 Subject: [PATCH] Change Vector to use more compact code using S.R.CS.Unsafe (#26637) S.R.CS.Unsafe is used in number of places in Vector already. This change modifies more places to use it to make the code more compact. Updated Vector.tt template to match while I was on it Signed-off-by: dotnet-bot --- .../shared/System/Numerics/Vector.cs | 1306 ++++---------------- .../shared/System/Numerics/Vector.tt | 305 +---- 2 files changed, 330 insertions(+), 1281 deletions(-) diff --git a/netcore/System.Private.CoreLib/shared/System/Numerics/Vector.cs b/netcore/System.Private.CoreLib/shared/System/Numerics/Vector.cs index 99e8b053702..da92955b10e 100644 --- a/netcore/System.Private.CoreLib/shared/System/Numerics/Vector.cs +++ b/netcore/System.Private.CoreLib/shared/System/Numerics/Vector.cs @@ -1,17 +1,22 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. -#nullable enable -#if netcoreapp -using Internal.Runtime.CompilerServices; -#endif using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; +using Internal.Runtime.CompilerServices; + +#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types +#if BIT64 +using nint = System.Int64; +#else +using nint = System.Int32; +#endif + namespace System.Numerics { /* Note: The following patterns are used throughout the code here and are described here @@ -106,7 +111,7 @@ namespace System.Numerics { fixed (byte* basePtr = &this.register.byte_0) { - for (int g = 0; g < Count; g++) + for (nint g = 0; g < Count; g++) { *(basePtr + g) = (byte)(object)value; } @@ -116,7 +121,7 @@ namespace System.Numerics { fixed (sbyte* basePtr = &this.register.sbyte_0) { - for (int g = 0; g < Count; g++) + for (nint g = 0; g < Count; g++) { *(basePtr + g) = (sbyte)(object)value; } @@ -126,7 +131,7 @@ namespace System.Numerics { fixed (ushort* basePtr = &this.register.uint16_0) { - for (int g = 0; g < Count; g++) + for (nint g = 0; g < Count; g++) { *(basePtr + g) = (ushort)(object)value; } @@ -136,7 +141,7 @@ namespace System.Numerics { fixed (short* basePtr = &this.register.int16_0) { - for (int g = 0; g < Count; g++) + for (nint g = 0; g < Count; g++) { *(basePtr + g) = (short)(object)value; } @@ -146,7 +151,7 @@ namespace System.Numerics { fixed (uint* basePtr = &this.register.uint32_0) { - for (int g = 0; g < Count; g++) + for (nint g = 0; g < Count; g++) { *(basePtr + g) = (uint)(object)value; } @@ -156,7 +161,7 @@ namespace System.Numerics { fixed (int* basePtr = &this.register.int32_0) { - for (int g = 0; g < Count; g++) + for (nint g = 0; g < Count; g++) { *(basePtr + g) = (int)(object)value; } @@ -166,7 +171,7 @@ namespace System.Numerics { fixed (ulong* basePtr = &this.register.uint64_0) { - for (int g = 0; g < Count; g++) + for (nint g = 0; g < Count; g++) { *(basePtr + g) = (ulong)(object)value; } @@ -176,7 +181,7 @@ namespace System.Numerics { fixed (long* basePtr = &this.register.int64_0) { - for (int g = 0; g < Count; g++) + for (nint g = 0; g < Count; g++) { *(basePtr + g) = (long)(object)value; } @@ -186,7 +191,7 @@ namespace System.Numerics { fixed (float* basePtr = &this.register.single_0) { - for (int g = 0; g < Count; g++) + for (nint g = 0; g < Count; g++) { *(basePtr + g) = (float)(object)value; } @@ -196,7 +201,7 @@ namespace System.Numerics { fixed (double* basePtr = &this.register.double_0) { - for (int g = 0; g < Count; g++) + for (nint g = 0; g < Count; g++) { *(basePtr + g) = (double)(object)value; } @@ -316,7 +321,6 @@ namespace System.Numerics /// [Intrinsic] public unsafe Vector(T[] values, int index) - : this() { if (values == null) { @@ -325,928 +329,239 @@ namespace System.Numerics } if (index < 0 || (values.Length - index) < Count) { - throw new IndexOutOfRangeException(SR.Format(SR.Arg_InsufficientNumberOfElements, Vector.Count, nameof(values))); + Vector.ThrowInsufficientNumberOfElementsException(Vector.Count); + } + this = Unsafe.ReadUnaligned>(ref Unsafe.As(ref values[index])); + } + + internal unsafe Vector(void* dataPointer) + { + ThrowHelper.ThrowForUnsupportedVectorBaseType(); + this = Unsafe.ReadUnaligned>(dataPointer); + } + + private Vector(ref Register existingRegister) + { + this.register = existingRegister; + } + + /// + /// Constructs a vector from the given . The span must contain at least elements. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector(ReadOnlySpan values) + { + ThrowHelper.ThrowForUnsupportedVectorBaseType(); + if (values.Length < Vector.Count) + { + Vector.ThrowInsufficientNumberOfElementsException(Vector.Count); + } + this = Unsafe.ReadUnaligned>(ref MemoryMarshal.GetReference(values)); + } + + /// + /// Constructs a vector from the given . The span must contain at least elements. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector(ReadOnlySpan values) + { + if (values.Length < Count) + { + Vector.ThrowInsufficientNumberOfElementsException(Vector.Count); + } + this = Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); + } + + /// + /// Constructs a vector from the given . The span must contain at least elements. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector(Span values) + { + if (values.Length < Count) + { + Vector.ThrowInsufficientNumberOfElementsException(Vector.Count); + } + this = Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); + } + #endregion Constructors + + #region Public Instance Methods + /// + /// Copies the vector to the given . The destination span must be at least size . + /// + /// The destination span which the values are copied into + /// If number of elements in source vector is greater than those available in destination span + public readonly void CopyTo(Span destination) + { + ThrowHelper.ThrowForUnsupportedVectorBaseType(); + if ((uint)destination.Length < (uint)Vector.Count) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + + Unsafe.WriteUnaligned>(ref MemoryMarshal.GetReference(destination), this); + } + + /// + /// Copies the vector to the given . The destination span must be at least size . + /// + /// The destination span which the values are copied into + /// If number of elements in source vector is greater than those available in destination span + public readonly void CopyTo(Span destination) + { + if ((uint)destination.Length < (uint)Count) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + + Unsafe.WriteUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(destination)), this); + } + + /// + /// Copies the vector to the given destination array. The destination array must be at least size Vector'T.Count. + /// + /// The destination array which the values are copied into + /// If the destination array is null + /// If number of elements in source vector is greater than those available in destination array + [Intrinsic] + public readonly void CopyTo(T[] destination) + { + CopyTo(destination, 0); + } + + /// + /// Copies the vector to the given destination array. The destination array must be at least size Vector'T.Count. + /// + /// The destination array which the values are copied into + /// The index to start copying to + /// If the destination array is null + /// If index is greater than end of the array or index is less than zero + /// If number of elements in source vector is greater than those available in destination array + [Intrinsic] + public readonly unsafe void CopyTo(T[] destination, int startIndex) + { + if (destination == null) + { + // Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull. + throw new NullReferenceException(SR.Arg_NullArgumentNullRef); + } + if ((uint)startIndex >= (uint)destination.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex), SR.Format(SR.Arg_ArgumentOutOfRangeException, startIndex)); + } + if ((destination.Length - startIndex) < Count) + { + throw new ArgumentException(SR.Format(SR.Arg_ElementsInSourceIsGreaterThanDestination, startIndex)); + } + + Unsafe.WriteUnaligned>(ref Unsafe.As(ref destination[startIndex]), this); + } + + /// + /// Returns the element at the given index. + /// + public readonly unsafe T this[int index] + { + [Intrinsic] + get + { + if ((uint)index >= (uint)Count) + { + throw new IndexOutOfRangeException(SR.Format(SR.Arg_ArgumentOutOfRangeException, index)); + } + + return Unsafe.Add(ref Unsafe.As, T>(ref Unsafe.AsRef>(in this)), index); + } + } + + /// + /// Returns a boolean indicating whether the given Object is equal to this vector instance. + /// + /// The Object to compare against. + /// True if the Object is equal to this vector; False otherwise. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public override readonly bool Equals(object? obj) + { + if (!(obj is Vector)) + { + return false; } + return Equals((Vector)obj); + } + /// + /// Returns a boolean indicating whether the given vector is equal to this vector instance. + /// + /// The vector to compare this instance to. + /// True if the other vector is equal to this instance; False otherwise. + [Intrinsic] + public readonly bool Equals(Vector other) + { if (Vector.IsHardwareAccelerated) { - if (typeof(T) == typeof(byte)) + for (int g = 0; g < Count; g++) { - fixed (byte* basePtr = &this.register.byte_0) + if (!ScalarEquals(this[g], other[g])) { - for (int g = 0; g < Count; g++) - { - *(basePtr + g) = (byte)(object)values[g + index]; - } + return false; } } + return true; + } + else + { + if (typeof(T) == typeof(byte)) + { + return + this.register.byte_0 == other.register.byte_0 + && this.register.byte_1 == other.register.byte_1 + && this.register.byte_2 == other.register.byte_2 + && this.register.byte_3 == other.register.byte_3 + && this.register.byte_4 == other.register.byte_4 + && this.register.byte_5 == other.register.byte_5 + && this.register.byte_6 == other.register.byte_6 + && this.register.byte_7 == other.register.byte_7 + && this.register.byte_8 == other.register.byte_8 + && this.register.byte_9 == other.register.byte_9 + && this.register.byte_10 == other.register.byte_10 + && this.register.byte_11 == other.register.byte_11 + && this.register.byte_12 == other.register.byte_12 + && this.register.byte_13 == other.register.byte_13 + && this.register.byte_14 == other.register.byte_14 + && this.register.byte_15 == other.register.byte_15; + } else if (typeof(T) == typeof(sbyte)) { - fixed (sbyte* basePtr = &this.register.sbyte_0) - { - for (int g = 0; g < Count; g++) - { - *(basePtr + g) = (sbyte)(object)values[g + index]; - } - } + return + this.register.sbyte_0 == other.register.sbyte_0 + && this.register.sbyte_1 == other.register.sbyte_1 + && this.register.sbyte_2 == other.register.sbyte_2 + && this.register.sbyte_3 == other.register.sbyte_3 + && this.register.sbyte_4 == other.register.sbyte_4 + && this.register.sbyte_5 == other.register.sbyte_5 + && this.register.sbyte_6 == other.register.sbyte_6 + && this.register.sbyte_7 == other.register.sbyte_7 + && this.register.sbyte_8 == other.register.sbyte_8 + && this.register.sbyte_9 == other.register.sbyte_9 + && this.register.sbyte_10 == other.register.sbyte_10 + && this.register.sbyte_11 == other.register.sbyte_11 + && this.register.sbyte_12 == other.register.sbyte_12 + && this.register.sbyte_13 == other.register.sbyte_13 + && this.register.sbyte_14 == other.register.sbyte_14 + && this.register.sbyte_15 == other.register.sbyte_15; } else if (typeof(T) == typeof(ushort)) { - fixed (ushort* basePtr = &this.register.uint16_0) - { - for (int g = 0; g < Count; g++) - { - *(basePtr + g) = (ushort)(object)values[g + index]; - } - } - } - else if (typeof(T) == typeof(short)) - { - fixed (short* basePtr = &this.register.int16_0) - { - for (int g = 0; g < Count; g++) - { - *(basePtr + g) = (short)(object)values[g + index]; - } - } - } - else if (typeof(T) == typeof(uint)) - { - fixed (uint* basePtr = &this.register.uint32_0) - { - for (int g = 0; g < Count; g++) - { - *(basePtr + g) = (uint)(object)values[g + index]; - } - } - } - else if (typeof(T) == typeof(int)) - { - fixed (int* basePtr = &this.register.int32_0) - { - for (int g = 0; g < Count; g++) - { - *(basePtr + g) = (int)(object)values[g + index]; - } - } - } - else if (typeof(T) == typeof(ulong)) - { - fixed (ulong* basePtr = &this.register.uint64_0) - { - for (int g = 0; g < Count; g++) - { - *(basePtr + g) = (ulong)(object)values[g + index]; - } - } - } - else if (typeof(T) == typeof(long)) - { - fixed (long* basePtr = &this.register.int64_0) - { - for (int g = 0; g < Count; g++) - { - *(basePtr + g) = (long)(object)values[g + index]; - } - } - } - else if (typeof(T) == typeof(float)) - { - fixed (float* basePtr = &this.register.single_0) - { - for (int g = 0; g < Count; g++) - { - *(basePtr + g) = (float)(object)values[g + index]; - } - } - } - else if (typeof(T) == typeof(double)) - { - fixed (double* basePtr = &this.register.double_0) - { - for (int g = 0; g < Count; g++) - { - *(basePtr + g) = (double)(object)values[g + index]; - } - } - } - } - else - { - if (typeof(T) == typeof(byte)) - { - fixed (byte* basePtr = &this.register.byte_0) - { - *(basePtr + 0) = (byte)(object)values[0 + index]; - *(basePtr + 1) = (byte)(object)values[1 + index]; - *(basePtr + 2) = (byte)(object)values[2 + index]; - *(basePtr + 3) = (byte)(object)values[3 + index]; - *(basePtr + 4) = (byte)(object)values[4 + index]; - *(basePtr + 5) = (byte)(object)values[5 + index]; - *(basePtr + 6) = (byte)(object)values[6 + index]; - *(basePtr + 7) = (byte)(object)values[7 + index]; - *(basePtr + 8) = (byte)(object)values[8 + index]; - *(basePtr + 9) = (byte)(object)values[9 + index]; - *(basePtr + 10) = (byte)(object)values[10 + index]; - *(basePtr + 11) = (byte)(object)values[11 + index]; - *(basePtr + 12) = (byte)(object)values[12 + index]; - *(basePtr + 13) = (byte)(object)values[13 + index]; - *(basePtr + 14) = (byte)(object)values[14 + index]; - *(basePtr + 15) = (byte)(object)values[15 + index]; - } - } - else if (typeof(T) == typeof(sbyte)) - { - fixed (sbyte* basePtr = &this.register.sbyte_0) - { - *(basePtr + 0) = (sbyte)(object)values[0 + index]; - *(basePtr + 1) = (sbyte)(object)values[1 + index]; - *(basePtr + 2) = (sbyte)(object)values[2 + index]; - *(basePtr + 3) = (sbyte)(object)values[3 + index]; - *(basePtr + 4) = (sbyte)(object)values[4 + index]; - *(basePtr + 5) = (sbyte)(object)values[5 + index]; - *(basePtr + 6) = (sbyte)(object)values[6 + index]; - *(basePtr + 7) = (sbyte)(object)values[7 + index]; - *(basePtr + 8) = (sbyte)(object)values[8 + index]; - *(basePtr + 9) = (sbyte)(object)values[9 + index]; - *(basePtr + 10) = (sbyte)(object)values[10 + index]; - *(basePtr + 11) = (sbyte)(object)values[11 + index]; - *(basePtr + 12) = (sbyte)(object)values[12 + index]; - *(basePtr + 13) = (sbyte)(object)values[13 + index]; - *(basePtr + 14) = (sbyte)(object)values[14 + index]; - *(basePtr + 15) = (sbyte)(object)values[15 + index]; - } - } - else if (typeof(T) == typeof(ushort)) - { - fixed (ushort* basePtr = &this.register.uint16_0) - { - *(basePtr + 0) = (ushort)(object)values[0 + index]; - *(basePtr + 1) = (ushort)(object)values[1 + index]; - *(basePtr + 2) = (ushort)(object)values[2 + index]; - *(basePtr + 3) = (ushort)(object)values[3 + index]; - *(basePtr + 4) = (ushort)(object)values[4 + index]; - *(basePtr + 5) = (ushort)(object)values[5 + index]; - *(basePtr + 6) = (ushort)(object)values[6 + index]; - *(basePtr + 7) = (ushort)(object)values[7 + index]; - } - } - else if (typeof(T) == typeof(short)) - { - fixed (short* basePtr = &this.register.int16_0) - { - *(basePtr + 0) = (short)(object)values[0 + index]; - *(basePtr + 1) = (short)(object)values[1 + index]; - *(basePtr + 2) = (short)(object)values[2 + index]; - *(basePtr + 3) = (short)(object)values[3 + index]; - *(basePtr + 4) = (short)(object)values[4 + index]; - *(basePtr + 5) = (short)(object)values[5 + index]; - *(basePtr + 6) = (short)(object)values[6 + index]; - *(basePtr + 7) = (short)(object)values[7 + index]; - } - } - else if (typeof(T) == typeof(uint)) - { - fixed (uint* basePtr = &this.register.uint32_0) - { - *(basePtr + 0) = (uint)(object)values[0 + index]; - *(basePtr + 1) = (uint)(object)values[1 + index]; - *(basePtr + 2) = (uint)(object)values[2 + index]; - *(basePtr + 3) = (uint)(object)values[3 + index]; - } - } - else if (typeof(T) == typeof(int)) - { - fixed (int* basePtr = &this.register.int32_0) - { - *(basePtr + 0) = (int)(object)values[0 + index]; - *(basePtr + 1) = (int)(object)values[1 + index]; - *(basePtr + 2) = (int)(object)values[2 + index]; - *(basePtr + 3) = (int)(object)values[3 + index]; - } - } - else if (typeof(T) == typeof(ulong)) - { - fixed (ulong* basePtr = &this.register.uint64_0) - { - *(basePtr + 0) = (ulong)(object)values[0 + index]; - *(basePtr + 1) = (ulong)(object)values[1 + index]; - } - } - else if (typeof(T) == typeof(long)) - { - fixed (long* basePtr = &this.register.int64_0) - { - *(basePtr + 0) = (long)(object)values[0 + index]; - *(basePtr + 1) = (long)(object)values[1 + index]; - } - } - else if (typeof(T) == typeof(float)) - { - fixed (float* basePtr = &this.register.single_0) - { - *(basePtr + 0) = (float)(object)values[0 + index]; - *(basePtr + 1) = (float)(object)values[1 + index]; - *(basePtr + 2) = (float)(object)values[2 + index]; - *(basePtr + 3) = (float)(object)values[3 + index]; - } - } - else if (typeof(T) == typeof(double)) - { - fixed (double* basePtr = &this.register.double_0) - { - *(basePtr + 0) = (double)(object)values[0 + index]; - *(basePtr + 1) = (double)(object)values[1 + index]; - } - } - } - } - -#pragma warning disable 3001 // void* is not a CLS-Compliant argument type - internal unsafe Vector(void* dataPointer) : this(dataPointer, 0) { } -#pragma warning restore 3001 // void* is not a CLS-Compliant argument type - -#pragma warning disable 3001 // void* is not a CLS-Compliant argument type - // Implemented with offset if this API ever becomes public; an offset of 0 is used internally. - internal unsafe Vector(void* dataPointer, int offset) - : this() - { - if (typeof(T) == typeof(byte)) - { - byte* castedPtr = (byte*)dataPointer; - castedPtr += offset; - fixed (byte* registerBase = &this.register.byte_0) - { - for (int g = 0; g < Count; g++) - { - registerBase[g] = castedPtr[g]; - } - } - } - else if (typeof(T) == typeof(sbyte)) - { - sbyte* castedPtr = (sbyte*)dataPointer; - castedPtr += offset; - fixed (sbyte* registerBase = &this.register.sbyte_0) - { - for (int g = 0; g < Count; g++) - { - registerBase[g] = castedPtr[g]; - } - } - } - else if (typeof(T) == typeof(ushort)) - { - ushort* castedPtr = (ushort*)dataPointer; - castedPtr += offset; - fixed (ushort* registerBase = &this.register.uint16_0) - { - for (int g = 0; g < Count; g++) - { - registerBase[g] = castedPtr[g]; - } - } - } - else if (typeof(T) == typeof(short)) - { - short* castedPtr = (short*)dataPointer; - castedPtr += offset; - fixed (short* registerBase = &this.register.int16_0) - { - for (int g = 0; g < Count; g++) - { - registerBase[g] = castedPtr[g]; - } - } - } - else if (typeof(T) == typeof(uint)) - { - uint* castedPtr = (uint*)dataPointer; - castedPtr += offset; - fixed (uint* registerBase = &this.register.uint32_0) - { - for (int g = 0; g < Count; g++) - { - registerBase[g] = castedPtr[g]; - } - } - } - else if (typeof(T) == typeof(int)) - { - int* castedPtr = (int*)dataPointer; - castedPtr += offset; - fixed (int* registerBase = &this.register.int32_0) - { - for (int g = 0; g < Count; g++) - { - registerBase[g] = castedPtr[g]; - } - } - } - else if (typeof(T) == typeof(ulong)) - { - ulong* castedPtr = (ulong*)dataPointer; - castedPtr += offset; - fixed (ulong* registerBase = &this.register.uint64_0) - { - for (int g = 0; g < Count; g++) - { - registerBase[g] = castedPtr[g]; - } - } - } - else if (typeof(T) == typeof(long)) - { - long* castedPtr = (long*)dataPointer; - castedPtr += offset; - fixed (long* registerBase = &this.register.int64_0) - { - for (int g = 0; g < Count; g++) - { - registerBase[g] = castedPtr[g]; - } - } - } - else if (typeof(T) == typeof(float)) - { - float* castedPtr = (float*)dataPointer; - castedPtr += offset; - fixed (float* registerBase = &this.register.single_0) - { - for (int g = 0; g < Count; g++) - { - registerBase[g] = castedPtr[g]; - } - } - } - else if (typeof(T) == typeof(double)) - { - double* castedPtr = (double*)dataPointer; - castedPtr += offset; - fixed (double* registerBase = &this.register.double_0) - { - for (int g = 0; g < Count; g++) - { - registerBase[g] = castedPtr[g]; - } - } - } - else - { - throw new NotSupportedException(SR.Arg_TypeNotSupported); - } - } -#pragma warning restore 3001 // void* is not a CLS-Compliant argument type - - private Vector(ref Register existingRegister) - { - this.register = existingRegister; - } - -#if netcoreapp - /// - /// Constructs a vector from the given . The span must contain at least elements. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector(ReadOnlySpan values) - : this() - { - ThrowHelper.ThrowForUnsupportedVectorBaseType(); - if (values.Length < Vector.Count) - { - Vector.ThrowInsufficientNumberOfElementsException(Vector.Count); - } - this = Unsafe.ReadUnaligned>(ref MemoryMarshal.GetReference(values)); - } - - /// - /// Constructs a vector from the given . The span must contain at least elements. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector(ReadOnlySpan values) - : this() - { - if (values.Length < Count) - { - Vector.ThrowInsufficientNumberOfElementsException(Vector.Count); - } - this = Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); - } - - /// - /// Constructs a vector from the given . The span must contain at least elements. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector(Span values) - : this() - { - if (values.Length < Count) - { - Vector.ThrowInsufficientNumberOfElementsException(Vector.Count); - } - this = Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); - } -#endif - #endregion Constructors - - #region Public Instance Methods - /// - /// Copies the vector to the given . The destination span must be at least size . - /// - /// The destination span which the values are copied into - /// If number of elements in source vector is greater than those available in destination span - public readonly void CopyTo(Span destination) - { - ThrowHelper.ThrowForUnsupportedVectorBaseType(); - if ((uint)destination.Length < (uint)Vector.Count) - { - ThrowHelper.ThrowArgumentException_DestinationTooShort(); - } - Unsafe.WriteUnaligned>(ref MemoryMarshal.GetReference(destination), this); - } - - /// - /// Copies the vector to the given . The destination span must be at least size . - /// - /// The destination span which the values are copied into - /// If number of elements in source vector is greater than those available in destination span - public readonly void CopyTo(Span destination) - { - if ((uint)destination.Length < (uint)Count) - { - ThrowHelper.ThrowArgumentException_DestinationTooShort(); - } - - Unsafe.WriteUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(destination)), this); - } - - /// - /// Copies the vector to the given destination array. The destination array must be at least size Vector'T.Count. - /// - /// The destination array which the values are copied into - /// If the destination array is null - /// If number of elements in source vector is greater than those available in destination array - [Intrinsic] - public readonly unsafe void CopyTo(T[] destination) - { - CopyTo(destination, 0); - } - - /// - /// Copies the vector to the given destination array. The destination array must be at least size Vector'T.Count. - /// - /// The destination array which the values are copied into - /// The index to start copying to - /// If the destination array is null - /// If index is greater than end of the array or index is less than zero - /// If number of elements in source vector is greater than those available in destination array - [Intrinsic] - public readonly unsafe void CopyTo(T[] destination, int startIndex) - { - if (destination == null) - { - // Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull. - throw new NullReferenceException(SR.Arg_NullArgumentNullRef); - } - if (startIndex < 0 || startIndex >= destination.Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.Format(SR.Arg_ArgumentOutOfRangeException, startIndex)); - } - if ((destination.Length - startIndex) < Count) - { - throw new ArgumentException(SR.Format(SR.Arg_ElementsInSourceIsGreaterThanDestination, startIndex)); - } - - if (Vector.IsHardwareAccelerated) - { - if (typeof(T) == typeof(byte)) - { - byte[] byteArray = (byte[])(object)destination; - fixed (byte* destinationBase = byteArray) - { - for (int g = 0; g < Count; g++) - { - destinationBase[startIndex + g] = (byte)(object)this[g]; - } - } - } - else if (typeof(T) == typeof(sbyte)) - { - sbyte[] sbyteArray = (sbyte[])(object)destination; - fixed (sbyte* destinationBase = sbyteArray) - { - for (int g = 0; g < Count; g++) - { - destinationBase[startIndex + g] = (sbyte)(object)this[g]; - } - } - } - else if (typeof(T) == typeof(ushort)) - { - ushort[] uint16Array = (ushort[])(object)destination; - fixed (ushort* destinationBase = uint16Array) - { - for (int g = 0; g < Count; g++) - { - destinationBase[startIndex + g] = (ushort)(object)this[g]; - } - } - } - else if (typeof(T) == typeof(short)) - { - short[] int16Array = (short[])(object)destination; - fixed (short* destinationBase = int16Array) - { - for (int g = 0; g < Count; g++) - { - destinationBase[startIndex + g] = (short)(object)this[g]; - } - } - } - else if (typeof(T) == typeof(uint)) - { - uint[] uint32Array = (uint[])(object)destination; - fixed (uint* destinationBase = uint32Array) - { - for (int g = 0; g < Count; g++) - { - destinationBase[startIndex + g] = (uint)(object)this[g]; - } - } - } - else if (typeof(T) == typeof(int)) - { - int[] int32Array = (int[])(object)destination; - fixed (int* destinationBase = int32Array) - { - for (int g = 0; g < Count; g++) - { - destinationBase[startIndex + g] = (int)(object)this[g]; - } - } - } - else if (typeof(T) == typeof(ulong)) - { - ulong[] uint64Array = (ulong[])(object)destination; - fixed (ulong* destinationBase = uint64Array) - { - for (int g = 0; g < Count; g++) - { - destinationBase[startIndex + g] = (ulong)(object)this[g]; - } - } - } - else if (typeof(T) == typeof(long)) - { - long[] int64Array = (long[])(object)destination; - fixed (long* destinationBase = int64Array) - { - for (int g = 0; g < Count; g++) - { - destinationBase[startIndex + g] = (long)(object)this[g]; - } - } - } - else if (typeof(T) == typeof(float)) - { - float[] singleArray = (float[])(object)destination; - fixed (float* destinationBase = singleArray) - { - for (int g = 0; g < Count; g++) - { - destinationBase[startIndex + g] = (float)(object)this[g]; - } - } - } - else if (typeof(T) == typeof(double)) - { - double[] doubleArray = (double[])(object)destination; - fixed (double* destinationBase = doubleArray) - { - for (int g = 0; g < Count; g++) - { - destinationBase[startIndex + g] = (double)(object)this[g]; - } - } - } - } - else - { - if (typeof(T) == typeof(byte)) - { - byte[] byteArray = (byte[])(object)destination; - fixed (byte* destinationBase = byteArray) - { - destinationBase[startIndex + 0] = this.register.byte_0; - destinationBase[startIndex + 1] = this.register.byte_1; - destinationBase[startIndex + 2] = this.register.byte_2; - destinationBase[startIndex + 3] = this.register.byte_3; - destinationBase[startIndex + 4] = this.register.byte_4; - destinationBase[startIndex + 5] = this.register.byte_5; - destinationBase[startIndex + 6] = this.register.byte_6; - destinationBase[startIndex + 7] = this.register.byte_7; - destinationBase[startIndex + 8] = this.register.byte_8; - destinationBase[startIndex + 9] = this.register.byte_9; - destinationBase[startIndex + 10] = this.register.byte_10; - destinationBase[startIndex + 11] = this.register.byte_11; - destinationBase[startIndex + 12] = this.register.byte_12; - destinationBase[startIndex + 13] = this.register.byte_13; - destinationBase[startIndex + 14] = this.register.byte_14; - destinationBase[startIndex + 15] = this.register.byte_15; - } - } - else if (typeof(T) == typeof(sbyte)) - { - sbyte[] sbyteArray = (sbyte[])(object)destination; - fixed (sbyte* destinationBase = sbyteArray) - { - destinationBase[startIndex + 0] = this.register.sbyte_0; - destinationBase[startIndex + 1] = this.register.sbyte_1; - destinationBase[startIndex + 2] = this.register.sbyte_2; - destinationBase[startIndex + 3] = this.register.sbyte_3; - destinationBase[startIndex + 4] = this.register.sbyte_4; - destinationBase[startIndex + 5] = this.register.sbyte_5; - destinationBase[startIndex + 6] = this.register.sbyte_6; - destinationBase[startIndex + 7] = this.register.sbyte_7; - destinationBase[startIndex + 8] = this.register.sbyte_8; - destinationBase[startIndex + 9] = this.register.sbyte_9; - destinationBase[startIndex + 10] = this.register.sbyte_10; - destinationBase[startIndex + 11] = this.register.sbyte_11; - destinationBase[startIndex + 12] = this.register.sbyte_12; - destinationBase[startIndex + 13] = this.register.sbyte_13; - destinationBase[startIndex + 14] = this.register.sbyte_14; - destinationBase[startIndex + 15] = this.register.sbyte_15; - } - } - else if (typeof(T) == typeof(ushort)) - { - ushort[] uint16Array = (ushort[])(object)destination; - fixed (ushort* destinationBase = uint16Array) - { - destinationBase[startIndex + 0] = this.register.uint16_0; - destinationBase[startIndex + 1] = this.register.uint16_1; - destinationBase[startIndex + 2] = this.register.uint16_2; - destinationBase[startIndex + 3] = this.register.uint16_3; - destinationBase[startIndex + 4] = this.register.uint16_4; - destinationBase[startIndex + 5] = this.register.uint16_5; - destinationBase[startIndex + 6] = this.register.uint16_6; - destinationBase[startIndex + 7] = this.register.uint16_7; - } - } - else if (typeof(T) == typeof(short)) - { - short[] int16Array = (short[])(object)destination; - fixed (short* destinationBase = int16Array) - { - destinationBase[startIndex + 0] = this.register.int16_0; - destinationBase[startIndex + 1] = this.register.int16_1; - destinationBase[startIndex + 2] = this.register.int16_2; - destinationBase[startIndex + 3] = this.register.int16_3; - destinationBase[startIndex + 4] = this.register.int16_4; - destinationBase[startIndex + 5] = this.register.int16_5; - destinationBase[startIndex + 6] = this.register.int16_6; - destinationBase[startIndex + 7] = this.register.int16_7; - } - } - else if (typeof(T) == typeof(uint)) - { - uint[] uint32Array = (uint[])(object)destination; - fixed (uint* destinationBase = uint32Array) - { - destinationBase[startIndex + 0] = this.register.uint32_0; - destinationBase[startIndex + 1] = this.register.uint32_1; - destinationBase[startIndex + 2] = this.register.uint32_2; - destinationBase[startIndex + 3] = this.register.uint32_3; - } - } - else if (typeof(T) == typeof(int)) - { - int[] int32Array = (int[])(object)destination; - fixed (int* destinationBase = int32Array) - { - destinationBase[startIndex + 0] = this.register.int32_0; - destinationBase[startIndex + 1] = this.register.int32_1; - destinationBase[startIndex + 2] = this.register.int32_2; - destinationBase[startIndex + 3] = this.register.int32_3; - } - } - else if (typeof(T) == typeof(ulong)) - { - ulong[] uint64Array = (ulong[])(object)destination; - fixed (ulong* destinationBase = uint64Array) - { - destinationBase[startIndex + 0] = this.register.uint64_0; - destinationBase[startIndex + 1] = this.register.uint64_1; - } - } - else if (typeof(T) == typeof(long)) - { - long[] int64Array = (long[])(object)destination; - fixed (long* destinationBase = int64Array) - { - destinationBase[startIndex + 0] = this.register.int64_0; - destinationBase[startIndex + 1] = this.register.int64_1; - } - } - else if (typeof(T) == typeof(float)) - { - float[] singleArray = (float[])(object)destination; - fixed (float* destinationBase = singleArray) - { - destinationBase[startIndex + 0] = this.register.single_0; - destinationBase[startIndex + 1] = this.register.single_1; - destinationBase[startIndex + 2] = this.register.single_2; - destinationBase[startIndex + 3] = this.register.single_3; - } - } - else if (typeof(T) == typeof(double)) - { - double[] doubleArray = (double[])(object)destination; - fixed (double* destinationBase = doubleArray) - { - destinationBase[startIndex + 0] = this.register.double_0; - destinationBase[startIndex + 1] = this.register.double_1; - } - } - } - } - - /// - /// Returns the element at the given index. - /// - public readonly unsafe T this[int index] - { - [Intrinsic] - get - { - if (index >= Count || index < 0) - { - throw new IndexOutOfRangeException(SR.Format(SR.Arg_ArgumentOutOfRangeException, index)); - } - if (typeof(T) == typeof(byte)) - { - fixed (byte* basePtr = &this.register.byte_0) - { - return (T)(object)*(basePtr + index); - } - } - else if (typeof(T) == typeof(sbyte)) - { - fixed (sbyte* basePtr = &this.register.sbyte_0) - { - return (T)(object)*(basePtr + index); - } - } - else if (typeof(T) == typeof(ushort)) - { - fixed (ushort* basePtr = &this.register.uint16_0) - { - return (T)(object)*(basePtr + index); - } - } - else if (typeof(T) == typeof(short)) - { - fixed (short* basePtr = &this.register.int16_0) - { - return (T)(object)*(basePtr + index); - } - } - else if (typeof(T) == typeof(uint)) - { - fixed (uint* basePtr = &this.register.uint32_0) - { - return (T)(object)*(basePtr + index); - } - } - else if (typeof(T) == typeof(int)) - { - fixed (int* basePtr = &this.register.int32_0) - { - return (T)(object)*(basePtr + index); - } - } - else if (typeof(T) == typeof(ulong)) - { - fixed (ulong* basePtr = &this.register.uint64_0) - { - return (T)(object)*(basePtr + index); - } - } - else if (typeof(T) == typeof(long)) - { - fixed (long* basePtr = &this.register.int64_0) - { - return (T)(object)*(basePtr + index); - } - } - else if (typeof(T) == typeof(float)) - { - fixed (float* basePtr = &this.register.single_0) - { - return (T)(object)*(basePtr + index); - } - } - else if (typeof(T) == typeof(double)) - { - fixed (double* basePtr = &this.register.double_0) - { - return (T)(object)*(basePtr + index); - } - } - else - { - throw new NotSupportedException(SR.Arg_TypeNotSupported); - } - } - } - - /// - /// Returns a boolean indicating whether the given Object is equal to this vector instance. - /// - /// The Object to compare against. - /// True if the Object is equal to this vector; False otherwise. - [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] - public override readonly bool Equals(object? obj) - { - if (!(obj is Vector)) - { - return false; - } - return Equals((Vector)obj); - } - - /// - /// Returns a boolean indicating whether the given vector is equal to this vector instance. - /// - /// The vector to compare this instance to. - /// True if the other vector is equal to this instance; False otherwise. - [Intrinsic] - public readonly bool Equals(Vector other) - { - if (Vector.IsHardwareAccelerated) - { - for (int g = 0; g < Count; g++) - { - if (!ScalarEquals(this[g], other[g])) - { - return false; - } - } - return true; - } - else - { - if (typeof(T) == typeof(byte)) - { - return - this.register.byte_0 == other.register.byte_0 - && this.register.byte_1 == other.register.byte_1 - && this.register.byte_2 == other.register.byte_2 - && this.register.byte_3 == other.register.byte_3 - && this.register.byte_4 == other.register.byte_4 - && this.register.byte_5 == other.register.byte_5 - && this.register.byte_6 == other.register.byte_6 - && this.register.byte_7 == other.register.byte_7 - && this.register.byte_8 == other.register.byte_8 - && this.register.byte_9 == other.register.byte_9 - && this.register.byte_10 == other.register.byte_10 - && this.register.byte_11 == other.register.byte_11 - && this.register.byte_12 == other.register.byte_12 - && this.register.byte_13 == other.register.byte_13 - && this.register.byte_14 == other.register.byte_14 - && this.register.byte_15 == other.register.byte_15; - } - else if (typeof(T) == typeof(sbyte)) - { - return - this.register.sbyte_0 == other.register.sbyte_0 - && this.register.sbyte_1 == other.register.sbyte_1 - && this.register.sbyte_2 == other.register.sbyte_2 - && this.register.sbyte_3 == other.register.sbyte_3 - && this.register.sbyte_4 == other.register.sbyte_4 - && this.register.sbyte_5 == other.register.sbyte_5 - && this.register.sbyte_6 == other.register.sbyte_6 - && this.register.sbyte_7 == other.register.sbyte_7 - && this.register.sbyte_8 == other.register.sbyte_8 - && this.register.sbyte_9 == other.register.sbyte_9 - && this.register.sbyte_10 == other.register.sbyte_10 - && this.register.sbyte_11 == other.register.sbyte_11 - && this.register.sbyte_12 == other.register.sbyte_12 - && this.register.sbyte_13 == other.register.sbyte_13 - && this.register.sbyte_14 == other.register.sbyte_14 - && this.register.sbyte_15 == other.register.sbyte_15; - } - else if (typeof(T) == typeof(ushort)) - { - return - this.register.uint16_0 == other.register.uint16_0 - && this.register.uint16_1 == other.register.uint16_1 - && this.register.uint16_2 == other.register.uint16_2 - && this.register.uint16_3 == other.register.uint16_3 - && this.register.uint16_4 == other.register.uint16_4 - && this.register.uint16_5 == other.register.uint16_5 - && this.register.uint16_6 == other.register.uint16_6 - && this.register.uint16_7 == other.register.uint16_7; + return + this.register.uint16_0 == other.register.uint16_0 + && this.register.uint16_1 == other.register.uint16_1 + && this.register.uint16_2 == other.register.uint16_2 + && this.register.uint16_3 == other.register.uint16_3 + && this.register.uint16_4 == other.register.uint16_4 + && this.register.uint16_5 == other.register.uint16_5 + && this.register.uint16_6 == other.register.uint16_6 + && this.register.uint16_7 == other.register.uint16_7; } else if (typeof(T) == typeof(short)) { @@ -1315,135 +630,42 @@ namespace System.Numerics /// The hash code. public override readonly int GetHashCode() { - int hash = 0; + HashCode hashCode = new HashCode(); - if (Vector.IsHardwareAccelerated) + if (typeof(T) == typeof(byte) || + typeof(T) == typeof(sbyte) || + typeof(T) == typeof(ushort) || + typeof(T) == typeof(short) || + typeof(T) == typeof(int) || + typeof(T) == typeof(uint) || + typeof(T) == typeof(long) || + typeof(T) == typeof(ulong)) { - if (typeof(T) == typeof(byte)) - { - for (int g = 0; g < Count; g++) - { - hash = HashCode.Combine(hash, ((byte)(object)this[g]).GetHashCode()); - } - return hash; - } - else if (typeof(T) == typeof(sbyte)) - { - for (int g = 0; g < Count; g++) - { - hash = HashCode.Combine(hash, ((sbyte)(object)this[g]).GetHashCode()); - } - return hash; - } - else if (typeof(T) == typeof(ushort)) - { - for (int g = 0; g < Count; g++) - { - hash = HashCode.Combine(hash, ((ushort)(object)this[g]).GetHashCode()); - } - return hash; - } - else if (typeof(T) == typeof(short)) - { - for (int g = 0; g < Count; g++) - { - hash = HashCode.Combine(hash, ((short)(object)this[g]).GetHashCode()); - } - return hash; - } - else if (typeof(T) == typeof(uint)) - { - for (int g = 0; g < Count; g++) - { - hash = HashCode.Combine(hash, ((uint)(object)this[g]).GetHashCode()); - } - return hash; - } - else if (typeof(T) == typeof(int)) - { - for (int g = 0; g < Count; g++) - { - hash = HashCode.Combine(hash, ((int)(object)this[g]).GetHashCode()); - } - return hash; - } - else if (typeof(T) == typeof(ulong)) - { - for (int g = 0; g < Count; g++) - { - hash = HashCode.Combine(hash, ((ulong)(object)this[g]).GetHashCode()); - } - return hash; - } - else if (typeof(T) == typeof(long)) - { - for (int g = 0; g < Count; g++) - { - hash = HashCode.Combine(hash, ((long)(object)this[g]).GetHashCode()); - } - return hash; - } - else if (typeof(T) == typeof(float)) + for (nint g = 0; g < Vector.Count; g++) { - for (int g = 0; g < Count; g++) - { - hash = HashCode.Combine(hash, ((float)(object)this[g]).GetHashCode()); - } - return hash; + hashCode.Add(Unsafe.Add(ref Unsafe.As, int>(ref Unsafe.AsRef>(in this)), (IntPtr)g)); } - else if (typeof(T) == typeof(double)) + } + else if (typeof(T) == typeof(float)) + { + for (nint g = 0; g < Count; g++) { - for (int g = 0; g < Count; g++) - { - hash = HashCode.Combine(hash, ((double)(object)this[g]).GetHashCode()); - } - return hash; + hashCode.Add(Unsafe.Add(ref Unsafe.As, float>(ref Unsafe.AsRef>(in this)), (IntPtr)g)); } - else + } + else if (typeof(T) == typeof(double)) + { + for (nint g = 0; g < Count; g++) { - throw new NotSupportedException(SR.Arg_TypeNotSupported); + hashCode.Add(Unsafe.Add(ref Unsafe.As, double>(ref Unsafe.AsRef>(in this)), (IntPtr)g)); } } else { - if (typeof(T) == typeof(byte) || - typeof(T) == typeof(sbyte) || - typeof(T) == typeof(ushort) || - typeof(T) == typeof(short) || - typeof(T) == typeof(int) || - typeof(T) == typeof(uint)) - { - return HashCode.Combine( - this.register.int32_0.GetHashCode(), - this.register.int32_1.GetHashCode(), - this.register.int32_2.GetHashCode(), - this.register.int32_3.GetHashCode()); - } - else if (typeof(T) == typeof(long) || typeof(T) == typeof(ulong)) - { - return HashCode.Combine( - this.register.int64_0.GetHashCode(), - this.register.int64_1.GetHashCode()); - } - else if (typeof(T) == typeof(float)) - { - hash = HashCode.Combine(hash, this.register.single_0.GetHashCode()); - hash = HashCode.Combine(hash, this.register.single_1.GetHashCode()); - hash = HashCode.Combine(hash, this.register.single_2.GetHashCode()); - hash = HashCode.Combine(hash, this.register.single_3.GetHashCode()); - return hash; - } - else if (typeof(T) == typeof(double)) - { - hash = HashCode.Combine(hash, this.register.double_0.GetHashCode()); - hash = HashCode.Combine(hash, this.register.double_1.GetHashCode()); - return hash; - } - else - { - throw new NotSupportedException(SR.Arg_TypeNotSupported); - } + throw new NotSupportedException(SR.Arg_TypeNotSupported); } + + return hashCode.ToHashCode(); } /// diff --git a/netcore/System.Private.CoreLib/shared/System/Numerics/Vector.tt b/netcore/System.Private.CoreLib/shared/System/Numerics/Vector.tt index ed2b606e556..3d75adbfe3f 100644 --- a/netcore/System.Private.CoreLib/shared/System/Numerics/Vector.tt +++ b/netcore/System.Private.CoreLib/shared/System/Numerics/Vector.tt @@ -7,16 +7,21 @@ <#@ import namespace="System.Runtime.InteropServices" #> <#@ include file="GenerationConfig.ttinclude" #><# GenerateCopyrightHeader(); #> -#nullable enable -#if netcoreapp -using Internal.Runtime.CompilerServices; -#endif +using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.Numerics.Hashing; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; +using Internal.Runtime.CompilerServices; + +#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types +#if BIT64 +using nint = System.Int64; +#else +using nint = System.Int32; +#endif + namespace System.Numerics { /* Note: The following patterns are used throughout the code here and are described here @@ -75,10 +80,7 @@ namespace System.Numerics public static Vector Zero { [Intrinsic] - get - { - return s_zero; - } + get => s_zero; } private static readonly Vector s_zero = new Vector(); @@ -88,20 +90,14 @@ namespace System.Numerics public static Vector One { [Intrinsic] - get - { - return s_one; - } + get => s_one; } private static readonly Vector s_one = new Vector(GetOneValue()); internal static Vector AllOnes { [Intrinsic] - get - { - return s_allOnes; - } + get => s_allOnes; } private static readonly Vector s_allOnes = new Vector(GetAllBitsSetValue()); #endregion Static Members @@ -124,7 +120,7 @@ namespace System.Numerics { fixed (<#=typeAliases[type]#>* basePtr = &this.<#=GetRegisterFieldName(type, 0)#>) { - for (int g = 0; g < Count; g++) + for (nint g = 0; g < Count; g++) { *(basePtr + g) = (<#=typeAliases[type]#>)(object)value; } @@ -169,7 +165,6 @@ namespace System.Numerics /// [Intrinsic] public unsafe Vector(T[] values, int index) - : this() { if (values == null) { @@ -178,102 +173,27 @@ namespace System.Numerics } if (index < 0 || (values.Length - index) < Count) { - throw new IndexOutOfRangeException(SR.Format(SR.Arg_InsufficientNumberOfElements, Vector.Count, nameof(values))); - } - - if (Vector.IsHardwareAccelerated) - { -<# - foreach (Type type in supportedTypes) - { -#> - <#=GenerateIfStatementHeader(type)#> - { - fixed (<#=typeAliases[type]#>* basePtr = &this.<#=GetRegisterFieldName(type, 0)#>) - { - for (int g = 0; g < Count; g++) - { - *(basePtr + g) = (<#=typeAliases[type]#>)(object)values[g + index]; - } - } - } -<# - } -#> - } - else - { -<# - foreach (Type type in supportedTypes) - { -#> - <#=GenerateIfStatementHeader(type)#> - { - fixed (<#=typeAliases[type]#>* basePtr = &this.<#=GetRegisterFieldName(type, 0)#>) - { -<# - for (int g = 0; g < GetNumFields(type, totalSize); g++) - { -#> - *(basePtr + <#=g#>) = (<#=typeAliases[type]#>)(object)values[<#=g#> + index]; -<# - } -#> - } - } -<# - } -#> + Vector.ThrowInsufficientNumberOfElementsException(Vector.Count); } + this = Unsafe.ReadUnaligned>(ref Unsafe.As(ref values[index])); } -#pragma warning disable 3001 // void* is not a CLS-Compliant argument type - internal unsafe Vector(void* dataPointer) : this(dataPointer, 0) { } -#pragma warning restore 3001 // void* is not a CLS-Compliant argument type - -#pragma warning disable 3001 // void* is not a CLS-Compliant argument type - // Implemented with offset if this API ever becomes public; an offset of 0 is used internally. - internal unsafe Vector(void* dataPointer, int offset) - : this() + internal unsafe Vector(void* dataPointer) { -<# - foreach (Type type in supportedTypes) - { -#> - <#=GenerateIfStatementHeader(type)#> - { - <#=typeAliases[type]#>* castedPtr = (<#=typeAliases[type]#>*)dataPointer; - castedPtr += offset; - fixed (<#=typeAliases[type]#>* registerBase = &this.<#=GetRegisterFieldName(type, 0)#>) - { - for (int g = 0; g < Count; g++) - { - registerBase[g] = castedPtr[g]; - } - } - } -<# - } -#> - else - { - throw new NotSupportedException(SR.Arg_TypeNotSupported); - } + ThrowHelper.ThrowForUnsupportedVectorBaseType(); + this = Unsafe.ReadUnaligned>(dataPointer); } -#pragma warning restore 3001 // void* is not a CLS-Compliant argument type private Vector(ref Register existingRegister) { this.register = existingRegister; } -#if netcoreapp /// /// Constructs a vector from the given . The span must contain at least elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector(ReadOnlySpan values) - : this() { ThrowHelper.ThrowForUnsupportedVectorBaseType(); if (values.Length < Vector.Count) @@ -282,13 +202,12 @@ namespace System.Numerics } this = Unsafe.ReadUnaligned>(ref MemoryMarshal.GetReference(values)); } - + /// /// Constructs a vector from the given . The span must contain at least elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector(ReadOnlySpan values) - : this() { if (values.Length < Count) { @@ -302,7 +221,6 @@ namespace System.Numerics /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector(Span values) - : this() { if (values.Length < Count) { @@ -310,7 +228,6 @@ namespace System.Numerics } this = Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); } -#endif #endregion Constructors #region Public Instance Methods @@ -326,6 +243,7 @@ namespace System.Numerics { ThrowHelper.ThrowArgumentException_DestinationTooShort(); } + Unsafe.WriteUnaligned>(ref MemoryMarshal.GetReference(destination), this); } @@ -351,7 +269,7 @@ namespace System.Numerics /// If the destination array is null /// If number of elements in source vector is greater than those available in destination array [Intrinsic] - public unsafe readonly void CopyTo(T[] destination) + public readonly void CopyTo(T[] destination) { CopyTo(destination, 0); } @@ -365,14 +283,14 @@ namespace System.Numerics /// If index is greater than end of the array or index is less than zero /// If number of elements in source vector is greater than those available in destination array [Intrinsic] - public unsafe readonly void CopyTo(T[] destination, int startIndex) + public readonly unsafe void CopyTo(T[] destination, int startIndex) { if (destination == null) { // Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull. throw new NullReferenceException(SR.Arg_NullArgumentNullRef); } - if (startIndex < 0 || startIndex >= destination.Length) + if ((uint)startIndex >= (uint)destination.Length) { throw new ArgumentOutOfRangeException(nameof(startIndex), SR.Format(SR.Arg_ArgumentOutOfRangeException, startIndex)); } @@ -381,84 +299,23 @@ namespace System.Numerics throw new ArgumentException(SR.Format(SR.Arg_ElementsInSourceIsGreaterThanDestination, startIndex)); } - if (Vector.IsHardwareAccelerated) - { -<# - foreach (Type type in supportedTypes) - { -#> - <#=GenerateIfStatementHeader(type)#> - { - <#=typeAliases[type]#>[] <#=type.Name.ToLowerInvariant()#>Array = (<#=typeAliases[type]#>[])(object)destination; - fixed (<#=typeAliases[type]#>* destinationBase = <#=type.Name.ToLowerInvariant()#>Array) - { - for (int g = 0; g < Count; g++) - { - destinationBase[startIndex + g] = (<#=typeAliases[type]#>)(object)this[g]; - } - } - } -<# - } -#> - } - else - { -<# - foreach (Type type in supportedTypes) - { -#> - <#=GenerateIfStatementHeader(type)#> - { - <#=typeAliases[type]#>[] <#=type.Name.ToLowerInvariant()#>Array = (<#=typeAliases[type]#>[])(object)destination; - fixed (<#=typeAliases[type]#>* destinationBase = <#=type.Name.ToLowerInvariant()#>Array) - { -<# - for (int g = 0; g < GetNumFields(type, totalSize); g++) - { -#> - destinationBase[startIndex + <#=g#>] = this.<#=GetRegisterFieldName(type, g)#>; -<# - } -#> - } - } -<# - } -#> - } + Unsafe.WriteUnaligned>(ref Unsafe.As(ref destination[startIndex]), this); } /// /// Returns the element at the given index. /// - public unsafe readonly T this[int index] + public readonly unsafe T this[int index] { [Intrinsic] get { - if (index >= Count || index < 0) + if ((uint)index >= (uint)Count) { throw new IndexOutOfRangeException(SR.Format(SR.Arg_ArgumentOutOfRangeException, index)); } -<# - foreach (Type type in supportedTypes) - { -#> - <#=GenerateIfStatementHeader(type)#> - { - fixed (<#=typeAliases[type]#>* basePtr = &this.<#=GetRegisterFieldName(type, 0)#>) - { - return (T)(object)*(basePtr + index); - } - } -<# - } -#> - else - { - throw new NotSupportedException(SR.Arg_TypeNotSupported); - } + + return Unsafe.Add(ref Unsafe.As, T>(ref Unsafe.AsRef>(in this)), index); } } @@ -543,56 +400,42 @@ namespace System.Numerics /// The hash code. public override readonly int GetHashCode() { - int hash = 0; + HashCode hashCode = new HashCode(); - if (Vector.IsHardwareAccelerated) + if (typeof(T) == typeof(byte) || + typeof(T) == typeof(sbyte) || + typeof(T) == typeof(ushort) || + typeof(T) == typeof(short) || + typeof(T) == typeof(int) || + typeof(T) == typeof(uint) || + typeof(T) == typeof(long) || + typeof(T) == typeof(ulong)) { -<# - foreach (Type type in supportedTypes) - { -#> - <#=GenerateIfStatementHeader(type)#> + for (nint g = 0; g < Vector.Count; g++) { - for (int g = 0; g < Count; g++) - { - hash = HashHelpers.Combine(hash, ((<#=typeAliases[type]#>)(object)this[g]).GetHashCode()); - } - return hash; - } -<# - } -#> - else - { - throw new NotSupportedException(SR.Arg_TypeNotSupported); + hashCode.Add(Unsafe.Add(ref Unsafe.As, int>(ref Unsafe.AsRef>(in this)), (IntPtr)g)); } } - else + else if (typeof(T) == typeof(float)) { -<# - foreach (Type type in supportedTypes) - { -#> - <#=GenerateIfStatementHeader(type)#> + for (nint g = 0; g < Count; g++) { -<# - for (int g = 0; g < GetNumFields(type, totalSize); g++) - { -#> - hash = HashHelpers.Combine(hash, this.<#=GetRegisterFieldName(type, g)#>.GetHashCode()); -<# - } -#> - return hash; + hashCode.Add(Unsafe.Add(ref Unsafe.As, float>(ref Unsafe.AsRef>(in this)), (IntPtr)g)); } -<# - } -#> - else + } + else if (typeof(T) == typeof(double)) + { + for (nint g = 0; g < Count; g++) { - throw new NotSupportedException(SR.Arg_TypeNotSupported); + hashCode.Add(Unsafe.Add(ref Unsafe.As, double>(ref Unsafe.AsRef>(in this)), (IntPtr)g)); } } + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + + return hashCode.ToHashCode(); } /// @@ -863,10 +706,8 @@ namespace System.Numerics /// The scalar value. /// The scaled vector. [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] - public static Vector operator *(Vector value, T factor) - { - return new Vector(factor) * value; - } + public static Vector operator *(Vector value, T factor) => + new Vector(factor) * value; /// /// Multiplies a vector by the given scalar. @@ -875,10 +716,8 @@ namespace System.Numerics /// The source vector. /// The scaled vector. [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] - public static Vector operator *(T factor, Vector value) - { - return new Vector(factor) * value; - } + public static Vector operator *(T factor, Vector value) => + new Vector(factor) * value; // This method is intrinsic only for certain types. It cannot access fields directly unless we are sure the context is unaccelerated. /// @@ -946,10 +785,7 @@ namespace System.Numerics /// /// The source vector. /// The negated vector. - public static Vector operator -(Vector value) - { - return Zero - value; - } + public static Vector operator -(Vector value) => Zero - value; #endregion Arithmetic Operators #region Bitwise Operators @@ -1052,10 +888,8 @@ namespace System.Numerics /// The source vector. /// The one's complement vector. [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] - public static Vector operator ~(Vector value) - { - return s_allOnes ^ value; - } + public static Vector operator ~(Vector value) => + s_allOnes ^ value; #endregion Bitwise Operators #region Logical Operators @@ -1067,10 +901,8 @@ namespace System.Numerics /// True if all elements are equal; False otherwise. [Intrinsic] [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Vector left, Vector right) - { - return left.Equals(right); - } + public static bool operator ==(Vector left, Vector right) => + left.Equals(right); /// /// Returns a boolean indicating whether any single pair of elements in the given vectors are not equal. @@ -1080,10 +912,7 @@ namespace System.Numerics /// True if left and right are not equal; False otherwise. [Intrinsic] [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Vector left, Vector right) - { - return !(left == right); - } + public static bool operator !=(Vector left, Vector right) => !(left == right); #endregion Logical Operators #region Conversions @@ -1105,10 +934,8 @@ namespace System.Numerics } #> [Intrinsic] - public static explicit operator Vector<<#=typeAliases[type]#>>(Vector value) - { - return new Vector<<#=typeAliases[type]#>>(ref value.register); - } + public static explicit operator Vector<<#=typeAliases[type]#>>(Vector value) => + new Vector<<#=typeAliases[type]#>>(ref value.register); <# } -- 2.11.4.GIT