Remove almost all allocations from F3 menu. (#2923)

This commit is contained in:
Pieter-Jan Briers
2022-06-10 12:59:43 +02:00
committed by GitHub
parent 8d5fa58e1a
commit 776669b789
32 changed files with 784 additions and 125 deletions

View File

@@ -1,5 +1,6 @@
using System;
using JetBrains.Annotations;
using Robust.Shared.Utility;
namespace Robust.Shared.Maths
{
@@ -7,7 +8,7 @@ namespace Robust.Shared.Maths
/// A representation of an angle, in radians.
/// </summary>
[Serializable]
public readonly struct Angle : IApproxEquatable<Angle>, IEquatable<Angle>
public readonly struct Angle : IApproxEquatable<Angle>, IEquatable<Angle>, ISpanFormattable
{
public static Angle Zero { get; } = new();
@@ -291,5 +292,22 @@ namespace Robust.Shared.Maths
{
return $"{Theta} rad";
}
public string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"{Theta} rad");
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Robust.Shared.Utility;
namespace Robust.Shared.Maths
{
@@ -10,7 +11,7 @@ namespace Robust.Shared.Maths
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Explicit)]
public struct Box2 : IEquatable<Box2>, IApproxEquatable<Box2>
public struct Box2 : IEquatable<Box2>, IApproxEquatable<Box2>, ISpanFormattable
{
/// <summary>
/// The X coordinate of the left edge of the box.
@@ -310,11 +311,28 @@ namespace Robust.Shared.Maths
return !(a == b);
}
public override string ToString()
public readonly override string ToString()
{
return $"({Left}, {Bottom}, {Right}, {Top})";
}
public readonly string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public readonly bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"({Left}, {Bottom}, {Right}, {Top})");
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Area(in Box2 box)
=> box.Width * box.Height;

View File

@@ -2,6 +2,7 @@ using System;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
using Robust.Shared.Utility;
namespace Robust.Shared.Maths
{
@@ -9,7 +10,7 @@ namespace Robust.Shared.Maths
/// This type contains a <see cref="Box2"/> and a rotation <see cref="Angle"/> in world space.
/// </summary>
[Serializable]
public struct Box2Rotated : IEquatable<Box2Rotated>
public struct Box2Rotated : IEquatable<Box2Rotated>, ISpanFormattable
{
public Box2 Box;
public Angle Rotation;
@@ -214,7 +215,24 @@ namespace Robust.Shared.Maths
/// </summary>
public override readonly string ToString()
{
return $"{Box.ToString()}, {Rotation.ToString()}";
return $"{Box}, {Rotation}";
}
public readonly string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public readonly bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"{Box}, {Rotation}");
}
}
}

View File

@@ -1,12 +1,13 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Robust.Shared.Utility;
namespace Robust.Shared.Maths
{
[Serializable]
[StructLayout(LayoutKind.Explicit)]
public struct Box2i : IEquatable<Box2i>
public struct Box2i : IEquatable<Box2i>, ISpanFormattable
{
[FieldOffset(sizeof(int) * 0)] public int Left;
[FieldOffset(sizeof(int) * 1)] public int Bottom;
@@ -136,6 +137,23 @@ namespace Robust.Shared.Maths
return $"({Left}, {Bottom}, {Right}, {Top})";
}
public readonly string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public readonly bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"({Left}, {Bottom}, {Right}, {Top})");
}
/// <summary>
/// Multiplies each side of the box by the scalar.
/// </summary>

View File

@@ -1,4 +1,5 @@
using System;
using Robust.Shared.Utility;
namespace Robust.Shared.Maths
{
@@ -6,7 +7,7 @@ namespace Robust.Shared.Maths
/// Represents a circle with a 2D position and a radius.
/// </summary>
[Serializable]
public struct Circle : IEquatable<Circle>
public struct Circle : IEquatable<Circle>, ISpanFormattable
{
/// <summary>
/// Position of the circle in 2D space.
@@ -108,5 +109,22 @@ namespace Robust.Shared.Maths
{
return $"Circle ({Position.X}, {Position.Y}), {Radius} r";
}
public readonly string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public readonly bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"Circle ({Position.X}, {Position.Y}), {Radius} r");
}
}
}

View File

@@ -31,6 +31,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Xml.Linq;
using JetBrains.Annotations;
using Robust.Shared.Utility;
using SysVector3 = System.Numerics.Vector3;
using SysVector4 = System.Numerics.Vector4;
@@ -46,7 +47,7 @@ namespace Robust.Shared.Maths
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Color : IEquatable<Color>
public struct Color : IEquatable<Color>, ISpanFormattable
{
/// <summary>
/// The red component of this Color4 structure.
@@ -239,6 +240,23 @@ namespace Robust.Shared.Maths
return $"{{(R, G, B, A) = ({R}, {G}, {B}, {A})}}";
}
public readonly string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public readonly bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"{{(R, G, B, A) = ({R}, {G}, {B}, {A})}}");
}
public readonly Color WithRed(float newR)
{
return new(newR, G, B, A);

View File

@@ -0,0 +1,203 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Text;
// Leaving this in this namespace because I only need this class here to work around maths being a separate assembly.
// ReSharper disable once CheckNamespace
namespace Robust.Shared.Utility;
/// <summary>
/// Helpers for dealing with string formatting and related things.
/// </summary>
public static class FormatHelpers
{
/// <summary>
/// Format a string interpolation into a given buffer. If the buffer is not large enough, the result is truncated.
/// </summary>
/// <remarks>
/// Assuming everything you're formatting with implements <see cref="ISpanFormattable"/>, this should be zero-alloc.
/// </remarks>
/// <param name="buffer">The buffer to format into.</param>
/// <param name="handler">String interpolation handler to implement buffer formatting logic.</param>
/// <returns>The amount of chars written into the buffer.</returns>
public static int FormatInto(
Span<char> buffer,
[InterpolatedStringHandlerArgument("buffer")] ref BufferInterpolatedStringHandler handler)
{
return handler.Length;
}
/// <summary>
/// Tries to format a string interpolation into a given buffer.
/// If the buffer is not large enough, the result is truncated.
/// </summary>
/// <remarks>
/// <para>
/// This is intended to be used as an easy implementation of <see cref="ISpanFormattable"/>.
/// </para>
/// <para>
/// Assuming everything you're formatting with implements <see cref="ISpanFormattable"/>,
/// this should be zero-alloc on release.
/// </para>
/// </remarks>
/// <param name="buffer">The buffer to format into.</param>
/// <param name="charsWritten">The amount of chars written into the buffer.</param>
/// <param name="handler">String interpolation handler to implement buffer formatting logic.</param>
/// <returns>False if the formatting failed due to lack of space and was truncated.</returns>
public static bool TryFormatInto(
Span<char> buffer,
out int charsWritten,
[InterpolatedStringHandlerArgument("buffer")] ref BufferInterpolatedStringHandler handler)
{
charsWritten = handler.Length;
return !handler.Truncated;
}
/// <summary>
/// Format a string interpolation into a given memory buffer.
/// If the buffer is not large enough, the result is truncated.
/// </summary>
/// <param name="buffer">The memory buffer to format into.</param>
/// <param name="handler">String interpolation handler to implement buffer formatting logic.</param>
/// <returns>The region of memory filled by the formatting operation.</returns>
public static Memory<char> FormatIntoMem(
Memory<char> buffer,
[InterpolatedStringHandlerArgument("buffer")] ref MemoryBufferInterpolatedStringHandler handler)
{
return buffer[..handler.Handler.Length];
}
/// <summary>
/// Copy the contents of a <see cref="StringBuilder"/> into a memory buffer, giving back the subregion used.
/// If the buffer is not enough space, the result is truncated.
/// </summary>
/// <param name="builder">The <see cref="StringBuilder"/> to copy from</param>
/// <param name="memory">The memory buffer to copy into.</param>
/// <returns>The memory region actually used by the copied data.</returns>
public static Memory<char> BuilderToMemory(StringBuilder builder, Memory<char> memory)
{
var truncLength = Math.Min(builder.Length, memory.Length);
builder.CopyTo(0, memory.Span, truncLength);
return memory[..builder.Length];
}
}
/// <summary>
/// Interpolated string handler used by <see cref="FormatHelpers.FormatInto"/>.
/// </summary>
[InterpolatedStringHandler]
public ref struct BufferInterpolatedStringHandler
{
private Span<char> _buffer;
internal int Length;
internal bool Truncated;
[SuppressMessage("ReSharper", "UnusedParameter.Local")]
public BufferInterpolatedStringHandler(int literalLength, int formattedCount, Span<char> buffer)
{
_buffer = buffer;
Length = 0;
Truncated = false;
}
public void AppendLiteral(string literal)
{
AppendString(literal);
}
public void AppendFormatted(ReadOnlySpan<char> value)
{
AppendString(value);
}
[SuppressMessage("ReSharper", "MergeCastWithTypeCheck")]
public void AppendFormatted<T>(T value)
{
if (value is ISpanFormattable)
{
// JIT is able to avoid boxing due to call structure.
((ISpanFormattable)value).TryFormat(_buffer, out var written, default, null);
Advance(written);
return;
}
var str = value?.ToString();
if (str != null)
AppendString(str);
}
[SuppressMessage("ReSharper", "MergeCastWithTypeCheck")]
public void AppendFormatted<T>(T value, string format)
{
string? str;
if (value is IFormattable)
{
if (value is ISpanFormattable)
{
// JIT is able to avoid boxing due to call structure.
Truncated |= !((ISpanFormattable)value).TryFormat(_buffer, out var written, format, null);
Advance(written);
return;
}
// JIT is able to avoid boxing due to call structure.
str = ((IFormattable)value).ToString(format, null);
}
else
{
str = value?.ToString();
}
if (str != null)
AppendString(str);
}
private void AppendString(ReadOnlySpan<char> value)
{
var copyLength = value.Length;
if (copyLength > _buffer.Length)
{
copyLength = _buffer.Length;
Truncated = true;
}
value[..copyLength].CopyTo(_buffer);
Advance(copyLength);
}
private void Advance(int amount)
{
_buffer = _buffer[amount..];
Length += amount;
}
}
/// <summary>
/// Interpolated string handler used by <see cref="FormatHelpers.FormatIntoMem"/>.
/// </summary>
/// <remarks>
/// Only exists as workaround for https://youtrack.jetbrains.com/issue/RIDER-78472.
/// </remarks>
[InterpolatedStringHandler]
public ref struct MemoryBufferInterpolatedStringHandler
{
public BufferInterpolatedStringHandler Handler;
public MemoryBufferInterpolatedStringHandler(int literalLength, int formattedCount, Memory<char> buffer)
{
Handler = new BufferInterpolatedStringHandler(literalLength, formattedCount, buffer.Span);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AppendLiteral(string literal) => Handler.AppendLiteral(literal);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AppendFormatted(ReadOnlySpan<char> value) => Handler.AppendFormatted(value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AppendFormatted<T>(T value) => Handler.AppendFormatted(value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AppendFormatted<T>(T value, string format) => Handler.AppendFormatted(value, format);
}

View File

@@ -29,12 +29,13 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
using Robust.Shared.Utility;
namespace Robust.Shared.Maths
{
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Matrix3 : IEquatable<Matrix3>, IApproxEquatable<Matrix3>
public struct Matrix3 : IEquatable<Matrix3>, IApproxEquatable<Matrix3>, ISpanFormattable
{
#region Fields & Access
@@ -1225,6 +1226,25 @@ namespace Robust.Shared.Maths
+ $"|{R2C0}, {R2C1}, {R2C2}|\n";
}
public readonly string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public readonly bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"|{R0C0}, {R0C1}, {R0C2}|\n"
+ $"|{R1C0}, {R1C1}, {R1C2}|\n"
+ $"|{R2C0}, {R2C1}, {R2C2}|\n");
}
#endregion String
}
#pragma warning restore 3019

View File

@@ -28,6 +28,7 @@ SOFTWARE.
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Robust.Shared.Utility;
namespace Robust.Shared.Maths
{
@@ -36,7 +37,7 @@ namespace Robust.Shared.Maths
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Matrix4 : IEquatable<Matrix4>
public struct Matrix4 : IEquatable<Matrix4>, ISpanFormattable
{
#region Fields
@@ -1160,11 +1161,28 @@ namespace Robust.Shared.Maths
/// Returns a System.String that represents the current Matrix44.
/// </summary>
/// <returns></returns>
public override string ToString()
public readonly override string ToString()
{
return $"{Row0}\n{Row1}\n{Row2}\n{Row3}";
}
public readonly string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public readonly bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"{Row0}\n{Row1}\n{Row2}\n{Row3}");
}
#endregion public override string ToString()
#region public override int GetHashCode()

View File

@@ -29,6 +29,7 @@ using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Xml.Serialization;
using Robust.Shared.Utility;
namespace Robust.Shared.Maths
{
@@ -37,7 +38,7 @@ namespace Robust.Shared.Maths
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Quaternion : IEquatable<Quaternion>
public struct Quaternion : IEquatable<Quaternion>, ISpanFormattable
{
#region Fields
@@ -903,9 +904,26 @@ namespace Robust.Shared.Maths
/// Returns a System.String that represents the current Quaternion.
/// </summary>
/// <returns></returns>
public override string ToString()
public readonly override string ToString()
{
return $"V: {Xyz}, W: {W}";
return $"V: {xyz}, W: {w}";
}
public readonly string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public readonly bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"V: {xyz}, W: {w}");
}
#endregion public override string ToString()

View File

@@ -1,11 +1,12 @@
using System;
using System.Diagnostics.CodeAnalysis;
using JetBrains.Annotations;
using Robust.Shared.Utility;
namespace Robust.Shared.Maths
{
[PublicAPI]
public struct Thickness : IEquatable<Thickness>
public struct Thickness : IEquatable<Thickness>, ISpanFormattable
{
public float Left;
public float Top;
@@ -108,11 +109,29 @@ namespace Robust.Shared.Maths
return !left.Equals(in right);
}
public override string ToString()
public readonly override string ToString()
{
return $"{Left},{Top},{Right},{Bottom}";
}
public readonly string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public readonly bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"{Left},{Top},{Right},{Bottom}");
}
public readonly void Deconstruct(out float left, out float top, out float right, out float bottom)
{
left = Left;

View File

@@ -1,6 +1,7 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Robust.Shared.Utility;
namespace Robust.Shared.Maths
{
@@ -10,7 +11,7 @@ namespace Robust.Shared.Maths
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Explicit)]
public struct UIBox2 : IEquatable<UIBox2>
public struct UIBox2 : IEquatable<UIBox2>, ISpanFormattable
{
/// <summary>
/// The X coordinate of the left edge of the box.
@@ -181,5 +182,22 @@ namespace Robust.Shared.Maths
{
return $"({Left}, {Top}, {Right}, {Bottom})";
}
public readonly string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public readonly bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"({Left}, {Top}, {Right}, {Bottom})");
}
}
}

View File

@@ -1,12 +1,13 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Robust.Shared.Utility;
namespace Robust.Shared.Maths
{
[Serializable]
[StructLayout(LayoutKind.Explicit)]
public struct UIBox2i : IEquatable<UIBox2i>
public struct UIBox2i : IEquatable<UIBox2i>, ISpanFormattable
{
[FieldOffset(sizeof(int) * 0)] public int Left;
[FieldOffset(sizeof(int) * 1)] public int Top;
@@ -145,5 +146,22 @@ namespace Robust.Shared.Maths
{
return $"({Left}, {Top}, {Right}, {Bottom})";
}
public readonly string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public readonly bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"({Left}, {Top}, {Right}, {Bottom})");
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Robust.Shared.Utility;
namespace Robust.Shared.Maths
{
@@ -9,7 +10,7 @@ namespace Robust.Shared.Maths
/// </summary>
[StructLayout(LayoutKind.Sequential)]
[Serializable]
public struct Vector2 : IEquatable<Vector2>, IApproxEquatable<Vector2>
public struct Vector2 : IEquatable<Vector2>, IApproxEquatable<Vector2>, ISpanFormattable
{
/// <summary>
/// The X component of the vector.
@@ -382,6 +383,23 @@ namespace Robust.Shared.Maths
return $"({X}, {Y})";
}
public readonly string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public readonly bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"({X}, {Y})");
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vector2 a, Vector2 b)
{

View File

@@ -1,13 +1,14 @@
using System;
using System.Runtime.InteropServices;
using System.Text.Json.Serialization;
using Robust.Shared.Utility;
namespace Robust.Shared.Maths
{
[Serializable]
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct Vector2i : IEquatable<Vector2i>
public struct Vector2i : IEquatable<Vector2i>, ISpanFormattable
{
public static readonly Vector2i Zero = (0, 0);
public static readonly Vector2i One = (1, 1);
@@ -170,5 +171,22 @@ namespace Robust.Shared.Maths
{
return $"({X}, {Y})";
}
public string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"({X}, {Y})");
}
}
}

View File

@@ -29,6 +29,7 @@ using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Xml.Serialization;
using Robust.Shared.Utility;
namespace Robust.Shared.Maths
{
@@ -40,7 +41,7 @@ namespace Robust.Shared.Maths
/// </remarks>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Vector3 : IEquatable<Vector3>
public struct Vector3 : IEquatable<Vector3>, ISpanFormattable
{
#region Fields
@@ -1130,11 +1131,28 @@ namespace Robust.Shared.Maths
/// Returns a System.String that represents the current Vector3.
/// </summary>
/// <returns></returns>
public override string ToString()
public readonly override string ToString()
{
return $"({X}, {Y}, {Z})";
}
public readonly string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public readonly bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"({X}, {Y}, {Z})");
}
#endregion
#region public override int GetHashCode()

View File

@@ -28,6 +28,7 @@ using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Xml.Serialization;
using Robust.Shared.Utility;
namespace Robust.Shared.Maths
{
@@ -37,7 +38,7 @@ namespace Robust.Shared.Maths
/// </remarks>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Vector4 : IEquatable<Vector4>
public struct Vector4 : IEquatable<Vector4>, ISpanFormattable
{
#region Fields
@@ -911,11 +912,28 @@ namespace Robust.Shared.Maths
/// Returns a System.String that represents the current Vector4.
/// </summary>
/// <returns></returns>
public override string ToString()
public readonly override string ToString()
{
return $"({X}, {Y}, {Z}, {W})";
}
public readonly string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
public readonly bool TryFormat(
Span<char> destination,
out int charsWritten,
ReadOnlySpan<char> format,
IFormatProvider? provider)
{
return FormatHelpers.TryFormatInto(
destination,
out charsWritten,
$"({X}, {Y}, {Z}, {W})");
}
#endregion public override string ToString()
#region public override int GetHashCode()