// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
namespace EpicGames.Core
{
///
/// View of a character string. Allows comparing/manipulating substrings without unnecessary memory allocations.
///
public readonly struct StringView : IEquatable
{
///
/// Memory containing the characters
///
public ReadOnlyMemory Memory { get; }
///
/// Span for the sequence of characters
///
public ReadOnlySpan Span => Memory.Span;
///
/// Length of the sequence of characters
///
public int Length => Memory.Length;
///
/// Constructor
///
/// String view to construct from
public StringView(StringView text)
{
Memory = text.Memory;
}
///
/// Constructor
///
/// String view to construct from
/// Offset within the string for this view
public StringView(StringView text, int index)
{
Memory = text.Memory.Slice(index);
}
///
/// Constructor
///
/// String view to construct from
/// Offset within the string for this view
/// Number of characters to include
public StringView(StringView text, int index, int count)
{
Memory = text.Memory.Slice(index, count);
}
///
/// Constructor
///
/// The memory containing the characters
public StringView(ReadOnlyMemory memory)
{
Memory = memory;
}
///
/// Constructor
///
/// The memory containing the characters
/// Offset within the string for this view
public StringView(ReadOnlyMemory memory, int index)
{
Memory = memory.Slice(index);
}
///
/// Constructor
///
/// The memory containing the characters
/// Offset within the string for this view
/// Number of characters to include
public StringView(ReadOnlyMemory memory, int index, int count)
{
Memory = memory.Slice(index, count);
}
///
/// Constructor
///
/// String to construct from
public StringView(string text)
{
Memory = text.AsMemory();
}
///
/// Constructs a view onto a substring of the given string
///
/// String to construct from
/// Offset within the string for this view
public StringView(string text, int index)
{
Memory = text.AsMemory(index);
}
///
/// Constructs a view onto a substring of the given string
///
/// String to construct from
/// Offset within the string for this view
/// Number of characters to include
public StringView(string text, int index, int count)
{
Memory = text.AsMemory(index, count);
}
///
/// Equality comparer
///
/// First string to compare
/// Second string to compare
/// True if the strings are equal
public static bool operator ==(StringView x, StringView y)
{
return x.Equals(y);
}
///
/// Inequality comparer
///
/// First string to compare
/// Second string to compare
/// True if the strings are equal
public static bool operator !=(StringView x, StringView y)
{
return !x.Equals(y);
}
///
public override bool Equals(object? obj)
{
return obj is StringView view && Equals(view);
}
///
public override int GetHashCode()
{
return String.GetHashCode(Memory.Span, StringComparison.Ordinal);
}
///
public int GetHashCode(StringComparison comparisonType)
{
return String.GetHashCode(Memory.Span, comparisonType);
}
///
public override string ToString()
{
return new string(Memory.Span);
}
///
public bool Equals(StringView other)
{
return Equals(other, StringComparison.CurrentCulture);
}
///
public bool Equals(StringView? other, StringComparison comparisonType)
{
return other.HasValue && Memory.Span.Equals(other.Value.Memory.Span, comparisonType);
}
///
/// Implicit conversion operator from a regular string
///
/// The string to construct from
public static implicit operator StringView(string text) => new StringView(text);
}
///
/// Comparer for StringView objects
///
public class StringViewComparer : IComparer, IEqualityComparer
{
///
/// Static instance of an ordinal StringView comparer
///
public static StringViewComparer Ordinal { get; } = new StringViewComparer(StringComparison.Ordinal);
///
/// Static instance of an ordinal StringView comparer which ignores case
///
public static StringViewComparer OrdinalIgnoreCase { get; } = new StringViewComparer(StringComparison.OrdinalIgnoreCase);
///
/// The comparison type
///
public StringComparison ComparisonType { get; }
///
/// Constructor
///
/// Type of comparison to perform
public StringViewComparer(StringComparison comparisonType)
{
ComparisonType = comparisonType;
}
///
public bool Equals(StringView x, StringView y)
{
return x.Span.Equals(y.Span, ComparisonType);
}
///
public int GetHashCode(StringView obj)
{
return String.GetHashCode(obj.Span, ComparisonType);
}
///
public int Compare(StringView x, StringView y)
{
return x.Span.CompareTo(y.Span, ComparisonType);
}
}
///
/// Comparer for StringView objects. However, it implements UE style ignore case compare
///
public class StringViewComparerUe : IComparer, IEqualityComparer
{
///
/// Static instance of an ordinal StringView comparer
///
public static StringViewComparerUe Ordinal { get; } = new StringViewComparerUe(StringComparison.Ordinal);
///
/// Static instance of an ordinal StringView comparer which ignores case
///
public static StringViewComparerUe OrdinalIgnoreCase { get; } = new StringViewComparerUe(StringComparison.OrdinalIgnoreCase);
///
/// The comparison type
///
public StringComparison ComparisonType { get; }
///
/// Constructor
///
/// Type of comparison to perform
public StringViewComparerUe(StringComparison comparisonType)
{
ComparisonType = comparisonType;
}
///
public bool Equals(StringView x, StringView y)
{
return x.Span.Equals(y.Span, ComparisonType);
}
///
public int GetHashCode(StringView obj)
{
return String.GetHashCode(obj.Span, ComparisonType);
}
///
public int Compare(StringView x, StringView y)
{
if (ComparisonType == StringComparison.OrdinalIgnoreCase)
{
return StringUtils.CompareIgnoreCaseUe(x.Span, y.Span);
}
else
{
return x.Span.CompareTo(y.Span, ComparisonType);
}
}
}
}