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

How to adopt PolySharp to support sub arrays #104

Open
apm1grb opened this issue Jul 26, 2024 · 4 comments
Open

How to adopt PolySharp to support sub arrays #104

apm1grb opened this issue Jul 26, 2024 · 4 comments

Comments

@apm1grb
Copy link

apm1grb commented Jul 26, 2024

According to the documentation PolySharp supports "Index and Range (see indices and ranges)".

The sample of the referenced Microsoft site tries to create sub-arrays:

string[] secondThirdFourth = words[1..4];

Unfortunately, this sample gets complaints:

image

I'm confused about the generic statement regarding PolySharp's support for "Index and Range". Do I miss something?

@xilefius
Copy link

xilefius commented Aug 12, 2024

What data type is your _words ? I actually had the exact same issue. Turns our this only works on Arrays and Spans, as those are know to the compiler. I tried it with List, which works in NET5+, but not NET48 with any of the Polyfill libs.

image

Edit: Sorry, correction - I have been trying this with diverse packages as well. My tests:

  • this PolySharp package: Your error
  • Polyfill package: Same error
  • PolyShim package: Works like I described above
  • PolyKit: Your error
  • Meziantou.Polyfill: Your Error
  • No package, using https://www.meziantou.net/how-to-use-csharp-8-indices-and-ranges-in-dotnet-standard-2-0-and-dotn.htm (Look for "You can copy the implementation from this snippet" at the end, download and include that file) works. But that is only this specific part and does not work together with another polyfill package after a quick test, as the classes are then implemented twice.

I cannot say anything about the quality of the PolyShim package, which seems to be the only one where this works 🤔

Will also look more into this, but maybe this helps you :-)

@xilefius
Copy link

xilefius commented Aug 12, 2024

And one more update: Seem to work with this and the other package if you just add that missing method, I got that from the blog link I posted. You only need this class / method

namespace System.Runtime.CompilerServices
{
    internal static class RuntimeHelpers
    {
        /// <summary>
        /// Slices the specified array using the specified range.
        /// </summary>
        public static T[] GetSubArray<T>(T[] array, Range range)
        {
            if (array == null)
            {
                throw new ArgumentNullException(nameof(array));
            }

            (int offset, int length) = range.GetOffsetAndLength(array.Length);

            if (default(T) != null || typeof(T[]) == array.GetType())
            {
                // We know the type of the array to be exactly T[].

                if (length == 0)
                {
                    return Array.Empty<T>();
                }

                var dest = new T[length];
                Array.Copy(array, offset, dest, 0, length);
                return dest;
            }
            else
            {
                // The array is actually a U[] where U:T.
                var dest = (T[])Array.CreateInstance(array.GetType().GetElementType(), length);
                Array.Copy(array, offset, dest, 0, length);
                return dest;
            }
        }
    }
}

@xilefius
Copy link

Last update (for now). I modified the method a bit to be closer to the original from https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs.
I did some quick tests including casting the array to object[] etc., seems to work. Maybe this helps you :-)

Not sure what the default(T) != null is for in the previously posted version. I can only assume some shortcut for value and struct types that cannot be null and cannot be inherited. May be a quick faster with that all around, I did not benchmark this.

using System.Security.Cryptography;

namespace System.Runtime.CompilerServices
{
    internal static class RuntimeHelpers
    {
        /// <summary>
        /// Slices the specified array using the specified range.
        /// Adapted from source: https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs.
        /// Required for be able to use `array[10..20] ` syntax in .NET Standard 2.0 and net48.
        /// </summary>
        public static T[] GetSubArray<T>(T[] array, Range range)
        {
            if (array == null)
            {
                throw new ArgumentNullException(nameof(array));
            }

            (int offset, int length) = range.GetOffsetAndLength(array.Length);

            if (length == 0)
            {
                return Array.Empty<T>();
            }

            T[] dest;

            if (typeof(T[]) == array.GetType())
            {
                // We know the type of the array to be exactly T[].
                dest = new T[length];
            }
            else
            {
                // The array is actually a U[] where U:T. We'll make sure to create
                // an array of the exact same backing type. The cast to T[] will
                // never fail.
                dest = (T[])Array.CreateInstance(array.GetType().GetElementType(), length);
            }

            // In either case, the newly-allocated array is the exact same type as the
            // original incoming array. It's safe for us to Array.Copy the contents
            // from the source array to the destination array, otherwise the contents
            // wouldn't have been valid for the source array in the first place.
            Array.Copy(array, offset, dest, 0, length);
            return dest;
        }
    }
}

@rezanid
Copy link

rezanid commented Oct 10, 2024

@Sergio0694 @xilefius why not add this to the code base? ;)

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

No branches or pull requests

3 participants