using System;
using Unity.Collections.LowLevel.Unsafe;
namespace Unity.Collections
{
///
/// Provides extension methods for FixedString*N*.
///
[BurstCompatible]
public unsafe static partial class FixedStringMethods
{
///
/// Returns the index of the first occurrence of a byte sequence in this string.
///
/// A FixedString*N* type.
/// A string to search.
/// A byte sequence to search for within this string.
/// The number of bytes in the byte sequence.
/// The index of the first occurrence of the byte sequence in this string. Returns -1 if no occurrence is found.
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
public static int IndexOf(ref this T fs, byte* bytes, int bytesLen)
where T : struct, INativeList, IUTF8Bytes
{
var dst = fs.GetUnsafePtr();
var dstLen = fs.Length;
for (var i = 0; i <= dstLen - bytesLen; ++i)
{
for (var j = 0; j < bytesLen; ++j)
if (dst[i + j] != bytes[j])
goto end_of_loop;
return i;
end_of_loop : {}
}
return -1;
}
///
/// Returns the index of the first occurrence of a byte sequence within a subrange of this string.
///
/// A FixedString*N* type.
/// A string to search.
/// A byte sequence to search for within this string.
/// The number of bytes in the byte sequence.
/// The first index in this string to consider as the first byte of the byte sequence.
/// The last index in this string to consider as the first byte of the byte sequence.
/// The index of the first occurrence of the byte sequence in this string. Returns -1 if no occurrence is found.
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
public static int IndexOf(ref this T fs, byte* bytes, int bytesLen, int startIndex, int distance = Int32.MaxValue)
where T : struct, INativeList, IUTF8Bytes
{
var dst = fs.GetUnsafePtr();
var dstLen = fs.Length;
var searchrange = Math.Min(distance - 1, dstLen - bytesLen);
for (var i = startIndex; i <= searchrange; ++i)
{
for (var j = 0; j < bytesLen; ++j)
if (dst[i + j] != bytes[j])
goto end_of_loop;
return i;
end_of_loop : {}
}
return -1;
}
///
/// Returns the index of the first occurrence of a substring within this string.
///
/// A FixedString*N* type.
/// A FixedString*N* type.
/// A string to search.
/// A substring to search for within this string.
/// The index of the first occurrence of the second string within this string. Returns -1 if no occurrence is found.
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
public static int IndexOf(ref this T fs, in T2 other)
where T : struct, INativeList, IUTF8Bytes
where T2 : struct, INativeList, IUTF8Bytes
{
ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
return fs.IndexOf(oref.GetUnsafePtr(), oref.Length);
}
///
/// Returns the index of the first occurrence of a substring within a subrange of this string.
///
/// A FixedString*N* type.
/// A FixedString*N* type.
/// A string to search.
/// A substring to search for within this string.
/// The first index in this string to consider as an occurrence of the second string.
/// The last index in this string to consider as an occurrence of the second string.
/// The index of the first occurrence of the substring within this string. Returns -1 if no occurrence is found.
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
public static int IndexOf(ref this T fs, in T2 other, int startIndex, int distance = Int32.MaxValue)
where T : struct, INativeList, IUTF8Bytes
where T2 : struct, INativeList, IUTF8Bytes
{
ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
return fs.IndexOf(oref.GetUnsafePtr(), oref.Length, startIndex, distance);
}
///
/// Returns true if a given substring occurs within this string.
///
/// A FixedString*N* type.
/// A FixedString*N* type.
/// A string to search.
/// A substring to search for within this string.
/// True if the substring occurs within this string.
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
public static bool Contains(ref this T fs, in T2 other)
where T : struct, INativeList, IUTF8Bytes
where T2 : struct, INativeList, IUTF8Bytes
{
return fs.IndexOf(in other) != -1;
}
///
/// Returns the index of the last occurrence of a byte sequence within this string.
///
/// A FixedString*N* type.
/// A string to search.
/// A byte sequence to search for within this string.
/// The number of bytes in the byte sequence.
/// The index of the last occurrence of the byte sequence within this string. Returns -1 if no occurrence is found.
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
public static int LastIndexOf(ref this T fs, byte* bytes, int bytesLen)
where T : struct, INativeList, IUTF8Bytes
{
var dst = fs.GetUnsafePtr();
var dstLen = fs.Length;
for (var i = dstLen - bytesLen; i >= 0; --i)
{
for (var j = 0; j < bytesLen; ++j)
if (dst[i + j] != bytes[j])
goto end_of_loop;
return i;
end_of_loop : {}
}
return -1;
}
///
/// Returns the index of the last occurrence of a byte sequence within a subrange of this string.
///
/// A FixedString*N* type.
/// A string to search.
/// A byte sequence to search for within this string.
/// The number of bytes in the byte sequence.
/// The smallest index in this string to consider as the first byte of the byte sequence.
/// The greatest index in this string to consider as the first byte of the byte sequence.
/// The index of the last occurrence of the byte sequence within this string. Returns -1 if no occurrences found.
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
public static int LastIndexOf(ref this T fs, byte* bytes, int bytesLen, int startIndex, int distance = int.MaxValue)
where T : struct, INativeList, IUTF8Bytes
{
var dst = fs.GetUnsafePtr();
var dstLen = fs.Length;
startIndex = Math.Min(dstLen - bytesLen, startIndex);
var searchrange = Math.Max(0, startIndex - distance);
for (var i = startIndex; i >= searchrange; --i)
{
for (var j = 0; j < bytesLen; ++j)
if (dst[i + j] != bytes[j])
goto end_of_loop;
return i;
end_of_loop : {}
}
return -1;
}
///
/// Returns the index of the last occurrence of a substring within this string.
///
/// A FixedString*N* type.
/// A FixedString*N* type.
/// A string to search.
/// A substring to search for in the this string.
/// The index of the last occurrence of the substring within this string. Returns -1 if no occurrence is found.
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
public static int LastIndexOf(ref this T fs, in T2 other)
where T : struct, INativeList, IUTF8Bytes
where T2 : struct, INativeList, IUTF8Bytes
{
ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
return fs.LastIndexOf(oref.GetUnsafePtr(), oref.Length);
}
///
/// Returns the index of the last occurrence of a substring within a subrange of this string.
///
/// A FixedString*N* type.
/// A FixedString*N* type.
/// A string to search.
/// A substring to search for within this string.
/// The greatest index in this string to consider as an occurrence of the substring.
/// The smallest index in this string to consider as an occurrence of the substring.
/// the index of the last occurrence of the substring within the first string. Returns -1 if no occurrence is found.
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
public static int LastIndexOf(ref this T fs, in T2 other, int startIndex, int distance = Int32.MaxValue)
where T : struct, INativeList, IUTF8Bytes
where T2 : struct, INativeList, IUTF8Bytes
{
ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
return fs.LastIndexOf(oref.GetUnsafePtr(), oref.Length, startIndex, distance);
}
///
/// Returns the sort position of this string relative to a byte sequence.
///
/// A FixedString*N* type.
/// A string to compare.
/// A byte sequence to compare.
/// The number of bytes in the byte sequence.
/// A number denoting the sort position of this string relative to the byte sequence:
///
/// 0 denotes that this string and byte sequence have the same sort position.
/// -1 denotes that this string should be sorted to precede the byte sequence.
/// +1 denotes that this string should be sorted to follow the byte sequence.
///
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
public static int CompareTo(ref this T fs, byte* bytes, int bytesLen)
where T : struct, INativeList, IUTF8Bytes
{
var a = fs.GetUnsafePtr();
var aa = fs.Length;
int chars = aa < bytesLen ? aa : bytesLen;
for (var i = 0; i < chars; ++i)
{
if (a[i] < bytes[i])
return -1;
if (a[i] > bytes[i])
return 1;
}
if (aa < bytesLen)
return -1;
if (aa > bytesLen)
return 1;
return 0;
}
///
/// Returns the sort position of this string relative to another.
///
/// A FixedString*N* type.
/// A FixedString*N* type.
/// A string to compare.
/// Another string to compare.
/// A number denoting the relative sort position of the strings:
///
/// 0 denotes that the strings have the same sort position.
/// -1 denotes that this string should be sorted to precede the other.
/// +1 denotes that this first string should be sorted to follow the other.
///
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
public static int CompareTo(ref this T fs, in T2 other)
where T : struct, INativeList, IUTF8Bytes
where T2 : struct, INativeList, IUTF8Bytes
{
ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
return fs.CompareTo(oref.GetUnsafePtr(), oref.Length);
}
///
/// Returns true if this string and a byte sequence are equal (meaning they have the same length and content).
///
/// A FixedString*N* type.
/// A string to compare for equality.
/// A sequence of bytes to compare for equality.
/// The number of bytes in the byte sequence.
/// True if this string and the byte sequence have the same length and if this string's character bytes match the byte sequence.
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
public static bool Equals(ref this T fs, byte* bytes, int bytesLen)
where T : struct, INativeList, IUTF8Bytes
{
var a = fs.GetUnsafePtr();
var aa = fs.Length;
if (aa != bytesLen)
return false;
if (a == bytes)
return true;
return fs.CompareTo(bytes, bytesLen) == 0;
}
///
/// Returns true if this string is equal to another.
///
/// A FixedString*N* type.
/// A FixedString*N* type.
/// A string to compare for equality.
/// Another string to compare for equality.
/// true if the two strings have the same length and matching content.
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
public static bool Equals(ref this T fs, in T2 other)
where T : struct, INativeList, IUTF8Bytes
where T2 : struct, INativeList, IUTF8Bytes
{
ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
return fs.Equals(oref.GetUnsafePtr(), oref.Length);
}
///
/// Returns the Unicode.Rune at an index of this string.
///
/// A FixedString*N* type.
/// A string to read.
/// A reference to an index in bytes (not characters).
/// The Unicode.Rune (character) which starts at the byte index. Returns Unicode.BadRune
/// if the byte(s) at the index do not form a valid UTF-8 encoded character.
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
public static Unicode.Rune Peek(ref this T fs, int index)
where T : struct, INativeList, IUTF8Bytes
{
if (index >= fs.Length)
return Unicode.BadRune;
Unicode.Utf8ToUcs(out var rune, fs.GetUnsafePtr(), ref index, fs.Capacity);
return rune;
}
///
/// Returns the Unicode.Rune at an index of this string. Increments the index to the position of the next character.
///
/// A FixedString*N* type.
/// A string to read.
/// A reference to an index in bytes (not characters). Incremented by 1 to 4 depending upon the UTF-8 encoded size of the character read.
/// The character (as a `Unicode.Rune`) which starts at the byte index. Returns `Unicode.BadRune`
/// if the byte(s) at the index do not form a valid UTF-8 encoded character.
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
public static Unicode.Rune Read(ref this T fs, ref int index)
where T : struct, INativeList, IUTF8Bytes
{
if (index >= fs.Length)
return Unicode.BadRune;
Unicode.Utf8ToUcs(out var rune, fs.GetUnsafePtr(), ref index, fs.Capacity);
return rune;
}
///
/// Writes a Unicode.Rune at an index of this string. Increments the index to the position of the next character.
///
/// A FixedString*N* type.
/// A string to modify.
/// A reference to an index in bytes (not characters). Incremented by 1 to 4 depending upon the UTF-8 encoded size of the character written.
/// A rune to write to the string, encoded as UTF-8.
/// FormatError.None if successful. Returns FormatError.Overflow if the index is invalid or if there is not enough space to store the encoded rune.
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
public static FormatError Write(ref this T fs, ref int index, Unicode.Rune rune)
where T : struct, INativeList, IUTF8Bytes
{
var err = Unicode.UcsToUtf8(fs.GetUnsafePtr(), ref index, fs.Capacity, rune);
if (err != ConversionError.None)
return FormatError.Overflow;
return FormatError.None;
}
///
/// Returns a copy of this string as a managed string.
///
/// A FixedString*N* type.
/// A string to copy.
/// A copy of this string as a managed string.
[NotBurstCompatible]
public static String ConvertToString(ref this T fs)
where T : struct, INativeList, IUTF8Bytes
{
var c = stackalloc char[fs.Length * 2];
int length = 0;
Unicode.Utf8ToUtf16(fs.GetUnsafePtr(), fs.Length, c, out length, fs.Length * 2);
return new String(c, 0, length);
}
///
/// Returns a hash code of this string.
///
/// A FixedString*N* type.
/// A string to get a hash code of.
/// A hash code of this string.
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
public static int ComputeHashCode(ref this T fs)
where T : struct, INativeList, IUTF8Bytes
{
return (int)CollectionHelper.Hash(fs.GetUnsafePtr(), fs.Length);
}
///
/// Returns the effective size in bytes of this string.
///
///
/// "Effective size" is `Length + 3`, the number of bytes you need to copy when serializing the string.
/// (The plus 3 accounts for the null-terminator byte and the 2 bytes that store the Length).
///
/// Useful for checking whether this string will fit in the space of a smaller FixedString*N*.
///
/// A FixedString*N* type.
/// A string to get the effective size of.
/// The effective size in bytes of this string.
[BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
public static int EffectiveSizeOf(ref this T fs)
where T : struct, INativeList, IUTF8Bytes
{
return sizeof(ushort) + fs.Length + 1;
}
}
}