// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
#if NETSTANDARD
using System.Runtime.InteropServices;
#endif
using CommunityToolkit.HighPerformance.Enumerables;
using CommunityToolkit.HighPerformance.Helpers.Internals;
namespace CommunityToolkit.HighPerformance;
///
/// Helpers for working with the type.
///
public static class StringExtensions
{
///
/// Returns a reference to the first element within a given , with no bounds checks.
///
/// The input instance.
/// A reference to the first element within , or the location it would have used, if is empty.
/// This method doesn't do any bounds checks, therefore it is responsibility of the caller to perform checks in case the returned value is dereferenced.
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref char DangerousGetReference(this string text)
{
#if NETCOREAPP3_1_OR_GREATER
return ref Unsafe.AsRef(text.GetPinnableReference());
#else
return ref MemoryMarshal.GetReference(text.AsSpan());
#endif
}
///
/// Returns a reference to an element at a specified index within a given , with no bounds checks.
///
/// The input instance.
/// The index of the element to retrieve within .
/// A reference to the element within at the index specified by .
/// This method doesn't do any bounds checks, therefore it is responsibility of the caller to ensure the parameter is valid.
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref char DangerousGetReferenceAt(this string text, int i)
{
#if NETCOREAPP3_1_OR_GREATER
ref char r0 = ref Unsafe.AsRef(text.GetPinnableReference());
#else
ref char r0 = ref MemoryMarshal.GetReference(text.AsSpan());
#endif
ref char ri = ref Unsafe.Add(ref r0, (nint)(uint)i);
return ref ri;
}
///
/// Counts the number of occurrences of a given character into a target instance.
///
/// The input instance to read.
/// The character to look for.
/// The number of occurrences of in .
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Count(this string text, char c)
{
ref char r0 = ref text.DangerousGetReference();
nint length = (nint)(uint)text.Length;
return (int)SpanHelper.Count(ref r0, length, c);
}
///
/// Enumerates the items in the input instance, as pairs of value/index values.
/// This extension should be used directly within a loop:
///
/// string text = "Hello, world!";
///
/// foreach (var item in text.Enumerate())
/// {
/// // Access the index and value of each item here...
/// int index = item.Index;
/// char value = item.Value;
/// }
///
/// The compiler will take care of properly setting up the loop with the type returned from this method.
///
/// The source to enumerate.
/// A wrapper type that will handle the value/index enumeration for .
/// The returned value shouldn't be used directly: use this extension in a loop.
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpanEnumerable Enumerate(this string text)
{
return new(text.AsSpan());
}
///
/// Tokenizes the values in the input instance using a specified separator.
/// This extension should be used directly within a loop:
///
/// string text = "Hello, world!";
///
/// foreach (var token in text.Tokenize(','))
/// {
/// // Access the tokens here...
/// }
///
/// The compiler will take care of properly setting up the loop with the type returned from this method.
///
/// The source to tokenize.
/// The separator character to use.
/// A wrapper type that will handle the tokenization for .
/// The returned value shouldn't be used directly: use this extension in a loop.
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpanTokenizer Tokenize(this string text, char separator)
{
return new(text.AsSpan(), separator);
}
///
/// Gets a content hash from the input instance using the Djb2 algorithm.
/// For more info, see the documentation for .
///
/// The source to enumerate.
/// The Djb2 value for the input instance.
/// The Djb2 hash is fully deterministic and with no random components.
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe int GetDjb2HashCode(this string text)
{
ref char r0 = ref text.DangerousGetReference();
nint length = (nint)(uint)text.Length;
return SpanHelper.GetDjb2HashCode(ref r0, length);
}
}