diff --git a/src/Discord.Net.Rest/Serialization/JsonConverters/EntityOrIdPropertyConverter.cs b/src/Discord.Net.Rest/Serialization/JsonConverters/EntityOrIdPropertyConverter.cs index d7e917213..c25302c18 100644 --- a/src/Discord.Net.Rest/Serialization/JsonConverters/EntityOrIdPropertyConverter.cs +++ b/src/Discord.Net.Rest/Serialization/JsonConverters/EntityOrIdPropertyConverter.cs @@ -28,7 +28,7 @@ namespace Discord.Serialization.Json.Converters else { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value.Id); + writer.WriteAttribute(map.Key, value.Id); else writer.WriteValue(value.Id); } diff --git a/src/Discord.Net.Rest/Serialization/JsonConverters/Int53PropertyConverter.cs b/src/Discord.Net.Rest/Serialization/JsonConverters/Int53PropertyConverter.cs index 9f8d51a46..d59fd1610 100644 --- a/src/Discord.Net.Rest/Serialization/JsonConverters/Int53PropertyConverter.cs +++ b/src/Discord.Net.Rest/Serialization/JsonConverters/Int53PropertyConverter.cs @@ -15,7 +15,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, long value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value); + writer.WriteAttribute(map.Key, value); else writer.WriteValue(value.ToString()); } diff --git a/src/Discord.Net.Rest/Serialization/JsonConverters/UInt53PropertyConverter.cs b/src/Discord.Net.Rest/Serialization/JsonConverters/UInt53PropertyConverter.cs index 07f6e54a3..fa35ff711 100644 --- a/src/Discord.Net.Rest/Serialization/JsonConverters/UInt53PropertyConverter.cs +++ b/src/Discord.Net.Rest/Serialization/JsonConverters/UInt53PropertyConverter.cs @@ -15,7 +15,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, ulong value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value); + writer.WriteAttribute(map.Key, value); else writer.WriteValue(value.ToString()); } diff --git a/src/Discord.Net.Serialization/Extensions/JsonReaderExtensions.cs b/src/Discord.Net.Serialization/Extensions/JsonReaderExtensions.cs index b14db80da..84b094724 100644 --- a/src/Discord.Net.Serialization/Extensions/JsonReaderExtensions.cs +++ b/src/Discord.Net.Serialization/Extensions/JsonReaderExtensions.cs @@ -27,8 +27,11 @@ namespace Discord.Serialization public static bool ParseBool(this JsonReader reader) => reader.Value.ParseBool(); public static Guid ParseGuid(this JsonReader reader) => reader.Value.ParseGuid(); + } - public static void Skip(this JsonReader reader) + public static class JsonUtils + { + public static void Skip(ref JsonReader reader) { int initialDepth = reader._depth; while (reader.Read() && reader._depth > initialDepth) { } diff --git a/src/Discord.Net.Serialization/Json/Converters/Collections.cs b/src/Discord.Net.Serialization/Json/Converters/Collections.cs index f811bf086..b0096b860 100644 --- a/src/Discord.Net.Serialization/Json/Converters/Collections.cs +++ b/src/Discord.Net.Serialization/Json/Converters/Collections.cs @@ -26,7 +26,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, List value, bool isTopLevel) { if (isTopLevel) - writer.WriteArrayStart(map.Utf16Key); + writer.WriteArrayStart(map.Key); else writer.WriteArrayStart(); for (int i = 0; i < value.Count; i++) diff --git a/src/Discord.Net.Serialization/Json/Converters/Nullable.cs b/src/Discord.Net.Serialization/Json/Converters/Nullable.cs index d40b40ca9..bd1efaa31 100644 --- a/src/Discord.Net.Serialization/Json/Converters/Nullable.cs +++ b/src/Discord.Net.Serialization/Json/Converters/Nullable.cs @@ -28,7 +28,7 @@ namespace Discord.Serialization.Json.Converters else { if (isTopLevel) - writer.WriteAttributeNull(map.Utf16Key); + writer.WriteAttributeNull(map.Key); else writer.WriteNull(); } diff --git a/src/Discord.Net.Serialization/Json/Converters/Object.cs b/src/Discord.Net.Serialization/Json/Converters/Object.cs index 5938af573..1e206fae3 100644 --- a/src/Discord.Net.Serialization/Json/Converters/Object.cs +++ b/src/Discord.Net.Serialization/Json/Converters/Object.cs @@ -1,5 +1,4 @@ using System.Text.Json; -using System.Text.Utf8; namespace Discord.Serialization.Json.Converters { @@ -21,17 +20,17 @@ namespace Discord.Serialization.Json.Converters if (reader.TokenType != JsonTokenType.PropertyName) throw new SerializationException("Bad input, expected PropertyName"); - if (_map.PropertiesByKey.TryGetValue(reader.Value, out var property)) + if (_map.TryGetProperty(reader.Value, out var property)) (property as IJsonPropertyMap).Read(model, ref reader); else - reader.Skip(); //Unknown property, skip + JsonUtils.Skip(ref reader); //Unknown property, skip } throw new SerializationException("Bad input, expected EndObject"); } public void Write(PropertyMap map, ref JsonWriter writer, T value, bool isTopLevel) { if (isTopLevel) - writer.WriteObjectStart(map.Utf16Key); + writer.WriteObjectStart(map.Key); else writer.WriteObjectStart(); for (int i = 0; i < _map.Properties.Length; i++) diff --git a/src/Discord.Net.Serialization/Json/Converters/Primitives.DateTime.cs b/src/Discord.Net.Serialization/Json/Converters/Primitives.DateTime.cs index e6bd2e764..e8e8e4ab8 100644 --- a/src/Discord.Net.Serialization/Json/Converters/Primitives.DateTime.cs +++ b/src/Discord.Net.Serialization/Json/Converters/Primitives.DateTime.cs @@ -16,7 +16,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, DateTime value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value); + writer.WriteAttribute(map.Key, value); else writer.WriteValue(value); } @@ -35,7 +35,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, DateTimeOffset value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value); + writer.WriteAttribute(map.Key, value); else writer.WriteValue(value); } diff --git a/src/Discord.Net.Serialization/Json/Converters/Primitives.Float.cs b/src/Discord.Net.Serialization/Json/Converters/Primitives.Float.cs index 7eaaea74b..1c5b33678 100644 --- a/src/Discord.Net.Serialization/Json/Converters/Primitives.Float.cs +++ b/src/Discord.Net.Serialization/Json/Converters/Primitives.Float.cs @@ -15,7 +15,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, float value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value.ToString()); + writer.WriteAttribute(map.Key, value.ToString()); else writer.WriteValue(value.ToString()); } @@ -34,7 +34,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, double value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value.ToString()); + writer.WriteAttribute(map.Key, value.ToString()); else writer.WriteValue(value.ToString()); } @@ -53,7 +53,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, decimal value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value.ToString()); + writer.WriteAttribute(map.Key, value.ToString()); else writer.WriteValue(value.ToString()); } diff --git a/src/Discord.Net.Serialization/Json/Converters/Primitives.Other.cs b/src/Discord.Net.Serialization/Json/Converters/Primitives.Other.cs index 175523eac..57ca83c3d 100644 --- a/src/Discord.Net.Serialization/Json/Converters/Primitives.Other.cs +++ b/src/Discord.Net.Serialization/Json/Converters/Primitives.Other.cs @@ -19,7 +19,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, bool value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value); + writer.WriteAttribute(map.Key, value); else writer.WriteValue(value); } @@ -38,7 +38,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, Guid value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value.ToString()); + writer.WriteAttribute(map.Key, value.ToString()); else writer.WriteValue(value.ToString()); } diff --git a/src/Discord.Net.Serialization/Json/Converters/Primitives.Signed.cs b/src/Discord.Net.Serialization/Json/Converters/Primitives.Signed.cs index bc3150e0b..dcf0cd946 100644 --- a/src/Discord.Net.Serialization/Json/Converters/Primitives.Signed.cs +++ b/src/Discord.Net.Serialization/Json/Converters/Primitives.Signed.cs @@ -15,7 +15,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, sbyte value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value); + writer.WriteAttribute(map.Key, value); else writer.WriteValue(value); } @@ -34,7 +34,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, short value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value); + writer.WriteAttribute(map.Key, value); else writer.WriteValue(value); } @@ -53,7 +53,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, int value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value); + writer.WriteAttribute(map.Key, value); else writer.WriteValue(value); } @@ -72,7 +72,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, long value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value.ToString()); + writer.WriteAttribute(map.Key, value.ToString()); else writer.WriteValue(value.ToString()); } diff --git a/src/Discord.Net.Serialization/Json/Converters/Primitives.String.cs b/src/Discord.Net.Serialization/Json/Converters/Primitives.String.cs index d51a23d10..2ec6b2b1e 100644 --- a/src/Discord.Net.Serialization/Json/Converters/Primitives.String.cs +++ b/src/Discord.Net.Serialization/Json/Converters/Primitives.String.cs @@ -35,29 +35,9 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, string value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value); + writer.WriteAttribute(map.Key, value); else writer.WriteValue(value); } } - - internal class Utf8StringPropertyConverter : IJsonPropertyConverter - { - public Utf8String Read(PropertyMap map, ref JsonReader reader, bool isTopLevel) - { - if (isTopLevel) - reader.Read(); - if (reader.ValueType != JsonValueType.String) - throw new SerializationException("Bad input, expected String"); - return new Utf8String(reader.Value); - } - public void Write(PropertyMap map, ref JsonWriter writer, Utf8String value, bool isTopLevel) - { - //TODO: Serialization causes allocs, fix - if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value.ToString()); - else - writer.WriteValue(value.ToString()); - } - } } diff --git a/src/Discord.Net.Serialization/Json/Converters/Primitives.Unsigned.cs b/src/Discord.Net.Serialization/Json/Converters/Primitives.Unsigned.cs index 539dfcaa0..cd1267abb 100644 --- a/src/Discord.Net.Serialization/Json/Converters/Primitives.Unsigned.cs +++ b/src/Discord.Net.Serialization/Json/Converters/Primitives.Unsigned.cs @@ -15,7 +15,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, byte value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value); + writer.WriteAttribute(map.Key, value); else writer.WriteValue(value); } @@ -34,7 +34,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, ushort value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value); + writer.WriteAttribute(map.Key, value); else writer.WriteValue(value); } @@ -53,7 +53,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, uint value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value); + writer.WriteAttribute(map.Key, value); else writer.WriteValue(value); } @@ -72,7 +72,7 @@ namespace Discord.Serialization.Json.Converters public void Write(PropertyMap map, ref JsonWriter writer, ulong value, bool isTopLevel) { if (isTopLevel) - writer.WriteAttribute(map.Utf16Key, value.ToString()); + writer.WriteAttribute(map.Key, value.ToString()); else writer.WriteValue(value.ToString()); } diff --git a/src/Discord.Net.Serialization/Json/IJsonPropertyMap.cs b/src/Discord.Net.Serialization/Json/IJsonPropertyMap.cs index d0921dedb..57c4564a5 100644 --- a/src/Discord.Net.Serialization/Json/IJsonPropertyMap.cs +++ b/src/Discord.Net.Serialization/Json/IJsonPropertyMap.cs @@ -1,12 +1,12 @@ -using System.Text.Json; -using System.Text.Utf8; +using System; +using System.Text.Json; namespace Discord.Serialization { internal interface IJsonPropertyMap { - string Utf16Key { get; } - Utf8String Utf8Key { get; } + string Key { get; } + ReadOnlyBuffer Utf8Key { get; } void Write(TModel model, ref JsonWriter writer); void Read(TModel model, ref JsonReader reader); diff --git a/src/Discord.Net.Serialization/Json/JsonFormat.cs b/src/Discord.Net.Serialization/Json/JsonFormat.cs index 73df35d2b..3126d0814 100644 --- a/src/Discord.Net.Serialization/Json/JsonFormat.cs +++ b/src/Discord.Net.Serialization/Json/JsonFormat.cs @@ -5,7 +5,6 @@ using System.Reflection; using System.Text; using System.Text.Formatting; using System.Text.Json; -using System.Text.Utf8; namespace Discord.Serialization.Json { @@ -29,7 +28,6 @@ namespace Discord.Serialization.Json //AddConverter(); //char.Parse does not support Json.Net's serialization AddConverter(); - AddConverter(); AddConverter(); AddConverter(); diff --git a/src/Discord.Net.Serialization/ModelMap.cs b/src/Discord.Net.Serialization/ModelMap.cs index d03bfe080..9e05cb891 100644 --- a/src/Discord.Net.Serialization/ModelMap.cs +++ b/src/Discord.Net.Serialization/ModelMap.cs @@ -7,13 +7,211 @@ namespace Discord.Serialization public class ModelMap where TModel : class, new() { - public readonly PropertyMap[] Properties; - public readonly Dictionary, PropertyMap> PropertiesByKey; + private struct PropertyEntry + { + public int hashCode; // Lower 31 bits of hash code, -1 if unused + public int next; // Index of next entry, -1 if last + public ReadOnlyBuffer key; // Key of entry + public PropertyMap value; // Value of entry + } + + private int[] _buckets; + private PropertyEntry[] _entries; + private int _count; + private int _freeList; + private int _freeCount; + + public PropertyMap[] Properties { get; } + + public ModelMap(List properties) + { + Properties = properties.ToArray(); + + int size = HashHelpers.GetPrime(Properties.Length); + _buckets = new int[size]; + for (int i = 0; i < _buckets.Length; i++) _buckets[i] = -1; + _entries = new PropertyEntry[size]; + _freeList = -1; + + for (int i = 0; i < properties.Count; i++) + AddProperty(properties[i].Utf8Key, properties[i]); + } + + public void AddProperty(ReadOnlyBuffer key, PropertyMap value) + { + int hashCode = GetKeyHashCode(key) & 0x7FFFFFFF; + int targetBucket = hashCode % _buckets.Length; - public ModelMap(Dictionary, PropertyMap> properties) + for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next) + { + if (_entries[i].hashCode == hashCode && KeyEquals(_entries[i].key, key)) + throw new ArgumentException("Duplicate property", nameof(key)); + } + int index; + if (_freeCount > 0) + { + index = _freeList; + _freeList = _entries[index].next; + _freeCount--; + } + else + { + if (_count == _entries.Length) + { + Resize(); + targetBucket = hashCode % _buckets.Length; + } + index = _count; + _count++; + } + + _entries[index].hashCode = hashCode; + _entries[index].next = _buckets[targetBucket]; + _entries[index].key = key; + _entries[index].value = value; + _buckets[targetBucket] = index; + } + private void Resize() + { + int newSize = HashHelpers.ExpandPrime(_count); + + var newBuckets = new int[newSize]; + for (int i = 0; i < newBuckets.Length; i++) + newBuckets[i] = -1; + + var newEntries = new PropertyEntry[newSize]; + Array.Copy(_entries, 0, newEntries, 0, _count); + + for (int i = 0; i < _count; i++) + { + if (newEntries[i].hashCode >= 0) + { + int bucket = newEntries[i].hashCode % newSize; + newEntries[i].next = newBuckets[bucket]; + newBuckets[bucket] = i; + } + } + _buckets = newBuckets; + _entries = newEntries; + } + + private int FindEntry(ReadOnlyBuffer key) + { + if (_buckets != null) + { + int hashCode = GetKeyHashCode(key) & 0x7FFFFFFF; + for (int i = _buckets[hashCode % _buckets.Length]; i >= 0; i = _entries[i].next) + { + if (_entries[i].hashCode == hashCode && KeyEquals(_entries[i].key, key)) + return i; + } + } + return -1; + } + private int FindEntry(ReadOnlySpan key) + { + if (_buckets != null) + { + int hashCode = GetKeyHashCode(key) & 0x7FFFFFFF; + for (int i = _buckets[hashCode % _buckets.Length]; i >= 0; i = _entries[i].next) + { + if (_entries[i].hashCode == hashCode && KeyEquals(_entries[i].key, key)) + return i; + } + } + return -1; + } + + public bool TryGetProperty(ReadOnlyBuffer key, out PropertyMap value) + { + int i = FindEntry(key); + if (i >= 0) + { + value = _entries[i].value; + return true; + } + value = default; + return false; + } + public bool TryGetProperty(ReadOnlySpan key, out PropertyMap value) + { + int i = FindEntry(key); + if (i >= 0) + { + value = _entries[i].value; + return true; + } + value = default; + return false; + } + + private bool KeyEquals(ReadOnlyBuffer x, ReadOnlyBuffer y) => x.Span.SequenceEqual(y.Span); + private bool KeyEquals(ReadOnlyBuffer x, ReadOnlySpan y) => x.Span.SequenceEqual(y); + + private int GetKeyHashCode(ReadOnlyBuffer obj) => GetKeyHashCode(obj.Span); + private int GetKeyHashCode(ReadOnlySpan obj) + { + //From Utf8String + //TODO: Replace when they do + unchecked + { + if (obj.Length <= 4) + { + int hash = obj.Length; + for (int i = 0; i < obj.Length; i++) + { + hash <<= 8; + hash ^= obj[i]; + } + return hash; + } + else + { + int hash = obj.Length; + hash ^= obj[0]; + hash <<= 8; + hash ^= obj[1]; + hash <<= 8; + hash ^= obj[obj.Length - 2]; + hash <<= 8; + hash ^= obj[obj.Length - 1]; + return hash; + } + } + } + } + + internal static class HashHelpers + { + public static readonly int[] primes = { + 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919, + 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, + 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437, + 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263, + 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369, 8639249, 10367101, + 12440537, 14928671, 17914409, 21497293, 25796759, 30956117, 37147349, 44576837, 53492207, 64190669, + 77028803, 92434613, 110921543, 133105859, 159727031, 191672443, 230006941, 276008387, 331210079, + 397452101, 476942527, 572331049, 686797261, 824156741, 988988137, 1186785773, 1424142949, 1708971541, + 2050765853, MaxPrimeArrayLength }; + + public static int GetPrime(int min) + { + for (int i = 0; i < primes.Length; i++) + { + int prime = primes[i]; + if (prime >= min) return prime; + } + return min; + } + + public static int ExpandPrime(int oldSize) { - PropertiesByKey = properties; - Properties = PropertiesByKey.Values.ToArray(); + int newSize = 2 * oldSize; + if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize) + return MaxPrimeArrayLength; + return GetPrime(newSize); } + + public const int MaxPrimeArrayLength = 0x7FEFFFFD; } -} +} \ No newline at end of file diff --git a/src/Discord.Net.Serialization/PropertyMap.cs b/src/Discord.Net.Serialization/PropertyMap.cs index fcffaa7a0..e2f50fda5 100644 --- a/src/Discord.Net.Serialization/PropertyMap.cs +++ b/src/Discord.Net.Serialization/PropertyMap.cs @@ -1,20 +1,21 @@ -using System.Reflection; +using System; +using System.Reflection; using System.Text.Utf8; namespace Discord.Serialization { public abstract class PropertyMap { - public string Utf16Key { get; } - public Utf8String Utf8Key { get; } + public string Key { get; } + public ReadOnlyBuffer Utf8Key { get; } public bool ExcludeNull { get; } public PropertyMap(PropertyInfo propInfo) { var jsonProperty = propInfo.GetCustomAttribute(); - Utf16Key = jsonProperty?.Key ?? propInfo.Name; - Utf8Key = new Utf8String(Utf16Key); + Key = jsonProperty?.Key ?? propInfo.Name; + Utf8Key = new ReadOnlyBuffer(new Utf8String(Key).Bytes.ToArray()); ExcludeNull = jsonProperty?.ExcludeNull ?? false; } } diff --git a/src/Discord.Net.Serialization/SerializationFormat.cs b/src/Discord.Net.Serialization/SerializationFormat.cs index 241ad6fca..b04ac2011 100644 --- a/src/Discord.Net.Serialization/SerializationFormat.cs +++ b/src/Discord.Net.Serialization/SerializationFormat.cs @@ -29,11 +29,11 @@ namespace Discord.Serialization .Where(x => x.CanRead && x.CanWrite) .ToArray(); - var properties = new Dictionary, PropertyMap>(propInfos.Length, Utf8SpanComparer.Instance); + var properties = new List(); for (int i = 0; i < propInfos.Length; i++) { var propMap = MapProperty(propInfos[i]); - properties.Add(propMap.Utf8Key, propMap); + properties.Add(propMap); } return new ModelMap(properties); }) as ModelMap; diff --git a/src/Discord.Net.Serialization/Utf8SpanComparer.cs b/src/Discord.Net.Serialization/Utf8SpanComparer.cs deleted file mode 100644 index b22763626..000000000 --- a/src/Discord.Net.Serialization/Utf8SpanComparer.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Discord.Serialization -{ - internal class Utf8SpanComparer : IEqualityComparer> - { - public static readonly Utf8SpanComparer Instance = new Utf8SpanComparer(); - - public bool Equals(ReadOnlySpan x, ReadOnlySpan y) => x.SequenceEqual(y); - public int GetHashCode(ReadOnlySpan obj) - { - //From Utf8String - //TODO: Replace when they do - unchecked - { - if (obj.Length <= 4) - { - int hash = obj.Length; - for (int i = 0; i < obj.Length; i++) - { - hash <<= 8; - hash ^= obj[i]; - } - return hash; - } - else - { - int hash = obj.Length; - hash ^= obj[0]; - hash <<= 8; - hash ^= obj[1]; - hash <<= 8; - hash ^= obj[obj.Length - 2]; - hash <<= 8; - hash ^= obj[obj.Length - 1]; - return hash; - } - } - } - } -}