Implement the Count property, the IEquatable and IFormattable interfaces, and the...
authorTanner Gooding <tagoo@outlook.com>
Thu, 29 Nov 2018 20:15:43 +0000 (12:15 -0800)
committerGitHub <noreply@github.com>
Thu, 29 Nov 2018 20:15:43 +0000 (12:15 -0800)
* Exposing the Count property on Vector64/128/256<T>

* Implementing IEquatable, IFormattable, and the object overrides on Vector64/128/256<T>

* Use StringBuilderCache, HashCode, and the provided format specifier

* Use StringBuilderCache.GetStringAndRelease and get the correct element when formatting Vector64/128/256<T>

src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector128_1.cs
src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector256_1.cs
src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64_1.cs

index f3599a9..da73f87 100644 (file)
@@ -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<T> where T : struct
+    public readonly struct Vector128<T> : IEquatable<Vector128<T>>, 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;
 
+        /// <summary>Gets the number of <typeparamref name="T" /> that are in a <see cref="Vector128{T}" />.</summary>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public static int Count
+        {
+            get
+            {
+                ThrowIfUnsupportedType();
+                return Vector128.Size / Unsafe.SizeOf<T>();
+            }
+        }
+
         /// <summary>Gets a new <see cref="Vector128{T}" /> with all elements initialized to zero.</summary>
         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
         public static Vector128<T> Zero
@@ -38,9 +52,7 @@ namespace System.Runtime.Intrinsics
             {
                 if (IsSupported)
                 {
-                    var items = new T[ElementCount];
-                    Unsafe.WriteUnaligned(ref Unsafe.As<T, byte>(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<T>();
-            }
-        }
-
         internal static bool IsSupported
         {
             [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -162,6 +165,34 @@ namespace System.Runtime.Intrinsics
         [CLSCompliant(false)]
         public Vector128<ulong> AsUInt64() => As<ulong>();
 
+        /// <summary>Determines whether the specified <see cref="Vector128{T}" /> is equal to the current instance.</summary>
+        /// <param name="other">The <see cref="Vector128{T}" /> to compare with the current instance.</param>
+        /// <returns><c>true</c> if <paramref name="other" /> is equal to the current instance; otherwise, <c>false</c>.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public bool Equals(Vector128<T> other)
+        {
+            ThrowIfUnsupportedType();
+
+            for (int i = 0; i < Count; i++)
+            {
+                if (!((IEquatable<T>)(GetElement(i))).Equals(other.GetElement(i)))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        /// <summary>Determines whether the specified object is equal to the current instance.</summary>
+        /// <param name="obj">The object to compare with the current instance.</param>
+        /// <returns><c>true</c> if <paramref name="obj" /> is a <see cref="Vector128{T}" /> and is equal to the current instance; otherwise, <c>false</c>.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public override bool Equals(object obj)
+        {
+            return (obj is Vector128<T>) && Equals((Vector128<T>)(obj));
+        }
+
         /// <summary>Gets the element at the specified index.</summary>
         /// <param name="index">The index of the element to get.</param>
         /// <returns>The value of the element at <paramref name="index" />.</returns>
@@ -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;
         }
 
+        /// <summary>Gets the hash code for the instance.</summary>
+        /// <returns>The hash code for the instance.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public override int GetHashCode()
+        {
+            ThrowIfUnsupportedType();
+
+            int hashCode = 0;
+
+            for (int i = 0; i < Count; i++)
+            {
+                hashCode = HashCode.Combine(hashCode, GetElement(i).GetHashCode());
+            }
+
+            return hashCode;
+        }
+
         /// <summary>Gets the value of the lower 64-bits as a new <see cref="Vector64{T}" />.</summary>
         /// <returns>The value of the lower 64-bits as a new <see cref="Vector64{T}" />.</returns>
         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
@@ -261,6 +309,50 @@ namespace System.Runtime.Intrinsics
             return Unsafe.As<Vector128<T>, T>(ref Unsafe.AsRef(in this));
         }
 
+        /// <summary>Converts the current instance to an equivalent string representation.</summary>
+        /// <returns>An equivalent string representation of the current instance.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public override string ToString()
+        {
+            return ToString("G");
+        }
+
+        /// <summary>Converts the current instance to an equivalent string representation using the specified format.</summary>
+        /// <param name="format">The format specifier used to format the individual elements of the current instance.</param>
+        /// <returns>An equivalent string representation of the current instance.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public string ToString(string format)
+        {
+            return ToString(format, CultureInfo.CurrentCulture);
+        }
+
+        /// <summary>Converts the current instance to an equivalent string representation using the specified format.</summary>
+        /// <param name="format">The format specifier used to format the individual elements of the current instance.</param>
+        /// <param name="formatProvider">The format provider used to format the individual elements of the current instance.</param>
+        /// <returns>An equivalent string representation of the current instance.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        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);
+        }
+
         /// <summary>Converts the current instance to a new <see cref="Vector256{T}" /> with the lower 128-bits set to the value of the current instance and the upper 128-bits initialized to zero.</summary>
         /// <returns>A new <see cref="Vector256{T}" /> with the lower 128-bits set to the value of the current instance and the upper 128-bits initialized to zero.</returns>
         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
index a86ffb5..3731698 100644 (file)
@@ -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<T> where T : struct
+    public readonly struct Vector256<T> : IEquatable<Vector256<T>>, 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;
 
+        /// <summary>Gets the number of <typeparamref name="T" /> that are in a <see cref="Vector256{T}" />.</summary>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public static int Count
+        {
+            get
+            {
+                ThrowIfUnsupportedType();
+                return Vector256.Size / Unsafe.SizeOf<T>();
+            }
+        }
+
         /// <summary>Gets a new <see cref="Vector256{T}" /> with all elements initialized to zero.</summary>
         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
         public static Vector256<T> Zero
@@ -40,9 +54,7 @@ namespace System.Runtime.Intrinsics
             {
                 if (IsSupported)
                 {
-                    var items = new T[ElementCount];
-                    Unsafe.WriteUnaligned(ref Unsafe.As<T, byte>(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<T>();
-            }
-        }
-
         internal static bool IsSupported
         {
             [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -164,6 +167,34 @@ namespace System.Runtime.Intrinsics
         [CLSCompliant(false)]
         public Vector256<ulong> AsUInt64() => As<ulong>();
 
+        /// <summary>Determines whether the specified <see cref="Vector256{T}" /> is equal to the current instance.</summary>
+        /// <param name="other">The <see cref="Vector256{T}" /> to compare with the current instance.</param>
+        /// <returns><c>true</c> if <paramref name="other" /> is equal to the current instance; otherwise, <c>false</c>.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public bool Equals(Vector256<T> other)
+        {
+            ThrowIfUnsupportedType();
+
+            for (int i = 0; i < Count; i++)
+            {
+                if (!((IEquatable<T>)(GetElement(i))).Equals(other.GetElement(i)))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        /// <summary>Determines whether the specified object is equal to the current instance.</summary>
+        /// <param name="obj">The object to compare with the current instance.</param>
+        /// <returns><c>true</c> if <paramref name="obj" /> is a <see cref="Vector256{T}" /> and is equal to the current instance; otherwise, <c>false</c>.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public override bool Equals(object obj)
+        {
+            return (obj is Vector256<T>) && Equals((Vector256<T>)(obj));
+        }
+
         /// <summary>Gets the element at the specified index.</summary>
         /// <param name="index">The index of the element to get.</param>
         /// <returns>The value of the element at <paramref name="index" />.</returns>
@@ -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;
         }
 
+        /// <summary>Gets the hash code for the instance.</summary>
+        /// <returns>The hash code for the instance.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public override int GetHashCode()
+        {
+            ThrowIfUnsupportedType();
+
+            int hashCode = 0;
+
+            for (int i = 0; i < Count; i++)
+            {
+                hashCode = HashCode.Combine(hashCode, GetElement(i).GetHashCode());
+            }
+
+            return hashCode;
+        }
+
         /// <summary>Gets the value of the lower 128-bits as a new <see cref="Vector128{T}" />.</summary>
         /// <returns>The value of the lower 128-bits as a new <see cref="Vector128{T}" />.</returns>
         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
@@ -262,5 +310,49 @@ namespace System.Runtime.Intrinsics
             ThrowIfUnsupportedType();
             return Unsafe.As<Vector256<T>, T>(ref Unsafe.AsRef(in this));
         }
+
+        /// <summary>Converts the current instance to an equivalent string representation.</summary>
+        /// <returns>An equivalent string representation of the current instance.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public override string ToString()
+        {
+            return ToString("G");
+        }
+
+        /// <summary>Converts the current instance to an equivalent string representation using the specified format.</summary>
+        /// <param name="format">The format specifier used to format the individual elements of the current instance.</param>
+        /// <returns>An equivalent string representation of the current instance.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public string ToString(string format)
+        {
+            return ToString(format, CultureInfo.CurrentCulture);
+        }
+
+        /// <summary>Converts the current instance to an equivalent string representation using the specified format.</summary>
+        /// <param name="format">The format specifier used to format the individual elements of the current instance.</param>
+        /// <param name="formatProvider">The format provider used to format the individual elements of the current instance.</param>
+        /// <returns>An equivalent string representation of the current instance.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        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);
+        }
     }
 }
index 0bb0286..b190549 100644 (file)
@@ -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<T> where T : struct
+    public readonly struct Vector64<T> : IEquatable<Vector64<T>>, 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;
 
+        /// <summary>Gets the number of <typeparamref name="T" /> that are in a <see cref="Vector64{T}" />.</summary>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public static int Count
+        {
+            get
+            {
+                ThrowIfUnsupportedType();
+                return Vector64.Size / Unsafe.SizeOf<T>();
+            }
+        }
+
         /// <summary>Gets a new <see cref="Vector64{T}" /> with all elements initialized to zero.</summary>
         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
         public static Vector64<T> Zero
@@ -36,9 +50,7 @@ namespace System.Runtime.Intrinsics
             {
                 if (IsSupported)
                 {
-                    var items = new T[ElementCount];
-                    Unsafe.WriteUnaligned(ref Unsafe.As<T, byte>(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<T>();
-            }
-        }
-
         internal static bool IsSupported
         {
             [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -160,6 +163,34 @@ namespace System.Runtime.Intrinsics
         [CLSCompliant(false)]
         public Vector64<ulong> AsUInt64() => As<ulong>();
 
+        /// <summary>Determines whether the specified <see cref="Vector64{T}" /> is equal to the current instance.</summary>
+        /// <param name="other">The <see cref="Vector64{T}" /> to compare with the current instance.</param>
+        /// <returns><c>true</c> if <paramref name="other" /> is equal to the current instance; otherwise, <c>false</c>.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public bool Equals(Vector64<T> other)
+        {
+            ThrowIfUnsupportedType();
+
+            for (int i = 0; i < Count; i++)
+            {
+                if (!((IEquatable<T>)(GetElement(i))).Equals(other.GetElement(i)))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        /// <summary>Determines whether the specified object is equal to the current instance.</summary>
+        /// <param name="obj">The object to compare with the current instance.</param>
+        /// <returns><c>true</c> if <paramref name="obj" /> is a <see cref="Vector64{T}" /> and is equal to the current instance; otherwise, <c>false</c>.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public override bool Equals(object obj)
+        {
+            return (obj is Vector64<T>) && Equals((Vector64<T>)(obj));
+        }
+
         /// <summary>Gets the element at the specified index.</summary>
         /// <param name="index">The index of the element to get.</param>
         /// <returns>The value of the element at <paramref name="index" />.</returns>
@@ -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;
         }
 
+        /// <summary>Gets the hash code for the instance.</summary>
+        /// <returns>The hash code for the instance.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public override int GetHashCode()
+        {
+            ThrowIfUnsupportedType();
+
+            int hashCode = 0;
+
+            for (int i = 0; i < Count; i++)
+            {
+                hashCode = HashCode.Combine(hashCode, GetElement(i).GetHashCode());
+            }
+
+            return hashCode;
+        }
+
         /// <summary>Converts the current instance to a scalar containing the value of the first element.</summary>
         /// <returns>A scalar <typeparamref name="T" /> containing the value of the first element.</returns>
         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
@@ -208,6 +256,50 @@ namespace System.Runtime.Intrinsics
             return Unsafe.As<Vector64<T>, T>(ref Unsafe.AsRef(in this));
         }
 
+        /// <summary>Converts the current instance to an equivalent string representation.</summary>
+        /// <returns>An equivalent string representation of the current instance.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public override string ToString()
+        {
+            return ToString("G");
+        }
+
+        /// <summary>Converts the current instance to an equivalent string representation using the specified format.</summary>
+        /// <param name="format">The format specifier used to format the individual elements of the current instance.</param>
+        /// <returns>An equivalent string representation of the current instance.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        public string ToString(string format)
+        {
+            return ToString(format, CultureInfo.CurrentCulture);
+        }
+
+        /// <summary>Converts the current instance to an equivalent string representation using the specified format.</summary>
+        /// <param name="format">The format specifier used to format the individual elements of the current instance.</param>
+        /// <param name="formatProvider">The format provider used to format the individual elements of the current instance.</param>
+        /// <returns>An equivalent string representation of the current instance.</returns>
+        /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
+        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);
+        }
+
         /// <summary>Converts the current instance to a new <see cref="Vector128{T}" /> with the lower 64-bits set to the value of the current instance and the upper 64-bits initialized to zero.</summary>
         /// <returns>A new <see cref="Vector128{T}" /> with the lower 64-bits set to the value of the current instance and the upper 64-bits initialized to zero.</returns>
         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>