Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

J2N.Numerics: Extended Span<char> support to net45 and netstandard2.0 #53

Merged
merged 24 commits into from
Nov 3, 2023

Conversation

NightOwl888
Copy link
Owner

@NightOwl888 NightOwl888 commented Oct 18, 2023

New APIs added for netstandard2.0 and net45 targets only

  • All Parse()/TryParse() overloads that accept ReadOnlySpan<char> on net6.0

APIs added < net6.0

namespace System
{
    public interface ISpanFormattable
    {
         bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
    }
}

New APIs

namespace J2N.Numerics
{
    public sealed class Byte
    {
        public static byte Parse(ReadOnlySpan<char> s, int radix)
        public override bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
        public static bool TryFormat(byte value, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
        public static bool TryParse(ReadOnlySpan<char> s, int radix, out byte result)
    }

    public sealed class Double
    {
        public override bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
        public static bool TryFormat(double value, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
    }

    public sealed class Int16
    {
        public static short Parse(ReadOnlySpan<char> s, int radix)
        public override bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
        public static bool TryFormat(short value, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
        public static bool TryParse(ReadOnlySpan<char> s, int radix, out short result)
    }

    public sealed class Int32
    {
        public static int Parse(ReadOnlySpan<char> s, int radix)
        public override bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
        public static bool TryFormat(int value, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
        public static bool TryParse(ReadOnlySpan<char> s, int radix, out int result)
    }

    public sealed class Int64
    {
        public static long Parse(ReadOnlySpan<char> s, int radix)
        public override bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
        public static bool TryFormat(long value, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
        public static bool TryParse(ReadOnlySpan<char> s, int radix, out long result)
    }

    public abstract class Number
    {
        public virtual bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
    }

    public sealed class SByte
    {
        public static sbyte Parse(ReadOnlySpan<char> s, int radix)
        public override bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
        public static bool TryFormat(sbyte value, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
        public static bool TryParse(ReadOnlySpan<char> s, int radix, out sbyte result)
    }

    public sealed class Single
    {
        public override bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
        public static bool TryFormat(float value, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
    }
}

New Features

  • Support AllowTypeSpecifier on integral types
    • Decimal format (base 10 - without AllowHexSpecifier) allows 'D', 'd', 'F', 'f', 'M', 'm', 'UL', 'Ul', 'uL', 'ul', 'LU', 'Lu', 'lU', or 'lu' after the number
    • Hex format (with AllowHexSpecifier) allows 'UL', 'Ul', 'uL', 'ul', 'LU', 'Lu', 'lU', or 'lu' after the number
  • Extended support for AllowTypeSpecifier on decimal types to include 'UL', 'Ul', 'uL', 'ul', 'LU', 'Lu', 'lU', or 'lu' after the number in addition to 'D', 'd', 'F', 'f', 'M', and 'm'
  • Adds a dependency on System.Memory for netstandard2.0 and net45 (primarily to allow Span<T> and ReadOnlySpan<T> support)

Optimizations

  • ValueStringBuilder ported from .NET 6.0 to replace StringBuilder in number formatters
  • Re-added unsafe pointers that were in the original .NET 6.0 formatters

Code Cleanup

  • Removes FEATURE_READONLYSPAN and normalizes all of the code to use FEATURE_SPAN

…ulture for basic tests to eliminate issues with localized negative symbols.
…hat were in the original dotnet runtime code to reduce allocations
…ariant culture for basic tests to eliminate issues with localized negative symbols."

This reverts commit c20e909.
…r all number types and tests"

This reverts commit 8a1255f.
…an casting to ReadOnlySpan<char> to support netstandard2.0 and net45
…latforms that don't support ReadOnlySpan<char> on Parse/TryParse methods.
…ixed conditional compilation issues that made the code less than optimal on modern platforms
…han passing the task to .NET"

This reverts commit c6ffa1d.
…han passing the task to the BCL. This allows us to support ReadOnlySpan<char> in net45 and netstandard2.0 without performance degradation.
…g(): Use ValueStringBuilder when supported to reduce heap allocations
…l formatting code from DoubleExtensions and SingleExtensions. Refactored to allow a TryFormat version.
…se with raw float and double data types + tests
…riginal code from dotnet runtime + adapted Harmony tests to call them
…irtual with a substandard (but functional) implementation that can be overridden. Made all TryFormat() methods public and added documentation.
…. Added support for parsing both integral type and real type specifiers into any data type (for decimal numbers only). Added support for parsing hexadecimal numbers with prefix "0x". Updated inline docs.
…char> and radix (without startIndex and length) + tests
@NightOwl888 NightOwl888 merged commit 2657215 into main Nov 3, 2023
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant