From 211d963a42c8988770afa4d2edcbe9be0ed0b8a8 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 29 Nov 2018 12:15:43 -0800 Subject: [PATCH] Implement the Count property, the IEquatable and IFormattable interfaces, and the standard object overrides on Vector64/128/256 (#21259) * Exposing the Count property on Vector64/128/256 * Implementing IEquatable, IFormattable, and the object overrides on Vector64/128/256 * Use StringBuilderCache, HashCode, and the provided format specifier * Use StringBuilderCache.GetStringAndRelease and get the correct element when formatting Vector64/128/256 --- .../System/Runtime/Intrinsics/Vector128_1.cs | 122 ++++++++++++++++++--- .../System/Runtime/Intrinsics/Vector256_1.cs | 122 ++++++++++++++++++--- .../shared/System/Runtime/Intrinsics/Vector64_1.cs | 122 ++++++++++++++++++--- 3 files changed, 321 insertions(+), 45 deletions(-) diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector128_1.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector128_1.cs index f3599a9..da73f87 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector128_1.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector128_1.cs @@ -3,8 +3,10 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Text; using Internal.Runtime.CompilerServices; namespace System.Runtime.Intrinsics @@ -13,13 +15,25 @@ namespace System.Runtime.Intrinsics [DebuggerDisplay("{DisplayString,nq}")] [DebuggerTypeProxy(typeof(Vector128DebugView<>))] [StructLayout(LayoutKind.Sequential, Size = Vector128.Size)] - public readonly struct Vector128 where T : struct + public readonly struct Vector128 : IEquatable>, IFormattable + where T : struct { // These fields exist to ensure the alignment is 8, rather than 1. // This also allows the debug view to work https://github.com/dotnet/coreclr/issues/15694) private readonly ulong _00; private readonly ulong _01; + /// Gets the number of that are in a . + /// The type of the current instance () is not supported. + public static int Count + { + get + { + ThrowIfUnsupportedType(); + return Vector128.Size / Unsafe.SizeOf(); + } + } + /// Gets a new with all elements initialized to zero. /// The type of the current instance () is not supported. public static Vector128 Zero @@ -38,9 +52,7 @@ namespace System.Runtime.Intrinsics { if (IsSupported) { - var items = new T[ElementCount]; - Unsafe.WriteUnaligned(ref Unsafe.As(ref items[0]), this); - return $"({string.Join(", ", items)})"; + return ToString(); } else { @@ -49,15 +61,6 @@ namespace System.Runtime.Intrinsics } } - internal static int ElementCount - { - get - { - ThrowIfUnsupportedType(); - return Vector128.Size / Unsafe.SizeOf(); - } - } - internal static bool IsSupported { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -162,6 +165,34 @@ namespace System.Runtime.Intrinsics [CLSCompliant(false)] public Vector128 AsUInt64() => As(); + /// Determines whether the specified is equal to the current instance. + /// The to compare with the current instance. + /// true if is equal to the current instance; otherwise, false. + /// The type of the current instance () is not supported. + public bool Equals(Vector128 other) + { + ThrowIfUnsupportedType(); + + for (int i = 0; i < Count; i++) + { + if (!((IEquatable)(GetElement(i))).Equals(other.GetElement(i))) + { + return false; + } + } + + return true; + } + + /// Determines whether the specified object is equal to the current instance. + /// The object to compare with the current instance. + /// true if is a and is equal to the current instance; otherwise, false. + /// The type of the current instance () is not supported. + public override bool Equals(object obj) + { + return (obj is Vector128) && Equals((Vector128)(obj)); + } + /// Gets the element at the specified index. /// The index of the element to get. /// The value of the element at . @@ -171,7 +202,7 @@ namespace System.Runtime.Intrinsics { ThrowIfUnsupportedType(); - if ((uint)(index) >= (uint)(ElementCount)) + if ((uint)(index) >= (uint)(Count)) { throw new ArgumentOutOfRangeException(nameof(index)); } @@ -190,7 +221,7 @@ namespace System.Runtime.Intrinsics { ThrowIfUnsupportedType(); - if ((uint)(index) >= (uint)(ElementCount)) + if ((uint)(index) >= (uint)(Count)) { throw new ArgumentOutOfRangeException(nameof(index)); } @@ -201,6 +232,23 @@ namespace System.Runtime.Intrinsics return result; } + /// Gets the hash code for the instance. + /// The hash code for the instance. + /// The type of the current instance () is not supported. + public override int GetHashCode() + { + ThrowIfUnsupportedType(); + + int hashCode = 0; + + for (int i = 0; i < Count; i++) + { + hashCode = HashCode.Combine(hashCode, GetElement(i).GetHashCode()); + } + + return hashCode; + } + /// Gets the value of the lower 64-bits as a new . /// The value of the lower 64-bits as a new . /// The type of the current instance () is not supported. @@ -261,6 +309,50 @@ namespace System.Runtime.Intrinsics return Unsafe.As, T>(ref Unsafe.AsRef(in this)); } + /// Converts the current instance to an equivalent string representation. + /// An equivalent string representation of the current instance. + /// The type of the current instance () is not supported. + public override string ToString() + { + return ToString("G"); + } + + /// Converts the current instance to an equivalent string representation using the specified format. + /// The format specifier used to format the individual elements of the current instance. + /// An equivalent string representation of the current instance. + /// The type of the current instance () is not supported. + public string ToString(string format) + { + return ToString(format, CultureInfo.CurrentCulture); + } + + /// Converts the current instance to an equivalent string representation using the specified format. + /// The format specifier used to format the individual elements of the current instance. + /// The format provider used to format the individual elements of the current instance. + /// An equivalent string representation of the current instance. + /// The type of the current instance () is not supported. + public string ToString(string format, IFormatProvider formatProvider) + { + ThrowIfUnsupportedType(); + + string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator; + int lastElement = Count - 1; + + var sb = StringBuilderCache.Acquire(); + sb.Append('<'); + + for (int i = 0; i < lastElement; i++) + { + sb.Append(((IFormattable)(GetElement(i))).ToString(format, formatProvider)); + sb.Append(separator); + sb.Append(' '); + } + sb.Append(((IFormattable)(GetElement(lastElement))).ToString(format, formatProvider)); + + sb.Append('>'); + return StringBuilderCache.GetStringAndRelease(sb); + } + /// Converts the current instance to a new with the lower 128-bits set to the value of the current instance and the upper 128-bits initialized to zero. /// A new with the lower 128-bits set to the value of the current instance and the upper 128-bits initialized to zero. /// The type of the current instance () is not supported. diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector256_1.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector256_1.cs index a86ffb5..3731698 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector256_1.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector256_1.cs @@ -3,8 +3,10 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Text; using Internal.Runtime.CompilerServices; namespace System.Runtime.Intrinsics @@ -13,7 +15,8 @@ namespace System.Runtime.Intrinsics [DebuggerDisplay("{DisplayString,nq}")] [DebuggerTypeProxy(typeof(Vector256DebugView<>))] [StructLayout(LayoutKind.Sequential, Size = Vector256.Size)] - public readonly struct Vector256 where T : struct + public readonly struct Vector256 : IEquatable>, IFormattable + where T : struct { // These fields exist to ensure the alignment is 8, rather than 1. // This also allows the debug view to work https://github.com/dotnet/coreclr/issues/15694) @@ -22,6 +25,17 @@ namespace System.Runtime.Intrinsics private readonly ulong _02; private readonly ulong _03; + /// Gets the number of that are in a . + /// The type of the current instance () is not supported. + public static int Count + { + get + { + ThrowIfUnsupportedType(); + return Vector256.Size / Unsafe.SizeOf(); + } + } + /// Gets a new with all elements initialized to zero. /// The type of the current instance () is not supported. public static Vector256 Zero @@ -40,9 +54,7 @@ namespace System.Runtime.Intrinsics { if (IsSupported) { - var items = new T[ElementCount]; - Unsafe.WriteUnaligned(ref Unsafe.As(ref items[0]), this); - return $"({string.Join(", ", items)})"; + return ToString(); } else { @@ -51,15 +63,6 @@ namespace System.Runtime.Intrinsics } } - internal static int ElementCount - { - get - { - ThrowIfUnsupportedType(); - return Vector256.Size / Unsafe.SizeOf(); - } - } - internal static bool IsSupported { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -164,6 +167,34 @@ namespace System.Runtime.Intrinsics [CLSCompliant(false)] public Vector256 AsUInt64() => As(); + /// Determines whether the specified is equal to the current instance. + /// The to compare with the current instance. + /// true if is equal to the current instance; otherwise, false. + /// The type of the current instance () is not supported. + public bool Equals(Vector256 other) + { + ThrowIfUnsupportedType(); + + for (int i = 0; i < Count; i++) + { + if (!((IEquatable)(GetElement(i))).Equals(other.GetElement(i))) + { + return false; + } + } + + return true; + } + + /// Determines whether the specified object is equal to the current instance. + /// The object to compare with the current instance. + /// true if is a and is equal to the current instance; otherwise, false. + /// The type of the current instance () is not supported. + public override bool Equals(object obj) + { + return (obj is Vector256) && Equals((Vector256)(obj)); + } + /// Gets the element at the specified index. /// The index of the element to get. /// The value of the element at . @@ -173,7 +204,7 @@ namespace System.Runtime.Intrinsics { ThrowIfUnsupportedType(); - if ((uint)(index) >= (uint)(ElementCount)) + if ((uint)(index) >= (uint)(Count)) { throw new ArgumentOutOfRangeException(nameof(index)); } @@ -192,7 +223,7 @@ namespace System.Runtime.Intrinsics { ThrowIfUnsupportedType(); - if ((uint)(index) >= (uint)(ElementCount)) + if ((uint)(index) >= (uint)(Count)) { throw new ArgumentOutOfRangeException(nameof(index)); } @@ -203,6 +234,23 @@ namespace System.Runtime.Intrinsics return result; } + /// Gets the hash code for the instance. + /// The hash code for the instance. + /// The type of the current instance () is not supported. + public override int GetHashCode() + { + ThrowIfUnsupportedType(); + + int hashCode = 0; + + for (int i = 0; i < Count; i++) + { + hashCode = HashCode.Combine(hashCode, GetElement(i).GetHashCode()); + } + + return hashCode; + } + /// Gets the value of the lower 128-bits as a new . /// The value of the lower 128-bits as a new . /// The type of the current instance () is not supported. @@ -262,5 +310,49 @@ namespace System.Runtime.Intrinsics ThrowIfUnsupportedType(); return Unsafe.As, T>(ref Unsafe.AsRef(in this)); } + + /// Converts the current instance to an equivalent string representation. + /// An equivalent string representation of the current instance. + /// The type of the current instance () is not supported. + public override string ToString() + { + return ToString("G"); + } + + /// Converts the current instance to an equivalent string representation using the specified format. + /// The format specifier used to format the individual elements of the current instance. + /// An equivalent string representation of the current instance. + /// The type of the current instance () is not supported. + public string ToString(string format) + { + return ToString(format, CultureInfo.CurrentCulture); + } + + /// Converts the current instance to an equivalent string representation using the specified format. + /// The format specifier used to format the individual elements of the current instance. + /// The format provider used to format the individual elements of the current instance. + /// An equivalent string representation of the current instance. + /// The type of the current instance () is not supported. + public string ToString(string format, IFormatProvider formatProvider) + { + ThrowIfUnsupportedType(); + + string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator; + int lastElement = Count - 1; + + var sb = StringBuilderCache.Acquire(); + sb.Append('<'); + + for (int i = 0; i < lastElement; i++) + { + sb.Append(((IFormattable)(GetElement(i))).ToString(format, formatProvider)); + sb.Append(separator); + sb.Append(' '); + } + sb.Append(((IFormattable)(GetElement(lastElement))).ToString(format, formatProvider)); + + sb.Append('>'); + return StringBuilderCache.GetStringAndRelease(sb); + } } } diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64_1.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64_1.cs index 0bb0286..b190549 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64_1.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64_1.cs @@ -3,8 +3,10 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Text; using Internal.Runtime.CompilerServices; namespace System.Runtime.Intrinsics @@ -13,12 +15,24 @@ namespace System.Runtime.Intrinsics [DebuggerDisplay("{DisplayString,nq}")] [DebuggerTypeProxy(typeof(Vector64DebugView<>))] [StructLayout(LayoutKind.Sequential, Size = Vector64.Size)] - public readonly struct Vector64 where T : struct + public readonly struct Vector64 : IEquatable>, IFormattable + where T : struct { // These fields exist to ensure the alignment is 8, rather than 1. // This also allows the debug view to work https://github.com/dotnet/coreclr/issues/15694) private readonly ulong _00; + /// Gets the number of that are in a . + /// The type of the current instance () is not supported. + public static int Count + { + get + { + ThrowIfUnsupportedType(); + return Vector64.Size / Unsafe.SizeOf(); + } + } + /// Gets a new with all elements initialized to zero. /// The type of the current instance () is not supported. public static Vector64 Zero @@ -36,9 +50,7 @@ namespace System.Runtime.Intrinsics { if (IsSupported) { - var items = new T[ElementCount]; - Unsafe.WriteUnaligned(ref Unsafe.As(ref items[0]), this); - return $"({string.Join(", ", items)})"; + return ToString(); } else { @@ -47,15 +59,6 @@ namespace System.Runtime.Intrinsics } } - internal static int ElementCount - { - get - { - ThrowIfUnsupportedType(); - return Vector64.Size / Unsafe.SizeOf(); - } - } - internal static bool IsSupported { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -160,6 +163,34 @@ namespace System.Runtime.Intrinsics [CLSCompliant(false)] public Vector64 AsUInt64() => As(); + /// Determines whether the specified is equal to the current instance. + /// The to compare with the current instance. + /// true if is equal to the current instance; otherwise, false. + /// The type of the current instance () is not supported. + public bool Equals(Vector64 other) + { + ThrowIfUnsupportedType(); + + for (int i = 0; i < Count; i++) + { + if (!((IEquatable)(GetElement(i))).Equals(other.GetElement(i))) + { + return false; + } + } + + return true; + } + + /// Determines whether the specified object is equal to the current instance. + /// The object to compare with the current instance. + /// true if is a and is equal to the current instance; otherwise, false. + /// The type of the current instance () is not supported. + public override bool Equals(object obj) + { + return (obj is Vector64) && Equals((Vector64)(obj)); + } + /// Gets the element at the specified index. /// The index of the element to get. /// The value of the element at . @@ -169,7 +200,7 @@ namespace System.Runtime.Intrinsics { ThrowIfUnsupportedType(); - if ((uint)(index) >= (uint)(ElementCount)) + if ((uint)(index) >= (uint)(Count)) { throw new ArgumentOutOfRangeException(nameof(index)); } @@ -188,7 +219,7 @@ namespace System.Runtime.Intrinsics { ThrowIfUnsupportedType(); - if ((uint)(index) >= (uint)(ElementCount)) + if ((uint)(index) >= (uint)(Count)) { throw new ArgumentOutOfRangeException(nameof(index)); } @@ -199,6 +230,23 @@ namespace System.Runtime.Intrinsics return result; } + /// Gets the hash code for the instance. + /// The hash code for the instance. + /// The type of the current instance () is not supported. + public override int GetHashCode() + { + ThrowIfUnsupportedType(); + + int hashCode = 0; + + for (int i = 0; i < Count; i++) + { + hashCode = HashCode.Combine(hashCode, GetElement(i).GetHashCode()); + } + + return hashCode; + } + /// Converts the current instance to a scalar containing the value of the first element. /// A scalar containing the value of the first element. /// The type of the current instance () is not supported. @@ -208,6 +256,50 @@ namespace System.Runtime.Intrinsics return Unsafe.As, T>(ref Unsafe.AsRef(in this)); } + /// Converts the current instance to an equivalent string representation. + /// An equivalent string representation of the current instance. + /// The type of the current instance () is not supported. + public override string ToString() + { + return ToString("G"); + } + + /// Converts the current instance to an equivalent string representation using the specified format. + /// The format specifier used to format the individual elements of the current instance. + /// An equivalent string representation of the current instance. + /// The type of the current instance () is not supported. + public string ToString(string format) + { + return ToString(format, CultureInfo.CurrentCulture); + } + + /// Converts the current instance to an equivalent string representation using the specified format. + /// The format specifier used to format the individual elements of the current instance. + /// The format provider used to format the individual elements of the current instance. + /// An equivalent string representation of the current instance. + /// The type of the current instance () is not supported. + public string ToString(string format, IFormatProvider formatProvider) + { + ThrowIfUnsupportedType(); + + string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator; + int lastElement = Count - 1; + + var sb = StringBuilderCache.Acquire(); + sb.Append('<'); + + for (int i = 0; i < lastElement; i++) + { + sb.Append(((IFormattable)(GetElement(i))).ToString(format, formatProvider)); + sb.Append(separator); + sb.Append(' '); + } + sb.Append(((IFormattable)(GetElement(lastElement))).ToString(format, formatProvider)); + + sb.Append('>'); + return StringBuilderCache.GetStringAndRelease(sb); + } + /// Converts the current instance to a new with the lower 64-bits set to the value of the current instance and the upper 64-bits initialized to zero. /// A new with the lower 64-bits set to the value of the current instance and the upper 64-bits initialized to zero. /// The type of the current instance () is not supported. -- 2.7.4