Add Vector3<TLane, TNumber>
This commit is contained in:
@@ -5,10 +5,10 @@ using System.Runtime.InteropServices;
|
||||
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public readonly unsafe struct ScalarLane<T> : ISPMD<ScalarLane<T>, T>
|
||||
where T : unmanaged, INumber<T>, IMinMaxValue<T>, IBitwiseOperators<T, T, T>
|
||||
public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, TNumber>
|
||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||
{
|
||||
public readonly T value;
|
||||
public readonly TNumber value;
|
||||
|
||||
public static int LaneWidth
|
||||
{
|
||||
@@ -16,77 +16,99 @@ public readonly unsafe struct ScalarLane<T> : ISPMD<ScalarLane<T>, T>
|
||||
get => 1;
|
||||
}
|
||||
|
||||
public static ScalarLane<T> Zero
|
||||
public static ScalarLane<TNumber> Zero
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => new(T.Zero);
|
||||
get => new(TNumber.Zero);
|
||||
}
|
||||
|
||||
public static ScalarLane<T> One
|
||||
public static ScalarLane<TNumber> One
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => new(T.One);
|
||||
get => new(TNumber.One);
|
||||
}
|
||||
|
||||
public static ScalarLane<T> MinValue
|
||||
public static ScalarLane<TNumber> MinValue
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => new(T.MinValue);
|
||||
get => new(TNumber.MinValue);
|
||||
}
|
||||
|
||||
public static ScalarLane<T> MaxValue
|
||||
public static ScalarLane<TNumber> MaxValue
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => new(T.MaxValue);
|
||||
get => new(TNumber.MaxValue);
|
||||
}
|
||||
|
||||
public readonly T this[int index]
|
||||
public readonly TNumber this[int index]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => value;
|
||||
}
|
||||
|
||||
public ScalarLane(T value)
|
||||
public ScalarLane(TNumber value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Create(T value) => new(value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Create(params ReadOnlySpan<T> values) => new(values[0]);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Create(Vector<T> value) => new(value[0]);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Sequence(T start, T step) => new(start);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Load(ref T value) => new(value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Load(T* pValue) => new(*pValue);
|
||||
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly void Store(ref T destination) => destination = value;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly void Store(T* pDestination) => *pDestination = value;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int CompressStore(ScalarLane<T> mask, ref T destination)
|
||||
public static ScalarLane<TNumber> Create(TNumber value)
|
||||
{
|
||||
return CompressStore(mask, (T*)Unsafe.AsPointer(in destination));
|
||||
return new(value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int CompressStore(ScalarLane<T> mask, T* pDestination)
|
||||
public static ScalarLane<TNumber> Create(params ReadOnlySpan<TNumber> values)
|
||||
{
|
||||
if (mask.value != T.Zero)
|
||||
return new(values[0]);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> Create(Vector<TNumber> value)
|
||||
{
|
||||
return new(value[0]);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> Sequence(TNumber start, TNumber step)
|
||||
{
|
||||
return new(start);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> Load(ref TNumber value)
|
||||
{
|
||||
return new(value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> Load(TNumber* pValue)
|
||||
{
|
||||
return new(*pValue);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly void Store(ref TNumber destination)
|
||||
{
|
||||
destination = value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly void Store(TNumber* pDestination)
|
||||
{
|
||||
*pDestination = value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int CompressStore(ScalarLane<TNumber> mask, ref TNumber destination)
|
||||
{
|
||||
return CompressStore(mask, (TNumber*)Unsafe.AsPointer(in destination));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int CompressStore(ScalarLane<TNumber> mask, TNumber* pDestination)
|
||||
{
|
||||
if (mask.value != TNumber.Zero)
|
||||
{
|
||||
*pDestination = value;
|
||||
return 1;
|
||||
@@ -96,299 +118,358 @@ public readonly unsafe struct ScalarLane<T> : ISPMD<ScalarLane<T>, T>
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly Vector<T> AsVector() => Vector.Create(value);
|
||||
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator +(ScalarLane<T> a, ScalarLane<T> b) => new(a.value + b.value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator +(ScalarLane<T> a, T b) => new(a.value + b);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator -(ScalarLane<T> a, ScalarLane<T> b) => new(a.value - b.value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator -(ScalarLane<T> a, T b) => new(a.value - b);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator *(ScalarLane<T> a, ScalarLane<T> b) => new(a.value * b.value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator *(ScalarLane<T> a, T b) => new(a.value * b);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator /(ScalarLane<T> a, ScalarLane<T> b) => new(a.value / b.value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator /(ScalarLane<T> a, T b) => new(a.value / b);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator %(ScalarLane<T> a, ScalarLane<T> b) => new(a.value % b.value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator %(ScalarLane<T> a, T b) => new(a.value % b);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator -(ScalarLane<T> a) => new(-a.value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator &(ScalarLane<T> a, ScalarLane<T> b) => new(a.value & b.value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator &(ScalarLane<T> a, T b) => new(a.value & b);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator |(ScalarLane<T> a, ScalarLane<T> b) => new(a.value | b.value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator |(ScalarLane<T> a, T b) => new(a.value | b);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator ^(ScalarLane<T> a, ScalarLane<T> b) => new(a.value ^ b.value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator ^(ScalarLane<T> a, T b) => new(a.value ^ b);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> operator ~(ScalarLane<T> a) => new(~a.value);
|
||||
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Abs(ScalarLane<T> value) => new(T.Abs(value.value));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Floor(ScalarLane<T> value)
|
||||
public readonly Vector<TNumber> AsVector()
|
||||
{
|
||||
// Note: INumber<T> does not provide Floor method, so we need to handle float and double specifically.
|
||||
// This is acceptable for performance because JIT generates specialized code for each T as long as they are struct.
|
||||
// Which mean for ScalarLane<float>, typeof(T) == typeof(float) is always true and jit will optimize away the other branches.
|
||||
if (typeof(T) == typeof(float))
|
||||
return Vector.Create(value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> operator +(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(a.value + b.value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> operator -(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(a.value - b.value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> operator *(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(a.value * b.value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> operator /(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(a.value / b.value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> operator %(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(a.value % b.value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> operator -(ScalarLane<TNumber> a)
|
||||
{
|
||||
return new(-a.value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> operator &(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(a.value & b.value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> operator |(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(a.value | b.value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> operator ^(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(a.value ^ b.value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> operator ~(ScalarLane<TNumber> a)
|
||||
{
|
||||
return new(~a.value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> operator ==(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(a.value == b.value ? ~TNumber.Zero : TNumber.Zero);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> operator !=(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(a.value != b.value ? ~TNumber.Zero : TNumber.Zero);
|
||||
}
|
||||
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator ScalarLane<TNumber>(TNumber value)
|
||||
{
|
||||
return new(value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> Abs(ScalarLane<TNumber> value)
|
||||
{
|
||||
return new(TNumber.Abs(value.value));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> Floor(ScalarLane<TNumber> value)
|
||||
{
|
||||
// Note: INumber<TLane> does not provide Floor method, so we need to handle float and double specifically.
|
||||
// This is acceptable for performance because JIT generates specialized code for each TLane as long as they are struct.
|
||||
// Which mean for ScalarLane<float>, typeof(TLane) == typeof(float) is always true and jit will optimize away the other branches.
|
||||
if (typeof(TNumber) == typeof(float))
|
||||
{
|
||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
||||
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||
var result = MathF.Floor(f);
|
||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
else if (typeof(TNumber) == typeof(double))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||
var result = Math.Floor(d);
|
||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Frac(ScalarLane<T> value) => new(value.value - T.CreateTruncating(value.value));
|
||||
public static ScalarLane<TNumber> Frac(ScalarLane<TNumber> value)
|
||||
{
|
||||
return new(value.value - TNumber.CreateTruncating(value.value));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Sqrt(ScalarLane<T> value)
|
||||
public static ScalarLane<TNumber> Sqrt(ScalarLane<TNumber> value)
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
if (typeof(TNumber) == typeof(float))
|
||||
{
|
||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
||||
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||
var result = MathF.Sqrt(f);
|
||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
else if (typeof(TNumber) == typeof(double))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||
var result = Math.Sqrt(d);
|
||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Lerp(ScalarLane<T> a, ScalarLane<T> b, ScalarLane<T> t) => new(a.value + (b.value - a.value) * t.value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> MultipleAdd(ScalarLane<T> a, ScalarLane<T> b, ScalarLane<T> c) => new(T.MultiplyAddEstimate(a.value, b.value, c.value));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Min(ScalarLane<T> a, ScalarLane<T> b) => new(T.Min(a.value, b.value));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Max(ScalarLane<T> a, ScalarLane<T> b) => new(T.Max(a.value, b.value));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Clamp(ScalarLane<T> value, ScalarLane<T> min, ScalarLane<T> max) => new(T.Clamp(value.value, min.value, max.value));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Saturate(ScalarLane<T> value) => Clamp(value, new(T.Zero), new(T.One));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Sin(ScalarLane<T> value)
|
||||
public static ScalarLane<TNumber> Lerp(ScalarLane<TNumber> a, ScalarLane<TNumber> b, ScalarLane<TNumber> t)
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
return new(a.value + (b.value - a.value) * t.value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> MultipleAdd(ScalarLane<TNumber> a, ScalarLane<TNumber> b, ScalarLane<TNumber> c)
|
||||
{
|
||||
return new(TNumber.MultiplyAddEstimate(a.value, b.value, c.value));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> Min(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(TNumber.Min(a.value, b.value));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> Max(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(TNumber.Max(a.value, b.value));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> Clamp(ScalarLane<TNumber> value, ScalarLane<TNumber> min, ScalarLane<TNumber> max)
|
||||
{
|
||||
return new(TNumber.Clamp(value.value, min.value, max.value));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> Saturate(ScalarLane<TNumber> value)
|
||||
{
|
||||
return Clamp(value, new(TNumber.Zero), new(TNumber.One));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> Sin(ScalarLane<TNumber> value)
|
||||
{
|
||||
if (typeof(TNumber) == typeof(float))
|
||||
{
|
||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
||||
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||
var result = MathF.Sin(f);
|
||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
else if (typeof(TNumber) == typeof(double))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||
var result = Math.Sin(d);
|
||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Cos(ScalarLane<T> value)
|
||||
public static ScalarLane<TNumber> Cos(ScalarLane<TNumber> value)
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
if (typeof(TNumber) == typeof(float))
|
||||
{
|
||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
||||
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||
var result = MathF.Cos(f);
|
||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
else if (typeof(TNumber) == typeof(double))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||
var result = Math.Cos(d);
|
||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static (ScalarLane<T> sin, ScalarLane<T> cos) SinCos(ScalarLane<T> value) => (Sin(value), Cos(value));
|
||||
public static (ScalarLane<TNumber> sin, ScalarLane<TNumber> cos) SinCos(ScalarLane<TNumber> value)
|
||||
{
|
||||
return (Sin(value), Cos(value));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Tan(ScalarLane<T> value)
|
||||
public static ScalarLane<TNumber> Tan(ScalarLane<TNumber> value)
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
if (typeof(TNumber) == typeof(float))
|
||||
{
|
||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
||||
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||
var result = MathF.Tan(f);
|
||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
else if (typeof(TNumber) == typeof(double))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||
var result = Math.Tan(d);
|
||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Asin(ScalarLane<T> value)
|
||||
public static ScalarLane<TNumber> Asin(ScalarLane<TNumber> value)
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
if (typeof(TNumber) == typeof(float))
|
||||
{
|
||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
||||
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||
var result = MathF.Asin(f);
|
||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
else if (typeof(TNumber) == typeof(double))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||
var result = Math.Asin(d);
|
||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Acos(ScalarLane<T> value)
|
||||
public static ScalarLane<TNumber> Acos(ScalarLane<TNumber> value)
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
if (typeof(TNumber) == typeof(float))
|
||||
{
|
||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
||||
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||
var result = MathF.Acos(f);
|
||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
else if (typeof(TNumber) == typeof(double))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||
var result = Math.Acos(d);
|
||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Atan(ScalarLane<T> value)
|
||||
public static ScalarLane<TNumber> Atan(ScalarLane<TNumber> value)
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
if (typeof(TNumber) == typeof(float))
|
||||
{
|
||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
||||
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||
var result = MathF.Atan(f);
|
||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
else if (typeof(TNumber) == typeof(double))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||
var result = Math.Atan(d);
|
||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Atan2(ScalarLane<T> y, ScalarLane<T> x)
|
||||
public static ScalarLane<TNumber> Atan2(ScalarLane<TNumber> y, ScalarLane<TNumber> x)
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
if (typeof(TNumber) == typeof(float))
|
||||
{
|
||||
var fy = Unsafe.As<ScalarLane<T>, float>(ref y);
|
||||
var fx = Unsafe.As<ScalarLane<T>, float>(ref x);
|
||||
var fy = Unsafe.As<ScalarLane<TNumber>, float>(ref y);
|
||||
var fx = Unsafe.As<ScalarLane<TNumber>, float>(ref x);
|
||||
var result = MathF.Atan2(fy, fx);
|
||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
else if (typeof(TNumber) == typeof(double))
|
||||
{
|
||||
var dy = Unsafe.As<ScalarLane<T>, double>(ref y);
|
||||
var dx = Unsafe.As<ScalarLane<T>, double>(ref x);
|
||||
var dy = Unsafe.As<ScalarLane<TNumber>, double>(ref y);
|
||||
var dx = Unsafe.As<ScalarLane<TNumber>, double>(ref x);
|
||||
var result = Math.Atan2(dy, dx);
|
||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Pow(ScalarLane<T> x, ScalarLane<T> y)
|
||||
public static ScalarLane<TNumber> Pow(ScalarLane<TNumber> x, ScalarLane<TNumber> y)
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
if (typeof(TNumber) == typeof(float))
|
||||
{
|
||||
var fx = Unsafe.As<ScalarLane<T>, float>(ref x);
|
||||
var fy = Unsafe.As<ScalarLane<T>, float>(ref y);
|
||||
var fx = Unsafe.As<ScalarLane<TNumber>, float>(ref x);
|
||||
var fy = Unsafe.As<ScalarLane<TNumber>, float>(ref y);
|
||||
var result = MathF.Pow(fx, fy);
|
||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
else if (typeof(TNumber) == typeof(double))
|
||||
{
|
||||
var dx = Unsafe.As<ScalarLane<T>, double>(ref x);
|
||||
var dy = Unsafe.As<ScalarLane<T>, double>(ref y);
|
||||
var dx = Unsafe.As<ScalarLane<TNumber>, double>(ref x);
|
||||
var dy = Unsafe.As<ScalarLane<TNumber>, double>(ref y);
|
||||
var result = Math.Pow(dx, dy);
|
||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Exp(ScalarLane<T> value)
|
||||
public static ScalarLane<TNumber> Exp(ScalarLane<TNumber> value)
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
if (typeof(TNumber) == typeof(float))
|
||||
{
|
||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
||||
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||
var result = MathF.Exp(f);
|
||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
else if (typeof(TNumber) == typeof(double))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||
var result = Math.Log(d);
|
||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
|
||||
return value;
|
||||
@@ -396,167 +477,222 @@ public readonly unsafe struct ScalarLane<T> : ISPMD<ScalarLane<T>, T>
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Exp2(ScalarLane<T> value)
|
||||
public static ScalarLane<TNumber> Exp2(ScalarLane<TNumber> value)
|
||||
{
|
||||
return Pow(new ScalarLane<T>(T.CreateChecked(2)), value);
|
||||
return Pow(new ScalarLane<TNumber>(TNumber.CreateChecked(2)), value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Log(ScalarLane<T> value)
|
||||
public static ScalarLane<TNumber> Log(ScalarLane<TNumber> value)
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
if (typeof(TNumber) == typeof(float))
|
||||
{
|
||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
||||
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||
var result = MathF.Log(f);
|
||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
else if (typeof(TNumber) == typeof(double))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||
var result = Math.Log(d);
|
||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Log2(ScalarLane<T> value)
|
||||
public static ScalarLane<TNumber> Log2(ScalarLane<TNumber> value)
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
if (typeof(TNumber) == typeof(float))
|
||||
{
|
||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
||||
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||
var result = MathF.Log2(f);
|
||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
else if (typeof(TNumber) == typeof(double))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||
var result = Math.Log2(d);
|
||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Ceil(ScalarLane<T> value)
|
||||
public static ScalarLane<TNumber> Ceil(ScalarLane<TNumber> value)
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
if (typeof(TNumber) == typeof(float))
|
||||
{
|
||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
||||
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||
var result = MathF.Ceiling(f);
|
||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
else if (typeof(TNumber) == typeof(double))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||
var result = Math.Ceiling(d);
|
||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(decimal))
|
||||
else if (typeof(TNumber) == typeof(decimal))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, decimal>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, decimal>(ref value);
|
||||
var result = Math.Ceiling(d);
|
||||
return Unsafe.As<decimal, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<decimal, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Round(ScalarLane<T> value)
|
||||
public static ScalarLane<TNumber> Round(ScalarLane<TNumber> value)
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
if (typeof(TNumber) == typeof(float))
|
||||
{
|
||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
||||
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||
var result = MathF.Round(f);
|
||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
else if (typeof(TNumber) == typeof(double))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||
var result = Math.Round(d);
|
||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(decimal))
|
||||
else if (typeof(TNumber) == typeof(decimal))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, decimal>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, decimal>(ref value);
|
||||
var result = Math.Round(d);
|
||||
return Unsafe.As<decimal, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<decimal, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Trunc(ScalarLane<T> value)
|
||||
public static ScalarLane<TNumber> Trunc(ScalarLane<TNumber> value)
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
if (typeof(TNumber) == typeof(float))
|
||||
{
|
||||
var f = Unsafe.As<ScalarLane<T>, float>(ref value);
|
||||
var f = Unsafe.As<ScalarLane<TNumber>, float>(ref value);
|
||||
var result = MathF.Truncate(f);
|
||||
return Unsafe.As<float, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<float, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
else if (typeof(TNumber) == typeof(double))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, double>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, double>(ref value);
|
||||
var result = Math.Truncate(d);
|
||||
return Unsafe.As<double, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<double, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
else if (typeof(T) == typeof(decimal))
|
||||
else if (typeof(TNumber) == typeof(decimal))
|
||||
{
|
||||
var d = Unsafe.As<ScalarLane<T>, decimal>(ref value);
|
||||
var d = Unsafe.As<ScalarLane<TNumber>, decimal>(ref value);
|
||||
var result = Math.Truncate(d);
|
||||
return Unsafe.As<decimal, ScalarLane<T>>(ref result);
|
||||
return Unsafe.As<decimal, ScalarLane<TNumber>>(ref result);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Sign(ScalarLane<T> value) => new((value.value > T.Zero) ? T.One : (value.value < T.Zero) ? ~T.Zero : T.Zero);
|
||||
public static ScalarLane<TNumber> Sign(ScalarLane<TNumber> value)
|
||||
{
|
||||
return new((value.value > TNumber.Zero) ? TNumber.One : (value.value < TNumber.Zero) ? ~TNumber.Zero : TNumber.Zero);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> CopySign(ScalarLane<T> magnitude, ScalarLane<T> sign) => new(T.CopySign(magnitude.value, sign.value));
|
||||
public static ScalarLane<TNumber> CopySign(ScalarLane<TNumber> magnitude, ScalarLane<TNumber> sign)
|
||||
{
|
||||
return new(TNumber.CopySign(magnitude.value, sign.value));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Rcp(ScalarLane<T> value) => new(T.One / value.value);
|
||||
public static ScalarLane<TNumber> Rcp(ScalarLane<TNumber> value)
|
||||
{
|
||||
return new(TNumber.One / value.value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Rsqrt(ScalarLane<T> value) => Sqrt(Rcp(value));
|
||||
public static ScalarLane<TNumber> Rsqrt(ScalarLane<TNumber> value)
|
||||
{
|
||||
return Sqrt(Rcp(value));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> Select(ScalarLane<TNumber> conditionMask, ScalarLane<TNumber> ifTrue, ScalarLane<TNumber> ifFalse)
|
||||
{
|
||||
return new(conditionMask.value != TNumber.Zero ? ifTrue.value : ifFalse.value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> GreaterThan(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(a.value > b.value ? ~TNumber.Zero : TNumber.Zero);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> GreaterThanOrEqual(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(a.value >= b.value ? ~TNumber.Zero : TNumber.Zero);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> LessThan(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(a.value < b.value ? ~TNumber.Zero : TNumber.Zero);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> LessThanOrEqual(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(a.value <= b.value ? ~TNumber.Zero : TNumber.Zero);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<TNumber> Equal(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||
{
|
||||
return new(a.value == b.value ? ~TNumber.Zero : TNumber.Zero);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool Any(ScalarLane<TNumber> mask)
|
||||
{
|
||||
return mask.value != TNumber.Zero;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool All(ScalarLane<TNumber> mask)
|
||||
{
|
||||
return mask.value != TNumber.Zero;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool None(ScalarLane<TNumber> mask)
|
||||
{
|
||||
return mask.value == TNumber.Zero;
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Select(ScalarLane<T> conditionMask, ScalarLane<T> ifTrue, ScalarLane<T> ifFalse) => new(conditionMask.value != T.Zero ? ifTrue.value : ifFalse.value);
|
||||
public bool Equals(ScalarLane<TNumber> other)
|
||||
{
|
||||
return value.Equals(other.value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> GreaterThan(ScalarLane<T> a, ScalarLane<T> b) => new(a.value > b.value ? ~T.Zero : T.Zero);
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is ScalarLane<TNumber> other && value.Equals(other.value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> GreaterThanOrEqual(ScalarLane<T> a, ScalarLane<T> b) => new(a.value >= b.value ? ~T.Zero : T.Zero);
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return value.GetHashCode();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> LessThan(ScalarLane<T> a, ScalarLane<T> b) => new(a.value < b.value ? ~T.Zero : T.Zero);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> LessThanOrEqual(ScalarLane<T> a, ScalarLane<T> b) => new(a.value <= b.value ? ~T.Zero : T.Zero);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScalarLane<T> Equal(ScalarLane<T> a, ScalarLane<T> b) => new(a.value == b.value ? ~T.Zero : T.Zero);
|
||||
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool Any(ScalarLane<T> mask) => mask.value != T.Zero;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool All(ScalarLane<T> mask) => mask.value != T.Zero;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool None(ScalarLane<T> mask) => mask.value == T.Zero;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return value.ToString() ?? string.Empty;
|
||||
|
||||
Reference in New Issue
Block a user