Edytuj

Udostępnij za pośrednictwem


ReadOnlySpanExtensions Class

Definition

Helpers for working with the ReadOnlySpan<T> type.

public static class ReadOnlySpanExtensions
type ReadOnlySpanExtensions = class
Public Module ReadOnlySpanExtensions
Inheritance
ReadOnlySpanExtensions

Methods

AsBytes<T>(ReadOnlySpan<T>)

Casts a ReadOnlySpan<T> of one primitive type T to ReadOnlySpan<T> of bytes.

AsSpan2D<T>(ReadOnlySpan<T>, Int32, Int32, Int32, Int32)

Returns a ReadOnlySpan2D<T> instance wrapping the underlying data for the given ReadOnlySpan<T> instance.

AsSpan2D<T>(ReadOnlySpan<T>, Int32, Int32)

Returns a ReadOnlySpan2D<T> instance wrapping the underlying data for the given ReadOnlySpan<T> instance.

Cast<TFrom,TTo>(ReadOnlySpan<TFrom>)

Casts a ReadOnlySpan<T> of one primitive type TFrom to another primitive type TTo.

CopyTo<T>(ReadOnlySpan<T>, RefEnumerable<T>)

Copies the contents of a given ReadOnlySpan<T> into destination RefEnumerable<T> instance.

Count<T>(ReadOnlySpan<T>, T)

Counts the number of occurrences of a given value into a target ReadOnlySpan<T> instance.

DangerousGetLookupReferenceAt<T>(ReadOnlySpan<T>, Int32)

Returns a reference to the first element within a given ReadOnlySpan<T>, clamping the input index in the valid range. If the i parameter exceeds the length of span, it will be clamped to 0. Therefore, the returned reference will always point to a valid element within span, assuming it is not empty. This method is specifically meant to efficiently index lookup tables, especially if they point to constant data. Consider this example where a lookup table is used to validate whether a given character is within a specific set:

public static ReadOnlySpan<bool> ValidSetLookupTable => new bool[]
{
    false, true, true, true, true, true, false, true,
    false, false, true, false, true, false, true, false,
    true, false, false, true, false, false, false, false,
    false, false, false, false, true, true, false, true
};

int ch = Console.Read();
bool isValid = ValidSetLookupTable.DangerousGetLookupReference(ch);

Even if the input index is outside the range of the lookup table, being clamped to 0, it will just cause the value 0 to be returned in this case, which is functionally the same for the check being performed. This extension can easily be used whenever the first position in a lookup table being referenced corresponds to a falsey value, like in this case. Additionally, the example above leverages a compiler optimization introduced with C# 7.3, which allows ReadOnlySpan<T> instances pointing to compile-time constant data to be directly mapped to the static .text section in the final assembly: the array being created in code will never actually be allocated, and the ReadOnlySpan<T> will just point to constant data. Note that this only works for blittable values that are not dependent on the byte endianness of the system, like Byte or Boolean. For more info, see https://vcsjones.dev/2019/02/01/csharp-readonly-span-bytes-static/.

DangerousGetReference<T>(ReadOnlySpan<T>)

Returns a reference to the first element within a given ReadOnlySpan<T>, with no bounds checks.

DangerousGetReferenceAt<T>(ReadOnlySpan<T>, Int32)

Returns a reference to an element at a specified index within a given ReadOnlySpan<T>, with no bounds checks.

DangerousGetReferenceAt<T>(ReadOnlySpan<T>, IntPtr)

Returns a reference to an element at a specified index within a given ReadOnlySpan<T>, with no bounds checks.

Enumerate<T>(ReadOnlySpan<T>)

Enumerates the items in the input ReadOnlySpan<T> instance, as pairs of value/index values. This extension should be used directly within a foreach loop:

ReadOnlySpan<string> words = new[] { "Hello", ", ", "world", "!" };

foreach (var item in words.Enumerate())
{
    // Access the index and value of each item here...
    int index = item.Index;
    string value = item.Value;
}

The compiler will take care of properly setting up the foreach loop with the type returned from this method.

GetDjb2HashCode<T>(ReadOnlySpan<T>)

Gets a content hash from the input ReadOnlySpan<T> instance using the Djb2 algorithm. It was designed by Daniel J. Bernstein and is a non-cryptographic has function. The main advantages of this algorithm are a good distribution of the resulting hash codes, which results in a relatively low number of collisions, while at the same time being particularly fast to process, making it suitable for quickly hashing even long sequences of values. For the reference implementation, see: http://www.cse.yorku.ca/~oz/hash.html. For details on the used constants, see the details provided in this StackOverflow answer (as well as the accepted one): https://stackoverflow.com/questions/10696223/reason-for-5381-number-in-djb-hash-function/13809282#13809282. Additionally, a comparison between some common hashing algorithms can be found in the reply to this StackExchange question: https://softwareengineering.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed. Note that the exact implementation is slightly different in this method when it is not called on a sequence of Byte values: in this case the GetHashCode() method will be invoked for each T value in the provided ReadOnlySpan<T> instance, and then those values will be combined using the Djb2 algorithm.

IndexOf<T>(ReadOnlySpan<T>, T)

Gets the index of an element of a given ReadOnlySpan<T> from its reference.

Tokenize<T>(ReadOnlySpan<T>, T)

Tokenizes the values in the input ReadOnlySpan<T> instance using a specified separator. This extension should be used directly within a foreach loop:

ReadOnlySpan<char> text = "Hello, world!";

foreach (var token in text.Tokenize(','))
{
    // Access the tokens here...
}

The compiler will take care of properly setting up the foreach loop with the type returned from this method.

TryCopyTo<T>(ReadOnlySpan<T>, RefEnumerable<T>)

Attempts to copy the contents of a given ReadOnlySpan<T> into destination RefEnumerable<T> instance.

Applies to