diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 20473f9c35902..f3971d1fc235e 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -444,6 +444,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4_1.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4_1.cs new file mode 100644 index 0000000000000..58060e6f1ba30 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4_1.cs @@ -0,0 +1,650 @@ +// 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. + +using System; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Text; + +namespace System.Numerics +{ + public readonly struct Vector4 : IEquatable>, IFormattable + where T : struct + { + // Fields + public T X { get; } + + public T Y { get; } + + public T Z { get; } + + public T W { get; } + + // Constructors + public Vector4(T value) + { + X = value; + Y = value; + Z = value; + W = value; + } + + public Vector4(T x, T y, T z, T w) + { + X = x; + Y = y; + Z = z; + W = w; + } + + public Vector4(T[] value) : this(value.AsSpan()) + { + } + + public Vector4(T[] value, int offset) : this(value.AsSpan(offset)) + { + } + + public Vector4(ReadOnlySpan value) + { + ThrowForUnsupportedVectorBaseType(); + + if (value.Length < 4) + { + ThrowHelper.ThrowArgumentOutOfRangeException( + ExceptionArgument.value, + ExceptionResource.ArgumentOutOfRange_SmallCapacity + ); + } + + X = value[0]; + Y = value[1]; + Z = value[2]; + W = value[3]; + } + + // Static Properties + public static Vector4 One + { + get + { + ThrowForUnsupportedVectorBaseType(); + T one = default; + if (typeof(T) == typeof(float)) + { + one = (T)(object)1.0f; + } + else if (typeof(T) == typeof(double)) + { + one = (T)(object)1.0d; + } + else + { + throw new NotImplementedException(); + } + + return new Vector4(one, one, one, one); + } + } + public static Vector4 UnitX + { + get + { + ThrowForUnsupportedVectorBaseType(); + T one = default; + T zero = default; + if (typeof(T) == typeof(float)) + { + one = (T)(object)1.0f; + } + else if (typeof(T) == typeof(double)) + { + one = (T)(object)1.0d; + } + else + { + throw new NotImplementedException(); + } + + return new Vector4(one, zero, zero, zero); + } + } + public static Vector4 UnitY + { + get + { + ThrowForUnsupportedVectorBaseType(); + T one = default; + T zero = default; + if (typeof(T) == typeof(float)) + { + one = (T)(object)1.0f; + } + else if (typeof(T) == typeof(double)) + { + one = (T)(object)1.0d; + } + else + { + throw new NotImplementedException(); + } + + return new Vector4(zero, one, zero, zero); + } + } + public static Vector4 UnitZ + { + get + { + ThrowForUnsupportedVectorBaseType(); + T one = default; + T zero = default; + if (typeof(T) == typeof(float)) + { + one = (T)(object)1.0f; + } + else if (typeof(T) == typeof(double)) + { + one = (T)(object)1.0d; + } + else + { + throw new NotImplementedException(); + } + + return new Vector4(zero, zero, one, zero); + } + } + public static Vector4 UnitW + { + get + { + ThrowForUnsupportedVectorBaseType(); + T one = default; + T zero = default; + if (typeof(T) == typeof(float)) + { + one = (T)(object)1.0f; + } + else if (typeof(T) == typeof(double)) + { + one = (T)(object)1.0d; + } + else + { + throw new NotImplementedException(); + } + + return new Vector4(zero, zero, zero, one); + } + } + public static Vector4 Zero + { + get + { + ThrowForUnsupportedVectorBaseType(); + return default; + } + } + + // With methods + public Vector4 WithX(T x) => new Vector4(x, Y, Z, W); + public Vector4 WithY(T y) => new Vector4(X, y, Z, W); + public Vector4 WithZ(T z) => new Vector4(X, Y, z, W); + public Vector4 WithW(T w) => new Vector4(X, Y, Z, w); + + // Operators + public static bool operator ==(Vector4 left, Vector4 right) + { + ThrowForUnsupportedVectorBaseType(); + + if (typeof(T) == typeof(float)) + { + return (float)(object)left.X == (float)(object)right.X + && (float)(object)left.Y == (float)(object)right.Y; + && (float)(object)left.Z == (float)(object)right.Z; + && (float)(object)left.W == (float)(object)right.W; + } + else if (typeof(T) == typeof(double)) + { + return (double)(object)left.X == (double)(object)right.X + && (double)(object)left.Y == (double)(object)right.Y; + && (double)(object)left.Z == (double)(object)right.Z; + && (double)(object)left.W == (double)(object)right.W; + } + + return default; + } + + public static bool operator !=(Vector4 left, Vector4 right) => !(left == right); + + public static Vector4 operator +(Vector4 value) => value; + + public static Vector4 operator -(Vector4 value) + { + ThrowForUnsupportedVectorBaseType(); + + if (typeof(T) == typeof(float)) + { + var negX = -(float)(object)value.X; + var negY = -(float)(object)value.Y; + var negZ = -(float)(object)value.Z; + var negW = -(float)(object)value.W; + return new Vector4((T)(object)negX, (T)(object)negY, (T)(object)negZ, (T)(object)negW); + } + else if (typeof(T) == typeof(double)) + { + var negX = -(double)(object)value.X; + var negY = -(double)(object)value.Y; + var negZ = -(double)(object)value.Z; + var negW = -(double)(object)value.W; + return new Vector4((T)(object)negX, (T)(object)negY, (T)(object)negZ, (T)(object)negW); + } + + return default; + } + + public static Vector4 operator +(Vector4 left, Vector4 right) + { + ThrowForUnsupportedVectorBaseType(); + + if (typeof(T) == typeof(float)) + { + var x = (float)(object)left.X + (float)(object)right.X; + var y = (float)(object)left.Y + (float)(object)right.Y; + var z = (float)(object)left.Z + (float)(object)right.Z; + var w = (float)(object)left.W + (float)(object)right.W; + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + else if (typeof(T) == typeof(double)) + { + var x = (double)(object)left.X + (double)(object)right.X; + var y = (double)(object)left.Y + (double)(object)right.Y; + var z = (double)(object)left.Z + (double)(object)right.Z; + var w = (double)(object)left.W + (double)(object)right.W; + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + + return default; + } + + public static Vector4 operator -(Vector4 left, Vector4 right) + { + ThrowForUnsupportedVectorBaseType(); + + if (typeof(T) == typeof(float)) + { + var x = (float)(object)left.X - (float)(object)right.X; + var y = (float)(object)left.Y - (float)(object)right.Y; + var z = (float)(object)left.Z - (float)(object)right.Z; + var w = (float)(object)left.W - (float)(object)right.W; + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + else if (typeof(T) == typeof(double)) + { + var x = (double)(object)left.X - (double)(object)right.X; + var y = (double)(object)left.Y - (double)(object)right.Y; + var z = (double)(object)left.Z - (double)(object)right.Z; + var w = (double)(object)left.W - (double)(object)right.W; + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + + return default; + } + + public static Vector4 operator *(Vector4 left, Vector4 right) + { + ThrowForUnsupportedVectorBaseType(); + + if (typeof(T) == typeof(float)) + { + var x = (float)(object)left.X * (float)(object)right.X; + var y = (float)(object)left.Y * (float)(object)right.Y; + var z = (float)(object)left.Z * (float)(object)right.Z; + var w = (float)(object)left.W * (float)(object)right.W; + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + else if (typeof(T) == typeof(double)) + { + var x = (double)(object)left.X * (double)(object)right.X; + var y = (double)(object)left.Y * (double)(object)right.Y; + var z = (double)(object)left.Z * (double)(object)right.Z; + var w = (double)(object)left.W * (double)(object)right.W; + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + + return default; + } + + public static Vector4 operator /(Vector4 left, Vector4 right) + { + ThrowForUnsupportedVectorBaseType(); + + if (typeof(T) == typeof(float)) + { + var x = (float)(object)left.X / (float)(object)right.X; + var y = (float)(object)left.Y / (float)(object)right.Y; + var z = (float)(object)left.Z / (float)(object)right.Z; + var w = (float)(object)left.W / (float)(object)right.W; + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + else if (typeof(T) == typeof(double)) + { + var x = (double)(object)left.X / (double)(object)right.X; + var y = (double)(object)left.Y / (double)(object)right.Y; + var z = (double)(object)left.Z / (double)(object)right.Z; + var w = (double)(object)left.W / (double)(object)right.W; + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + + return default; + } + + public static Vector4 operator *(Vector4 left, T right) + { + ThrowForUnsupportedVectorBaseType(); + + if (typeof(T) == typeof(float)) + { + var scalar = (float)(object)right; + var x = (float)(object)left.X * scalar; + var y = (float)(object)left.Y * scalar; + var z = (float)(object)left.Z * scalar; + var w = (float)(object)left.W * scalar; + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + else if (typeof(T) == typeof(double)) + { + var scalar = (double)(object)right; + var x = (double)(object)left.X * scalar; + var y = (double)(object)left.Y * scalar; + var z = (double)(object)left.Z * scalar; + var w = (double)(object)left.W * scalar; + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + + return default; + } + + public static Vector4 operator /(Vector4 left, T right) + { + ThrowForUnsupportedVectorBaseType(); + + if (typeof(T) == typeof(float)) + { + var scalar = (float)(object)right; + var x = (float)(object)left.X / scalar; + var y = (float)(object)left.Y / scalar; + var z = (float)(object)left.Z / scalar; + var w = (float)(object)left.W / scalar; + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + else if (typeof(T) == typeof(double)) + { + var scalar = (double)(object)right; + var x = (double)(object)left.X / scalar; + var y = (double)(object)left.Y / scalar; + var z = (double)(object)left.Z / scalar; + var w = (double)(object)left.W / scalar; + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + + return default; + } + + public static Vector4 operator *(T left, Vector4 right) => right * left; + + // "Friendly" Operators + public static Vector4 Plus(Vector4 value) => value; // unary plus is nop + public static Vector4 Negate(Vector4 value) => -value; + + public static Vector4 Add(Vector4 left, Vector4 right) => left + right; + public static Vector4 Subtract(Vector4 left, Vector4 right) => left - right; + + public static Vector4 Multiply(Vector4 left, Vector4 right) => left * right; + public static Vector4 Divide(Vector4 left, Vector4 right) => left / right; + + public static Vector4 Multiply(Vector4 left, T right) => left * right; + public static Vector4 Divide(Vector4 left, T right) => left / right; + + public static Vector4 Multiply(T left, Vector4 right) => left * right; + + // Static Methods + + public static Vector4 Abs(Vector4 value) + { + ThrowForUnsupportedVectorBaseType(); + + if (typeof(T) == typeof(float)) + { + var x = MathF.Abs((float)(object)value.X); + var y = MathF.Abs((float)(object)value.Y); + var z = MathF.Abs((float)(object)value.Z); + var w = MathF.Abs((float)(object)value.W); + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + else if (typeof(T) == typeof(double)) + { + var x = MathF.Abs((double)(object)value.X); + var y = MathF.Abs((double)(object)value.Y); + var z = MathF.Abs((double)(object)value.Z); + var w = MathF.Abs((double)(object)value.W); + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + + return default; + } + + public static Vector4 Clamp(Vector4 value, Vector4 min, Vector4 max) => Min(Max(value, min), max); // Keeps style of old Vector4 method (HLSL style) + + public static T Distance(Vector4 left, Vector4 right) + { + return (left - right).Length(); + } + + public static T DistanceSquared(Vector4 left, Vector4 right) => (left - right).LengthSquared(); + + public static T Dot(Vector4 left, Vector4 right) + { + ThrowForUnsupportedVectorBaseType(); + + if (typeof(T) == typeof(float)) + { + var x = (float)(object)left.X * (float)(object)right.X; + var y = (float)(object)left.Y * (float)(object)right.Y; + var z = (float)(object)left.Z * (float)(object)right.Z; + var w = (float)(object)left.W * (float)(object)right.W; + + return (T)(object)(x + y + z + w); + } + else if (typeof(T) == typeof(double)) + { + var x = (double)(object)left.X * (double)(object)right.X; + var y = (double)(object)left.Y * (double)(object)right.Y; + var z = (double)(object)left.Z * (double)(object)right.Z; + var w = (double)(object)left.W * (double)(object)right.W; + + return (T)(object)(x + y + z + w); + } + + return default; + } + + public static Vector4 Lerp(Vector4 min, Vector4 max, T amount) => (min * (One - new Vector4(amount))) + (max * amount); + + public static Vector4 Min(Vector4 left, Vector4 right) + { + ThrowForUnsupportedVectorBaseType(); + + if (typeof(T) == typeof(float)) + { + var x = Math.Min((float)(object)left.X, (float)(object)right.X); + var y = Math.Min((float)(object)left.Y, (float)(object)right.Y); + var z = Math.Min((float)(object)left.Z, (float)(object)right.Z); + var w = Math.Min((float)(object)left.W, (float)(object)right.W); + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + else if (typeof(T) == typeof(double)) + { + var x = Math.Min((double)(object)left.X, (double)(object)right.X); + var y = Math.Min((double)(object)left.Y, (double)(object)right.Y); + var z = Math.Min((double)(object)left.Z, (double)(object)right.Z); + var w = Math.Min((double)(object)left.W, (double)(object)right.W); + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + + return default; + } + + public static Vector4 Max(Vector4 left, Vector4 right) + { + ThrowForUnsupportedVectorBaseType(); + + if (typeof(T) == typeof(float)) + { + var x = Math.Max((float)(object)left.X, (float)(object)right.X); + var y = Math.Max((float)(object)left.Y, (float)(object)right.Y); + var z = Math.Max((float)(object)left.Z, (float)(object)right.Z); + var w = Math.Max((float)(object)left.W, (float)(object)right.W); + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + else if (typeof(T) == typeof(double)) + { + var x = Math.Max((double)(object)left.X, (double)(object)right.X); + var y = Math.Max((double)(object)left.Y, (double)(object)right.Y); + var z = Math.Max((double)(object)left.Z, (double)(object)right.Z); + var w = Math.Max((double)(object)left.W, (double)(object)right.W); + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + + return default; + } + + public static Vector4 Normalize(Vector4 value) => value / value.Length(); + + public static Vector4 SquareRoot(Vector4 value) + { + ThrowForUnsupportedVectorBaseType(); + + if (typeof(T) == typeof(float)) + { + var x = MathF.Sqrt((float)(object)value.X); + var y = MathF.Sqrt((float)(object)value.Y); + var z = MathF.Sqrt((float)(object)value.Z); + var w = MathF.Sqrt((float)(object)value.W); + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + else if (typeof(T) == typeof(double)) + { + var x = MathF.Sqrt((double)(object)value.X); + var y = MathF.Sqrt((double)(object)value.Y); + var z = MathF.Sqrt((double)(object)value.Z); + var w = MathF.Sqrt((double)(object)value.W); + return new Vector4((T)(object)x, (T)(object)y, (T)(object)z, (T)(object)w); + } + + return default; + } + + public static Vector4 Transform(Vector4 position, Matrix4x4 matrix) + { + throw new NotImplementedException("To be implemented once Matrix4x4 is implemented"); + } + + public static Vector4 Transform(Vector4 position, Quaternion rotation) + { + throw new NotImplementedException("To be implemented once Quaternion is implemented"); + } + + // Methods + + public readonly void CopyTo(T[] array) => CopyTo(array.AsSpan()); + + public readonly void CopyTo(T[] array, int index) => CopyTo(array.AsSpan(index)); + + public readonly void CopyTo(Span destination) + { + if (destination.Length < 4) + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.destination, ExceptionResource.ArgumentOutOfRange_SmallCapacity); + } + + destination[0] = X; + destination[1] = Y; + destination[2] = Z; + destination[3] = W; + } + + public override readonly bool Equals(object? obj) => obj is Vector4 other && Equals(other); + public readonly bool Equals(Vector4 other) => this == other; + + public override readonly int GetHashCode() => HashCode.Combine(X, Y, Z, W); + + public readonly T Length() + { + if (typeof(T) == typeof(float)) + { + var squared = LengthSquared(); + return (T)(object)MathF.Sqrt((float)(object)squared); + } + else if (typeof(T) == typeof(double)) + { + var squared = LengthSquared(); + return (T)(object)Math.Sqrt((double)(object)squared); + } + + return default; + } + + public readonly T LengthSquared() => Dot(this, this); + + public readonly override string ToString() => ToString("G"); + + public readonly string ToString(string? format) => ToString(format, CultureInfo.CurrentCulture); + + public readonly string ToString(string? format, IFormatProvider? formatProvider) + { + ThrowForUnsupportedVectorBaseType(); + + static string ToString(T val, string? format, IFormatProvider? formatProvider) + { + if (typeof(T) == typeof(float)) + { + return ((float)(object)val).ToString(format, formatProvider); + } + else if (typeof(T) == typeof(double)) + { + return ((double)(object)val).ToString(format, formatProvider); + } + + return default!; + } + + StringBuilder sb = new StringBuilder(); + string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator; + sb.Append('<'); + sb.Append(ToString(X, format, formatProvider)); + sb.Append(separator); + sb.Append(' '); + sb.Append(ToString(Y, format, formatProvider)); + sb.Append(separator); + sb.Append(' '); + sb.Append(ToString(Z, format, formatProvider)); + sb.Append(separator); + sb.Append(' '); + sb.Append(ToString(W, format, formatProvider)); + sb.Append('>'); + return sb.ToString(); + } + + internal static void ThrowForUnsupportedVectorBaseType() + { + if (typeof(T) != typeof(float) && typeof(T) != typeof(double)) + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.Arg_TypeNotSupported); + } + } + } +}