Implement the Count property, the IEquatable and IFormattable interfaces, and the...
[platform/upstream/coreclr.git] / src / System.Private.CoreLib / shared / System / Runtime / Intrinsics / Vector256_1.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 using System.Diagnostics;
6 using System.Globalization;
7 using System.Runtime.CompilerServices;
8 using System.Runtime.InteropServices;
9 using System.Text;
10 using Internal.Runtime.CompilerServices;
11
12 namespace System.Runtime.Intrinsics
13 {
14     [Intrinsic]
15     [DebuggerDisplay("{DisplayString,nq}")]
16     [DebuggerTypeProxy(typeof(Vector256DebugView<>))]
17     [StructLayout(LayoutKind.Sequential, Size = Vector256.Size)]
18     public readonly struct Vector256<T> : IEquatable<Vector256<T>>, IFormattable
19         where T : struct
20     {
21         // These fields exist to ensure the alignment is 8, rather than 1.
22         // This also allows the debug view to work https://github.com/dotnet/coreclr/issues/15694)
23         private readonly ulong _00;
24         private readonly ulong _01;
25         private readonly ulong _02;
26         private readonly ulong _03;
27
28         /// <summary>Gets the number of <typeparamref name="T" /> that are in a <see cref="Vector256{T}" />.</summary>
29         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
30         public static int Count
31         {
32             get
33             {
34                 ThrowIfUnsupportedType();
35                 return Vector256.Size / Unsafe.SizeOf<T>();
36             }
37         }
38
39         /// <summary>Gets a new <see cref="Vector256{T}" /> with all elements initialized to zero.</summary>
40         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
41         public static Vector256<T> Zero
42         {
43             [Intrinsic]
44             get
45             {
46                 ThrowIfUnsupportedType();
47                 return default;
48             }
49         }
50
51         internal unsafe string DisplayString
52         {
53             get
54             {
55                 if (IsSupported)
56                 {
57                     return ToString();
58                 }
59                 else
60                 {
61                     return SR.NotSupported_Type;
62                 }
63             }
64         }
65
66         internal static bool IsSupported
67         {
68             [MethodImpl(MethodImplOptions.AggressiveInlining)]
69             get
70             {
71                 return (typeof(T) == typeof(byte)) ||
72                        (typeof(T) == typeof(sbyte)) ||
73                        (typeof(T) == typeof(short)) ||
74                        (typeof(T) == typeof(ushort)) ||
75                        (typeof(T) == typeof(int)) ||
76                        (typeof(T) == typeof(uint)) ||
77                        (typeof(T) == typeof(long)) ||
78                        (typeof(T) == typeof(ulong)) ||
79                        (typeof(T) == typeof(float)) ||
80                        (typeof(T) == typeof(double));
81             }
82         }
83
84         [MethodImpl(MethodImplOptions.AggressiveInlining)]
85         internal static void ThrowIfUnsupportedType()
86         {
87             if (!IsSupported)
88             {
89                 throw new NotSupportedException(SR.Arg_TypeNotSupported);
90             }
91         }
92
93         /// <summary>Reinterprets the current instance as a new <see cref="Vector256{U}" />.</summary>
94         /// <typeparam name="U">The type of the vector the current instance should be reinterpreted as.</typeparam>
95         /// <returns>The current instance reinterpreted as a new <see cref="Vector256{U}" />.</returns>
96         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) or the type of the target (<typeparamref name="U" />) is not supported.</exception>
97         [Intrinsic]
98         [MethodImpl(MethodImplOptions.AggressiveInlining)]
99         public Vector256<U> As<U>() where U : struct
100         {
101             ThrowIfUnsupportedType();
102             Vector256<U>.ThrowIfUnsupportedType();
103             return Unsafe.As<Vector256<T>, Vector256<U>>(ref Unsafe.AsRef(in this));
104         }
105
106         /// <summary>Reinterprets the current instance as a new <see cref="Vector256{byte}" />.</summary>
107         /// <returns>The current instance reinterpreted as a new <see cref="Vector256{byte}" />.</returns>
108         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
109         [Intrinsic]
110         public Vector256<byte> AsByte() => As<byte>();
111
112         /// <summary>Reinterprets the current instance as a new <see cref="Vector256{double}" />.</summary>
113         /// <returns>The current instance reinterpreted as a new <see cref="Vector256{double}" />.</returns>
114         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
115         [Intrinsic]
116         public Vector256<double> AsDouble() => As<double>();
117
118         /// <summary>Reinterprets the current instance as a new <see cref="Vector256{short}" />.</summary>
119         /// <returns>The current instance reinterpreted as a new <see cref="Vector256{short}" />.</returns>
120         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
121         [Intrinsic]
122         public Vector256<short> AsInt16() => As<short>();
123
124         /// <summary>Reinterprets the current instance as a new <see cref="Vector256{int}" />.</summary>
125         /// <returns>The current instance reinterpreted as a new <see cref="Vector256{int}" />.</returns>
126         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
127         [Intrinsic]
128         public Vector256<int> AsInt32() => As<int>();
129
130         /// <summary>Reinterprets the current instance as a new <see cref="Vector256{long}" />.</summary>
131         /// <returns>The current instance reinterpreted as a new <see cref="Vector256{long}" />.</returns>
132         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
133         [Intrinsic]
134         public Vector256<long> AsInt64() => As<long>();
135
136         /// <summary>Reinterprets the current instance as a new <see cref="Vector256{sbyte}" />.</summary>
137         /// <returns>The current instance reinterpreted as a new <see cref="Vector256{sbyte}" />.</returns>
138         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
139         [Intrinsic]
140         [CLSCompliant(false)]
141         public Vector256<sbyte> AsSByte() => As<sbyte>();
142
143         /// <summary>Reinterprets the current instance as a new <see cref="Vector256{float}" />.</summary>
144         /// <returns>The current instance reinterpreted as a new <see cref="Vector256{float}" />.</returns>
145         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
146         [Intrinsic]
147         public Vector256<float> AsSingle() => As<float>();
148
149         /// <summary>Reinterprets the current instance as a new <see cref="Vector256{ushort}" />.</summary>
150         /// <returns>The current instance reinterpreted as a new <see cref="Vector256{ushort}" />.</returns>
151         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
152         [Intrinsic]
153         [CLSCompliant(false)]
154         public Vector256<ushort> AsUInt16() => As<ushort>();
155
156         /// <summary>Reinterprets the current instance as a new <see cref="Vector256{uint}" />.</summary>
157         /// <returns>The current instance reinterpreted as a new <see cref="Vector256{uint}" />.</returns>
158         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
159         [Intrinsic]
160         [CLSCompliant(false)]
161         public Vector256<uint> AsUInt32() => As<uint>();
162
163         /// <summary>Reinterprets the current instance as a new <see cref="Vector256{ulong}" />.</summary>
164         /// <returns>The current instance reinterpreted as a new <see cref="Vector256{ulong}" />.</returns>
165         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
166         [Intrinsic]
167         [CLSCompliant(false)]
168         public Vector256<ulong> AsUInt64() => As<ulong>();
169
170         /// <summary>Determines whether the specified <see cref="Vector256{T}" /> is equal to the current instance.</summary>
171         /// <param name="other">The <see cref="Vector256{T}" /> to compare with the current instance.</param>
172         /// <returns><c>true</c> if <paramref name="other" /> is equal to the current instance; otherwise, <c>false</c>.</returns>
173         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
174         public bool Equals(Vector256<T> other)
175         {
176             ThrowIfUnsupportedType();
177
178             for (int i = 0; i < Count; i++)
179             {
180                 if (!((IEquatable<T>)(GetElement(i))).Equals(other.GetElement(i)))
181                 {
182                     return false;
183                 }
184             }
185
186             return true;
187         }
188
189         /// <summary>Determines whether the specified object is equal to the current instance.</summary>
190         /// <param name="obj">The object to compare with the current instance.</param>
191         /// <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>
192         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
193         public override bool Equals(object obj)
194         {
195             return (obj is Vector256<T>) && Equals((Vector256<T>)(obj));
196         }
197
198         /// <summary>Gets the element at the specified index.</summary>
199         /// <param name="index">The index of the element to get.</param>
200         /// <returns>The value of the element at <paramref name="index" />.</returns>
201         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
202         /// <exception cref="ArgumentOutOfRangeException"><paramref name="index" /> was less than zero or greater than the number of elements.</exception>
203         public T GetElement(int index)
204         {
205             ThrowIfUnsupportedType();
206
207             if ((uint)(index) >= (uint)(Count))
208             {
209                 throw new ArgumentOutOfRangeException(nameof(index));
210             }
211
212             ref T e0 = ref Unsafe.As<Vector256<T>, T>(ref Unsafe.AsRef(in this));
213             return Unsafe.Add(ref e0, index);
214         }
215
216         /// <summary>Creates a new <see cref="Vector256{T}" /> with the element at the specified index set to the specified value and the remaining elements set to the same value as that in the current instance.</summary>
217         /// <param name="index">The index of the element to set.</param>
218         /// <param name="value">The value to set the value to.</param>
219         /// <returns>A <see cref="Vector256{T}" /> with the value of the element at <paramref name="index" /> set to <paramref name="value" /> and the remaining elements set to the same value as that in the current instance.</returns>
220         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
221         /// <exception cref="ArgumentOutOfRangeException"><paramref name="index" /> was less than zero or greater than the number of elements.</exception>
222         public Vector256<T> WithElement(int index, T value)
223         {
224             ThrowIfUnsupportedType();
225
226             if ((uint)(index) >= (uint)(Count))
227             {
228                 throw new ArgumentOutOfRangeException(nameof(index));
229             }
230
231             Vector256<T> result = this;
232             ref T e0 = ref Unsafe.As<Vector256<T>, T>(ref result);
233             Unsafe.Add(ref e0, index) = value;
234             return result;
235         }
236
237         /// <summary>Gets the hash code for the instance.</summary>
238         /// <returns>The hash code for the instance.</returns>
239         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
240         public override int GetHashCode()
241         {
242             ThrowIfUnsupportedType();
243
244             int hashCode = 0;
245
246             for (int i = 0; i < Count; i++)
247             {
248                 hashCode = HashCode.Combine(hashCode, GetElement(i).GetHashCode());
249             }
250
251             return hashCode;
252         }
253
254         /// <summary>Gets the value of the lower 128-bits as a new <see cref="Vector128{T}" />.</summary>
255         /// <returns>The value of the lower 128-bits as a new <see cref="Vector128{T}" />.</returns>
256         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
257         public Vector128<T> GetLower()
258         {
259             ThrowIfUnsupportedType();
260             Vector128<T>.ThrowIfUnsupportedType();
261             return Unsafe.As<Vector256<T>, Vector128<T>>(ref Unsafe.AsRef(in this));
262         }
263
264         /// <summary>Creates a new <see cref="Vector256{T}" /> with the lower 128-bits set to the specified value and the lower 128-bits set to the same value as that in the current instance.</summary>
265         /// <param name="value">The value of the lower 128-bits as a <see cref="Vector128{T}" />.</param>
266         /// <returns>A new <see cref="Vector256{T}" /> with the lower 128-bits set to the specified value and the lower 128-bits set to the same value as that in the current instance.</returns>
267         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
268         public Vector256<T> WithLower(Vector128<T> value)
269         {
270             ThrowIfUnsupportedType();
271             Vector128<T>.ThrowIfUnsupportedType();
272
273             Vector256<T> result = this;
274             Unsafe.As<Vector256<T>, Vector128<T>>(ref result) = value;
275             return result;
276         }
277
278         /// <summary>Gets the value of the upper 128-bits as a new <see cref="Vector128{T}" />.</summary>
279         /// <returns>The value of the upper 128-bits as a new <see cref="Vector128{T}" />.</returns>
280         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
281         public Vector128<T> GetUpper()
282         {
283             ThrowIfUnsupportedType();
284             Vector128<T>.ThrowIfUnsupportedType();
285
286             ref Vector128<T> lower = ref Unsafe.As<Vector256<T>, Vector128<T>>(ref Unsafe.AsRef(in this));
287             return Unsafe.Add(ref lower, 1);
288         }
289
290         /// <summary>Creates a new <see cref="Vector256{T}" /> with the upper 128-bits set to the specified value and the upper 128-bits set to the same value as that in the current instance.</summary>
291         /// <param name="value">The value of the upper 128-bits as a <see cref="Vector128{T}" />.</param>
292         /// <returns>A new <see cref="Vector256{T}" /> with the upper 128-bits set to the specified value and the upper 128-bits set to the same value as that in the current instance.</returns>
293         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
294         public Vector256<T> WithUpper(Vector128<T> value)
295         {
296             ThrowIfUnsupportedType();
297             Vector128<T>.ThrowIfUnsupportedType();
298
299             Vector256<T> result = this;
300             ref Vector128<T> lower = ref Unsafe.As<Vector256<T>, Vector128<T>>(ref result);
301             Unsafe.Add(ref lower, 1) = value;
302             return result;
303         }
304
305         /// <summary>Converts the current instance to a scalar containing the value of the first element.</summary>
306         /// <returns>A scalar <typeparamref name="T" /> containing the value of the first element.</returns>
307         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
308         public T ToScalar()
309         {
310             ThrowIfUnsupportedType();
311             return Unsafe.As<Vector256<T>, T>(ref Unsafe.AsRef(in this));
312         }
313
314         /// <summary>Converts the current instance to an equivalent string representation.</summary>
315         /// <returns>An equivalent string representation of the current instance.</returns>
316         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
317         public override string ToString()
318         {
319             return ToString("G");
320         }
321
322         /// <summary>Converts the current instance to an equivalent string representation using the specified format.</summary>
323         /// <param name="format">The format specifier used to format the individual elements of the current instance.</param>
324         /// <returns>An equivalent string representation of the current instance.</returns>
325         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
326         public string ToString(string format)
327         {
328             return ToString(format, CultureInfo.CurrentCulture);
329         }
330
331         /// <summary>Converts the current instance to an equivalent string representation using the specified format.</summary>
332         /// <param name="format">The format specifier used to format the individual elements of the current instance.</param>
333         /// <param name="formatProvider">The format provider used to format the individual elements of the current instance.</param>
334         /// <returns>An equivalent string representation of the current instance.</returns>
335         /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
336         public string ToString(string format, IFormatProvider formatProvider)
337         {
338             ThrowIfUnsupportedType();
339
340             string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator;
341             int lastElement = Count - 1;
342
343             var sb = StringBuilderCache.Acquire();
344             sb.Append('<');
345
346             for (int i = 0; i < lastElement; i++)
347             {
348                 sb.Append(((IFormattable)(GetElement(i))).ToString(format, formatProvider));
349                 sb.Append(separator);
350                 sb.Append(' ');
351             }
352             sb.Append(((IFormattable)(GetElement(lastElement))).ToString(format, formatProvider));
353
354             sb.Append('>');
355             return StringBuilderCache.GetStringAndRelease(sb);
356         }
357     }
358 }