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