using System; using System.Text; namespace LaunchDarkly.EventSource { /// /// Points to a span of UTF-8-encoded text in a buffer. /// /// /// This is similar to the Span type in .NET 5. It is used internally by /// EventSource to store event data if the stream is using UTF-8 encoding. /// If so, reading will return the same /// byte array, to avoid unnecessary copying. /// public struct Utf8ByteSpan { /// /// The byte array containing the data. May be null if is zero. /// /// /// It is the caller's responsibility not to modify the array. /// public byte[] Data { get; } /// /// The offset of the first relevant byte of data within the array. This may be /// greater than zero if the span represents a subset of a larger buffer. /// public int Offset { get; } /// /// The number of bytes of relevant data within the array. This may be less than /// Data.Length if the span represents a subset of a larger buffer. /// public int Length { get; } /// /// Constructs a new instance. /// /// The byte array containing the data. /// The offset of the first relevant byte of data within the array. /// The number of bytes of relevant data within the array. public Utf8ByteSpan(byte[] data, int offset, int length) { Data = length == 0 ? null : data; Offset = offset; Length = length; } /// /// Constructs a new instance by copying a string. /// /// A string to convert to UTF-8 bytes. public Utf8ByteSpan(string s) { Data = s.Length == 0 ? null : Encoding.UTF8.GetBytes(s); Offset = 0; Length = Data is null ? 0 : Data.Length; } /// /// Converts the UTF-8 byte data to a string. /// /// A new string. public string GetString() => Data is null ? "" : Encoding.UTF8.GetString(Data, Offset, Length); /// /// Tests whether the bytes in this span are the same as another span. /// /// Another Utf8ByteSpan. /// True if the two spans have the same length and the same /// data, starting from each one's Offset. public bool Equals(Utf8ByteSpan other) { var len = Length; if (len != other.Length) { return false; } int offset = Offset, otherOffset = other.Offset; byte[] data = Data, otherData = other.Data; for (int i = 0; i < len; i++) { if (data[i + offset] != otherData[i + otherOffset]) { return false; } } return true; } /// /// Tests whether the bytes in this span are the same as the UTF-8 encoding /// of the specified string. /// /// /// This method is potentially inefficient and should be used only in testing. /// /// A string. /// True if the bytes are equivalent. public bool Equals(string s) { byte[] data = Data; int offset = Offset, len = Length; for (int i = 0; i < len; i++) { if (data[offset + i] > 127) { // There are multi-byte characters in the span, so we can't do a 1:1 comparison of bytes return GetString().Equals(s); } } // There are no multi-byte characters, so we don't need to convert to or from a UTF-16 string if (len != s.Length) { return false; } for (int i = 0; i < len; i++) { if ((char)data[offset + i] != s[i]) { return false; } } return true; } } }