diff --git a/Unity3D/3rdLib/Utf8Json/Attributes.cs b/Unity3D/3rdLib/Utf8Json/Attributes.cs new file mode 100644 index 0000000..77166a0 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Attributes.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Utf8Json +{ + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class JsonFormatterAttribute : Attribute + { + public Type FormatterType { get; private set; } + public object[] Arguments { get; private set; } + + public JsonFormatterAttribute(Type formatterType) + { + this.FormatterType = formatterType; + } + + public JsonFormatterAttribute(Type formatterType, params object[] arguments) + { + this.FormatterType = formatterType; + this.Arguments = arguments; + } + } + + [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = true)] + public class SerializationConstructorAttribute : Attribute + { + + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Formatters/AnonymousFormatter.cs b/Unity3D/3rdLib/Utf8Json/Formatters/AnonymousFormatter.cs new file mode 100644 index 0000000..be74725 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Formatters/AnonymousFormatter.cs @@ -0,0 +1,28 @@ +using System; + +namespace Utf8Json.Formatters +{ + public sealed class AnonymousFormatter : IJsonFormatter + { + readonly JsonSerializeAction serialize; + readonly JsonDeserializeFunc deserialize; + + public AnonymousFormatter(JsonSerializeAction serialize, JsonDeserializeFunc deserialize) + { + this.serialize = serialize; + this.deserialize = deserialize; + } + + public void Serialize(ref JsonWriter writer, T value, IJsonFormatterResolver formatterResolver) + { + if (serialize == null) throw new InvalidOperationException(this.GetType().Name + " does not support Serialize."); + serialize(ref writer, value, formatterResolver); + } + + public T Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (deserialize == null) throw new InvalidOperationException(this.GetType().Name + " does not support Deserialize."); + return deserialize(ref reader, formatterResolver); + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Formatters/CollectionFormatters.cs b/Unity3D/3rdLib/Utf8Json/Formatters/CollectionFormatters.cs new file mode 100644 index 0000000..7f07c71 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Formatters/CollectionFormatters.cs @@ -0,0 +1,1187 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using Utf8Json.Formatters.Internal; +using Utf8Json.Internal; + +#if NETSTANDARD +using System.Collections.Concurrent; +#endif + +namespace Utf8Json.Formatters +{ + public class ArrayFormatter : IJsonFormatter, IOverwriteJsonFormatter + { + static readonly ArrayPool arrayPool = new ArrayPool(99); + readonly CollectionDeserializeToBehaviour deserializeToBehaviour; + + public ArrayFormatter() + : this(CollectionDeserializeToBehaviour.Add) + { + + } + + public ArrayFormatter(CollectionDeserializeToBehaviour deserializeToBehaviour) + { + this.deserializeToBehaviour = deserializeToBehaviour; + } + + public void Serialize(ref JsonWriter writer, T[] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteBeginArray(); + var formatter = formatterResolver.GetFormatterWithVerify(); + if (value.Length != 0) + { + formatter.Serialize(ref writer, value[0], formatterResolver); + } + for (int i = 1; i < value.Length; i++) + { + writer.WriteValueSeparator(); + formatter.Serialize(ref writer, value[i], formatterResolver); + } + writer.WriteEndArray(); + } + + public T[] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var count = 0; + var formatter = formatterResolver.GetFormatterWithVerify(); + + var workingArea = arrayPool.Rent(); + try + { + var array = workingArea; + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + if (array.Length < count) + { + Array.Resize(ref array, array.Length * 2); + } + + array[count - 1] = formatter.Deserialize(ref reader, formatterResolver); + } + + var result = new T[count]; + Array.Copy(array, result, count); + Array.Clear(workingArea, 0, Math.Min(count, workingArea.Length)); + return result; + } + finally + { + arrayPool.Return(workingArea); + } + } + + public void DeserializeTo(ref T[] value, ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + // null, do nothing(same as empty) + return; + } + + var count = 0; + var formatter = formatterResolver.GetFormatterWithVerify(); + + if (deserializeToBehaviour == CollectionDeserializeToBehaviour.Add) + { + var workingArea = arrayPool.Rent(); + try + { + var array = workingArea; + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + if (array.Length < count) + { + Array.Resize(ref array, array.Length * 2); + } + + array[count - 1] = formatter.Deserialize(ref reader, formatterResolver); + } + + if (count == 0) + { + return; + } + + var result = new T[value.Length + count]; + Array.Copy(value, 0, result, 0, value.Length); + Array.Copy(array, 0, result, value.Length, count); + Array.Clear(workingArea, 0, Math.Min(count, workingArea.Length)); + } + finally + { + arrayPool.Return(workingArea); + } + } + else + { + var array = value; // use same array overwrite set. + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + if (array.Length < count) + { + Array.Resize(ref array, array.Length * 2); + } + + array[count - 1] = formatter.Deserialize(ref reader, formatterResolver); + } + + Array.Resize(ref array, count); // resize, fit length. + } + } + } + + public class ArraySegmentFormatter : IJsonFormatter> + { + static readonly ArrayPool arrayPool = new ArrayPool(99); + + public void Serialize(ref JsonWriter writer, ArraySegment value, IJsonFormatterResolver formatterResolver) + { + if (value.Array == null) { writer.WriteNull(); return; } + + var array = value.Array; + var offset = value.Offset; + var count = value.Count; + + writer.WriteBeginArray(); + var formatter = formatterResolver.GetFormatterWithVerify(); + if (count != 0) + { + formatter.Serialize(ref writer, value.Array[offset], formatterResolver); + } + + for (int i = 1; i < count; i++) + { + writer.WriteValueSeparator(); + formatter.Serialize(ref writer, array[offset + i], formatterResolver); + } + writer.WriteEndArray(); + } + + public ArraySegment Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return default(ArraySegment); + + var count = 0; + var formatter = formatterResolver.GetFormatterWithVerify(); + + var workingArea = arrayPool.Rent(); + try + { + var array = workingArea; + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + if (array.Length < count) + { + Array.Resize(ref array, array.Length * 2); + } + + array[count - 1] = formatter.Deserialize(ref reader, formatterResolver); + } + + var result = new T[count]; + Array.Copy(array, result, count); + Array.Clear(workingArea, 0, Math.Min(count, workingArea.Length)); + return new ArraySegment(result, 0, result.Length); + } + finally + { + arrayPool.Return(workingArea); + } + } + } + + public class ListFormatter : IJsonFormatter>, IOverwriteJsonFormatter> + { + readonly CollectionDeserializeToBehaviour deserializeToBehaviour; + + public ListFormatter() : this(CollectionDeserializeToBehaviour.Add) + { + + } + + public ListFormatter(CollectionDeserializeToBehaviour deserializeToBehaviour) + { + this.deserializeToBehaviour = deserializeToBehaviour; + } + + public void Serialize(ref JsonWriter writer, List value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteBeginArray(); + var formatter = formatterResolver.GetFormatterWithVerify(); + if (value.Count != 0) + { + formatter.Serialize(ref writer, value[0], formatterResolver); + } + for (int i = 1; i < value.Count; i++) + { + writer.WriteValueSeparator(); + formatter.Serialize(ref writer, value[i], formatterResolver); + } + writer.WriteEndArray(); + } + + public List Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var count = 0; + var formatter = formatterResolver.GetFormatterWithVerify(); + + var list = new List(); + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + list.Add(formatter.Deserialize(ref reader, formatterResolver)); + } + + return list; + } + + public void DeserializeTo(ref List value, ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + // null, do nothing + return; + } + + var count = 0; + var formatter = formatterResolver.GetFormatterWithVerify(); + var list = value; // use the reference + + if (deserializeToBehaviour == CollectionDeserializeToBehaviour.OverwriteReplace) + { + list.Clear(); // clear before add. + } + + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + list.Add(formatter.Deserialize(ref reader, formatterResolver)); + } + } + } + + public abstract class CollectionFormatterBase : IJsonFormatter, IOverwriteJsonFormatter + where TCollection : class, IEnumerable + where TEnumerator : IEnumerator + { + public void Serialize(ref JsonWriter writer, TCollection value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteBeginArray(); + var formatter = formatterResolver.GetFormatterWithVerify(); + + // Unity's foreach struct enumerator causes boxing so iterate manually. + var e = GetSourceEnumerator(value); + try + { + var isFirst = true; + while (e.MoveNext()) + { + if (isFirst) + { + isFirst = false; + } + else + { + writer.WriteValueSeparator(); + } + formatter.Serialize(ref writer, e.Current, formatterResolver); + } + } + finally + { + e.Dispose(); + } + + writer.WriteEndArray(); + } + } + + public TCollection Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + var formatter = formatterResolver.GetFormatterWithVerify(); + var builder = Create(); + + var count = 0; + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + Add(ref builder, count - 1, formatter.Deserialize(ref reader, formatterResolver)); + } + + return Complete(ref builder); + } + } + + public void DeserializeTo(ref TCollection value, ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + // not supported + if (SupportedOverwriteBehaviour == null) + { + value = Deserialize(ref reader, formatterResolver); + return; + } + + if (reader.ReadIsNull()) return; // do nothing + + + var formatter = formatterResolver.GetFormatterWithVerify(); + ClearOnOverwriteDeserialize(ref value); + + var count = 0; + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + AddOnOverwriteDeserialize(ref value, count - 1, formatter.Deserialize(ref reader, formatterResolver)); + } + } + + // Some collections can use struct iterator, this is optimization path + protected abstract TEnumerator GetSourceEnumerator(TCollection source); + + // abstraction for deserialize + protected abstract TIntermediate Create(); + protected abstract void Add(ref TIntermediate collection, int index, TElement value); + protected abstract TCollection Complete(ref TIntermediate intermediateCollection); + + // additional support for overwrite + + protected virtual CollectionDeserializeToBehaviour? SupportedOverwriteBehaviour + { + get + { + return null; + } + } + + protected virtual void ClearOnOverwriteDeserialize(ref TCollection value) + { + } + + protected virtual void AddOnOverwriteDeserialize(ref TCollection collection, int index, TElement value) + { + } + } + + public abstract class CollectionFormatterBase : CollectionFormatterBase, TCollection> + where TCollection : class, IEnumerable + { + protected override IEnumerator GetSourceEnumerator(TCollection source) + { + return source.GetEnumerator(); + } + } + + public abstract class CollectionFormatterBase : CollectionFormatterBase + where TCollection : class, IEnumerable + { + protected sealed override TCollection Complete(ref TCollection intermediateCollection) + { + return intermediateCollection; + } + } + + public sealed class GenericCollectionFormatter : CollectionFormatterBase + where TCollection : class, ICollection, new() + { + protected override TCollection Create() + { + return new TCollection(); + } + + protected override void Add(ref TCollection collection, int index, TElement value) + { + collection.Add(value); + } + } + + public sealed class LinkedListFormatter : CollectionFormatterBase, LinkedList.Enumerator, LinkedList> + { + readonly CollectionDeserializeToBehaviour deserializeToBehaviour; + + public LinkedListFormatter() : this(CollectionDeserializeToBehaviour.Add) + { + + } + + public LinkedListFormatter(CollectionDeserializeToBehaviour deserializeToBehaviour) + { + this.deserializeToBehaviour = deserializeToBehaviour; + } + + protected override void Add(ref LinkedList collection, int index, T value) + { + collection.AddLast(value); + } + + protected override LinkedList Complete(ref LinkedList intermediateCollection) + { + return intermediateCollection; + } + + protected override LinkedList Create() + { + return new LinkedList(); + } + + protected override LinkedList.Enumerator GetSourceEnumerator(LinkedList source) + { + return source.GetEnumerator(); + } + + protected override CollectionDeserializeToBehaviour? SupportedOverwriteBehaviour + { + get + { + return deserializeToBehaviour; + } + } + + protected override void AddOnOverwriteDeserialize(ref LinkedList collection, int index, T value) + { + collection.AddLast(value); + } + + protected override void ClearOnOverwriteDeserialize(ref LinkedList value) + { + value.Clear(); + } + } + + public sealed class QeueueFormatter : CollectionFormatterBase, Queue.Enumerator, Queue> + { + readonly CollectionDeserializeToBehaviour deserializeToBehaviour; + + public QeueueFormatter() : this(CollectionDeserializeToBehaviour.Add) + { + + } + + public QeueueFormatter(CollectionDeserializeToBehaviour deserializeToBehaviour) + { + this.deserializeToBehaviour = deserializeToBehaviour; + } + + protected override void Add(ref Queue collection, int index, T value) + { + collection.Enqueue(value); + } + + protected override Queue Create() + { + return new Queue(); + } + + protected override Queue.Enumerator GetSourceEnumerator(Queue source) + { + return source.GetEnumerator(); + } + + protected override Queue Complete(ref Queue intermediateCollection) + { + return intermediateCollection; + } + + protected override CollectionDeserializeToBehaviour? SupportedOverwriteBehaviour + { + get + { + return deserializeToBehaviour; + } + } + + protected override void AddOnOverwriteDeserialize(ref Queue collection, int index, T value) + { + collection.Enqueue(value); + } + + protected override void ClearOnOverwriteDeserialize(ref Queue value) + { + value.Clear(); + } + } + + + // should deserialize reverse order. + public sealed class StackFormatter : CollectionFormatterBase, Stack.Enumerator, Stack> + { + protected override void Add(ref ArrayBuffer collection, int index, T value) + { + collection.Add(value); + } + + protected override ArrayBuffer Create() + { + return new ArrayBuffer(4); + } + + protected override Stack.Enumerator GetSourceEnumerator(Stack source) + { + return source.GetEnumerator(); + } + + protected override Stack Complete(ref ArrayBuffer intermediateCollection) + { + var bufArray = intermediateCollection.Buffer; + var stack = new Stack(intermediateCollection.Size); + for (int i = intermediateCollection.Size - 1; i >= 0; i--) + { + stack.Push(bufArray[i]); + } + return stack; + } + } + + public sealed class HashSetFormatter : CollectionFormatterBase, HashSet.Enumerator, HashSet> + { + protected override void Add(ref HashSet collection, int index, T value) + { + collection.Add(value); + } + + protected override HashSet Complete(ref HashSet intermediateCollection) + { + return intermediateCollection; + } + + protected override HashSet Create() + { + return new HashSet(); + } + + protected override HashSet.Enumerator GetSourceEnumerator(HashSet source) + { + return source.GetEnumerator(); + } + } + + public sealed class ReadOnlyCollectionFormatter : CollectionFormatterBase, ReadOnlyCollection> + { + protected override void Add(ref ArrayBuffer collection, int index, T value) + { + collection.Add(value); + } + + protected override ReadOnlyCollection Complete(ref ArrayBuffer intermediateCollection) + { + return new ReadOnlyCollection(intermediateCollection.ToArray()); + } + + protected override ArrayBuffer Create() + { + return new ArrayBuffer(4); + } + } + + public sealed class InterfaceListFormatter : CollectionFormatterBase, IList> + { + protected override void Add(ref List collection, int index, T value) + { + collection.Add(value); + } + + protected override List Create() + { + return new List(); + } + + protected override IList Complete(ref List intermediateCollection) + { + return intermediateCollection; + } + } + + public sealed class InterfaceCollectionFormatter : CollectionFormatterBase, ICollection> + { + protected override void Add(ref List collection, int index, T value) + { + collection.Add(value); + } + + protected override List Create() + { + return new List(); + } + + protected override ICollection Complete(ref List intermediateCollection) + { + return intermediateCollection; + } + } + + + public sealed class InterfaceEnumerableFormatter : CollectionFormatterBase, IEnumerable> + { + protected override void Add(ref ArrayBuffer collection, int index, T value) + { + collection.Add(value); + } + + protected override ArrayBuffer Create() + { + return new ArrayBuffer(4); + } + + protected override IEnumerable Complete(ref ArrayBuffer intermediateCollection) + { + return intermediateCollection.ToArray(); + } + } + + // {Key:key, Elements:[Array]} (not compatible with JSON.NET) + public sealed class InterfaceGroupingFormatter : IJsonFormatter> + { + public void Serialize(ref JsonWriter writer, IGrouping value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + return; + } + else + { + writer.WriteRaw(CollectionFormatterHelper.groupingName[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Key, formatterResolver); + writer.WriteRaw(CollectionFormatterHelper.groupingName[1]); + formatterResolver.GetFormatterWithVerify>().Serialize(ref writer, value.AsEnumerable(), formatterResolver); + + writer.WriteEndObject(); + } + } + + public IGrouping Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + TKey resultKey = default(TKey); + IEnumerable resultValue = default(IEnumerable); + + reader.ReadIsBeginObjectWithVerify(); + + var count = 0; + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + CollectionFormatterHelper.groupingAutomata.TryGetValue(keyString, out key); +#else + CollectionFormatterHelper.groupingAutomata.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + resultKey = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 1: + resultValue = formatterResolver.GetFormatterWithVerify>().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new Grouping(resultKey, resultValue); + } + } + } + + public sealed class InterfaceLookupFormatter : IJsonFormatter> + { + public void Serialize(ref JsonWriter writer, ILookup value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + return; + } + else + { + formatterResolver.GetFormatterWithVerify>>().Serialize(ref writer, value.AsEnumerable(), formatterResolver); + } + } + + public ILookup Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + if (reader.ReadIsNull()) return null; + + var count = 0; + + var formatter = formatterResolver.GetFormatterWithVerify>(); + var intermediateCollection = new Dictionary>(); + + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + var g = formatter.Deserialize(ref reader, formatterResolver); + intermediateCollection.Add(g.Key, g); + } + + return new Lookup(intermediateCollection); + } + } + } + + class Grouping : IGrouping + { + readonly TKey key; + readonly IEnumerable elements; + + public Grouping(TKey key, IEnumerable elements) + { + this.key = key; + this.elements = elements; + } + + public TKey Key + { + get + { + return key; + } + } + + public IEnumerator GetEnumerator() + { + return elements.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + class Lookup : ILookup + { + readonly Dictionary> groupings; + + public Lookup(Dictionary> groupings) + { + this.groupings = groupings; + } + + public IEnumerable this[TKey key] + { + get + { + return groupings[key]; + } + } + + public int Count + { + get + { + return groupings.Count; + } + } + + public bool Contains(TKey key) + { + return groupings.ContainsKey(key); + } + + public IEnumerator> GetEnumerator() + { + return groupings.Values.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return groupings.Values.GetEnumerator(); + } + } + + // NonGenerics + + public sealed class NonGenericListFormatter : IJsonFormatter + where T : class, IList, new() + { + public void Serialize(ref JsonWriter writer, T value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + return; + } + + var formatter = formatterResolver.GetFormatterWithVerify(); + + writer.WriteBeginArray(); + if (value.Count != 0) + { + formatter.Serialize(ref writer, value[0], formatterResolver); + } + for (int i = 1; i < value.Count; i++) + { + writer.WriteValueSeparator(); + formatter.Serialize(ref writer, value[i], formatterResolver); + } + writer.WriteEndArray(); + } + + public T Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var count = 0; + var formatter = formatterResolver.GetFormatterWithVerify(); + + var list = new T(); + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + list.Add(formatter.Deserialize(ref reader, formatterResolver)); + } + + return list; + } + } + + public sealed class NonGenericInterfaceEnumerableFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new NonGenericInterfaceEnumerableFormatter(); + + public void Serialize(ref JsonWriter writer, IEnumerable value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + return; + } + + var formatter = formatterResolver.GetFormatterWithVerify(); + + writer.WriteBeginArray(); + + var i = 0; + foreach (var item in value) + { + if (i != 0) writer.WriteValueSeparator(); + formatter.Serialize(ref writer, item, formatterResolver); + } + + writer.WriteEndArray(); + } + + public IEnumerable Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var count = 0; + var formatter = formatterResolver.GetFormatterWithVerify(); + + var list = new List(); + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + list.Add(formatter.Deserialize(ref reader, formatterResolver)); + } + + return list; + } + } + + public sealed class NonGenericInterfaceCollectionFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new NonGenericInterfaceCollectionFormatter(); + + public void Serialize(ref JsonWriter writer, ICollection value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + return; + } + + var formatter = formatterResolver.GetFormatterWithVerify(); + + writer.WriteBeginArray(); + var e = value.GetEnumerator(); + try + { + if (e.MoveNext()) + { + formatter.Serialize(ref writer, e.Current, formatterResolver); + while (e.MoveNext()) + { + writer.WriteValueSeparator(); + formatter.Serialize(ref writer, e.Current, formatterResolver); + } + } + } + finally + { + var d = e as IDisposable; + if (d != null) d.Dispose(); + } + writer.WriteEndArray(); + } + + public ICollection Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var count = 0; + var formatter = formatterResolver.GetFormatterWithVerify(); + + var list = new List(); + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + list.Add(formatter.Deserialize(ref reader, formatterResolver)); + } + + return list; + } + } + + public sealed class NonGenericInterfaceListFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new NonGenericInterfaceListFormatter(); + + public void Serialize(ref JsonWriter writer, IList value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + return; + } + + var formatter = formatterResolver.GetFormatterWithVerify(); + + writer.WriteBeginArray(); + if (value.Count != 0) + { + formatter.Serialize(ref writer, value[0], formatterResolver); + } + for (int i = 1; i < value.Count; i++) + { + writer.WriteValueSeparator(); + formatter.Serialize(ref writer, value[i], formatterResolver); + } + writer.WriteEndArray(); + } + + public IList Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var count = 0; + var formatter = formatterResolver.GetFormatterWithVerify(); + + var list = new List(); + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + list.Add(formatter.Deserialize(ref reader, formatterResolver)); + } + + return list; + } + } + + +#if NETSTANDARD + + public sealed class ObservableCollectionFormatter : CollectionFormatterBase> + { + protected override void Add(ref ObservableCollection collection, int index, T value) + { + collection.Add(value); + } + + protected override ObservableCollection Create() + { + return new ObservableCollection(); + } + } + + public sealed class ReadOnlyObservableCollectionFormatter : CollectionFormatterBase, ReadOnlyObservableCollection> + { + protected override void Add(ref ObservableCollection collection, int index, T value) + { + collection.Add(value); + } + + protected override ObservableCollection Create() + { + return new ObservableCollection(); + } + + protected override ReadOnlyObservableCollection Complete(ref ObservableCollection intermediateCollection) + { + return new ReadOnlyObservableCollection(intermediateCollection); + } + } + + public sealed class InterfaceReadOnlyListFormatter : CollectionFormatterBase, IReadOnlyList> + { + protected override void Add(ref ArrayBuffer collection, int index, T value) + { + collection.Add(value); + } + + protected override ArrayBuffer Create() + { + return new ArrayBuffer(4); + } + + protected override IReadOnlyList Complete(ref ArrayBuffer intermediateCollection) + { + return intermediateCollection.ToArray(); + } + } + + public sealed class InterfaceReadOnlyCollectionFormatter : CollectionFormatterBase, IReadOnlyCollection> + { + protected override void Add(ref ArrayBuffer collection, int index, T value) + { + collection.Add(value); + } + + protected override ArrayBuffer Create() + { + return new ArrayBuffer(4); + } + + protected override IReadOnlyCollection Complete(ref ArrayBuffer intermediateCollection) + { + return intermediateCollection.ToArray(); + } + } + + public sealed class InterfaceSetFormatter : CollectionFormatterBase, ISet> + { + protected override void Add(ref HashSet collection, int index, T value) + { + collection.Add(value); + } + + protected override ISet Complete(ref HashSet intermediateCollection) + { + return intermediateCollection; + } + + protected override HashSet Create() + { + return new HashSet(); + } + } + + public sealed class ConcurrentBagFormatter : CollectionFormatterBase> + { + protected override void Add(ref ConcurrentBag collection, int index, T value) + { + collection.Add(value); + } + + protected override ConcurrentBag Create() + { + return new ConcurrentBag(); + } + } + + public sealed class ConcurrentQueueFormatter : CollectionFormatterBase> + { + protected override void Add(ref ConcurrentQueue collection, int index, T value) + { + collection.Enqueue(value); + } + + protected override ConcurrentQueue Create() + { + return new ConcurrentQueue(); + } + } + + public sealed class ConcurrentStackFormatter : CollectionFormatterBase, ConcurrentStack> + { + protected override void Add(ref ArrayBuffer collection, int index, T value) + { + collection.Add(value); + } + + protected override ArrayBuffer Create() + { + return new ArrayBuffer(4); + } + + protected override ConcurrentStack Complete(ref ArrayBuffer intermediateCollection) + { + var bufArray = intermediateCollection.Buffer; + var stack = new ConcurrentStack(); + for (int i = intermediateCollection.Size - 1; i >= 0; i--) + { + stack.Push(bufArray[i]); + } + return stack; + } + } + +#endif +} + + +namespace Utf8Json.Formatters.Internal +{ + internal static class CollectionFormatterHelper + { + internal static readonly byte[][] groupingName; + internal static readonly AutomataDictionary groupingAutomata; + + static CollectionFormatterHelper() + { + groupingName = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Key"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Elements"), + }; + groupingAutomata = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Key"), 0 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Elements"), 1 }, + }; + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Formatters/DateTimeFormatter.cs b/Unity3D/3rdLib/Utf8Json/Formatters/DateTimeFormatter.cs new file mode 100644 index 0000000..3ddb272 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Formatters/DateTimeFormatter.cs @@ -0,0 +1,973 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using Utf8Json.Internal; + +namespace Utf8Json.Formatters +{ + public sealed class DateTimeFormatter : IJsonFormatter + { + readonly string formatString; + + public DateTimeFormatter() + { + this.formatString = null; + } + + public DateTimeFormatter(string formatString) + { + this.formatString = formatString; + } + + public void Serialize(ref JsonWriter writer, DateTime value, IJsonFormatterResolver formatterResolver) + { + writer.WriteString(value.ToString(formatString)); + } + + public DateTime Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var str = reader.ReadString(); + if (formatString == null) + { + return DateTime.Parse(str, CultureInfo.InvariantCulture); + } + else + { + return DateTime.ParseExact(str, formatString, CultureInfo.InvariantCulture); + } + } + } + + public sealed class NullableDateTimeFormatter : IJsonFormatter + { + readonly DateTimeFormatter innerFormatter; + + public NullableDateTimeFormatter() + { + this.innerFormatter = new DateTimeFormatter(); + } + + public NullableDateTimeFormatter(string formatString) + { + this.innerFormatter = new DateTimeFormatter(formatString); + } + + public void Serialize(ref JsonWriter writer, DateTime? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + innerFormatter.Serialize(ref writer, value.Value, formatterResolver); + } + + public DateTime? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + return innerFormatter.Deserialize(ref reader, formatterResolver); + } + } + + public sealed class ISO8601DateTimeFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new ISO8601DateTimeFormatter(); + + public void Serialize(ref JsonWriter writer, DateTime value, IJsonFormatterResolver formatterResolver) + { + var year = value.Year; + var month = value.Month; + var day = value.Day; + var hour = value.Hour; + var minute = value.Minute; + var second = value.Second; + var nanosec = value.Ticks % TimeSpan.TicksPerSecond; + + const int baseLength = 19 + 2; // {YEAR}-{MONTH}-{DAY}T{Hour}:{Minute}:{Second} + quotation + const int nanosecLength = 8; // .{nanoseconds} + + switch (value.Kind) + { + case DateTimeKind.Local: + // +{Hour}:{Minute} + writer.EnsureCapacity(baseLength + ((nanosec == 0) ? 0 : nanosecLength) + 6); + break; + case DateTimeKind.Utc: + // Z + writer.EnsureCapacity(baseLength + ((nanosec == 0) ? 0 : nanosecLength) + 1); + break; + case DateTimeKind.Unspecified: + default: + writer.EnsureCapacity(baseLength + ((nanosec == 0) ? 0 : nanosecLength)); + break; + } + + writer.WriteRawUnsafe((byte)'\"'); + + if (year < 10) + { + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + } + else if (year < 100) + { + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + } + else if (year < 1000) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(year); + writer.WriteRawUnsafe((byte)'-'); + + if (month < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(month); + writer.WriteRawUnsafe((byte)'-'); + + if (day < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(day); + + writer.WriteRawUnsafe((byte)'T'); + + if (hour < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(hour); + writer.WriteRawUnsafe((byte)':'); + + if (minute < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(minute); + writer.WriteRawUnsafe((byte)':'); + + if (second < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(second); + + if (nanosec != 0) + { + writer.WriteRawUnsafe((byte)'.'); + + if (nanosec < 10) + { + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + } + else if (nanosec < 100) + { + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + } + else if (nanosec < 1000) + { + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + } + else if (nanosec < 10000) + { + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + } + else if (nanosec < 100000) + { + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + } + else if (nanosec < 1000000) + { + writer.WriteRawUnsafe((byte)'0'); + } + + writer.WriteInt64(nanosec); + } + + switch (value.Kind) + { + case DateTimeKind.Local: + // should not use `BaseUtcOffset` - https://stackoverflow.com/questions/10019267/is-there-a-generic-timezoneinfo-for-central-europe + var localOffset = TimeZoneInfo.Local.GetUtcOffset(value); + var minus = (localOffset < TimeSpan.Zero); + if (minus) localOffset = localOffset.Negate(); + var h = localOffset.Hours; + var m = localOffset.Minutes; + writer.WriteRawUnsafe(minus ? (byte)'-' : (byte)'+'); + if (h < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(h); + writer.WriteRawUnsafe((byte)':'); + if (m < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(m); + break; + case DateTimeKind.Utc: + writer.WriteRawUnsafe((byte)'Z'); + break; + case DateTimeKind.Unspecified: + default: + break; + } + + writer.WriteRawUnsafe((byte)'\"'); + } + + public DateTime Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var str = reader.ReadStringSegmentUnsafe(); + var array = str.Array; + var i = str.Offset; + var len = str.Count; + var to = str.Offset + str.Count; + + // YYYY + if (len == 4) + { + var y = (array[i++] - (byte)'0') * 1000 + (array[i++] - (byte)'0') * 100 + (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + return new DateTime(y, 1, 1); + } + + // YYYY-MM + if (len == 7) + { + var y = (array[i++] - (byte)'0') * 1000 + (array[i++] - (byte)'0') * 100 + (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + if (array[i++] != (byte)'-') goto ERROR; + var m = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + return new DateTime(y, m, 1); + } + + // YYYY-MM-DD + if (len == 10) + { + var y = (array[i++] - (byte)'0') * 1000 + (array[i++] - (byte)'0') * 100 + (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + if (array[i++] != (byte)'-') goto ERROR; + var m = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + if (array[i++] != (byte)'-') goto ERROR; + var d = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + return new DateTime(y, m, d); + } + + // range-first section requires 19 + if (len < 19) goto ERROR; + + var year = (array[i++] - (byte)'0') * 1000 + (array[i++] - (byte)'0') * 100 + (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + if (array[i++] != (byte)'-') goto ERROR; + var month = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + if (array[i++] != (byte)'-') goto ERROR; + var day = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + + if (array[i++] != (byte)'T') goto ERROR; + + var hour = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + if (array[i++] != (byte)':') goto ERROR; + var minute = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + if (array[i++] != (byte)':') goto ERROR; + var second = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + + int ticks = 0; + if (i < to && array[i] == '.') + { + i++; + + // *7. + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 1000000; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 100000; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 10000; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 1000; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 100; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 10; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 1; + i++; + + // others, lack of precision + while (i < to && NumberConverter.IsNumber(array[i])) + { + i++; + } + } + + END_TICKS: + var kind = DateTimeKind.Unspecified; + if (i < to && array[i] == 'Z') + { + kind = DateTimeKind.Utc; + } + else if (i < to && array[i] == '-' || array[i] == '+') + { + if (!(i + 5 < to)) goto ERROR; + + kind = DateTimeKind.Local; + var minus = array[i++] == '-'; + + var h = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + i++; + var m = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + + var offset = new TimeSpan(h, m, 0); + if (minus) offset = offset.Negate(); + + return new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc).AddTicks(ticks).Subtract(offset).ToLocalTime(); + } + + return new DateTime(year, month, day, hour, minute, second, kind).AddTicks(ticks); + + ERROR: + throw new InvalidOperationException("invalid datetime format. value:" + StringEncoding.UTF8.GetString(str.Array, str.Offset, str.Count)); + } + } + + public sealed class UnixTimestampDateTimeFormatter : IJsonFormatter + { + static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + public void Serialize(ref JsonWriter writer, DateTime value, IJsonFormatterResolver formatterResolver) + { + var ticks = (long)(value.ToUniversalTime() - UnixEpoch).TotalSeconds; + writer.WriteQuotation(); + writer.WriteInt64(ticks); + writer.WriteQuotation(); + } + + public DateTime Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var str = reader.ReadStringSegmentUnsafe(); + int readCount; + var ticks = NumberConverter.ReadUInt64(str.Array, str.Offset, out readCount); + + return UnixEpoch.AddSeconds(ticks); + } + } + + public sealed class DateTimeOffsetFormatter : IJsonFormatter + { + readonly string formatString; + + public DateTimeOffsetFormatter() + { + this.formatString = null; + } + + public DateTimeOffsetFormatter(string formatString) + { + this.formatString = formatString; + } + + public void Serialize(ref JsonWriter writer, DateTimeOffset value, IJsonFormatterResolver formatterResolver) + { + writer.WriteString(value.ToString(formatString)); + } + + public DateTimeOffset Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var str = reader.ReadString(); + if (formatString == null) + { + return DateTimeOffset.Parse(str, CultureInfo.InvariantCulture); + } + else + { + return DateTimeOffset.ParseExact(str, formatString, CultureInfo.InvariantCulture); + } + } + } + + public sealed class NullableDateTimeOffsetFormatter : IJsonFormatter + { + readonly DateTimeOffsetFormatter innerFormatter; + + public NullableDateTimeOffsetFormatter() + { + this.innerFormatter = new DateTimeOffsetFormatter(); + } + + public NullableDateTimeOffsetFormatter(string formatString) + { + this.innerFormatter = new DateTimeOffsetFormatter(formatString); + } + + public void Serialize(ref JsonWriter writer, DateTimeOffset? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + innerFormatter.Serialize(ref writer, value.Value, formatterResolver); + } + + public DateTimeOffset? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + return innerFormatter.Deserialize(ref reader, formatterResolver); + } + } + + public sealed class ISO8601DateTimeOffsetFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new ISO8601DateTimeOffsetFormatter(); + + public void Serialize(ref JsonWriter writer, DateTimeOffset value, IJsonFormatterResolver formatterResolver) + { + var year = value.Year; + var month = value.Month; + var day = value.Day; + var hour = value.Hour; + var minute = value.Minute; + var second = value.Second; + var nanosec = value.Ticks % TimeSpan.TicksPerSecond; + + const int baseLength = 19 + 2; // {YEAR}-{MONTH}-{DAY}T{Hour}:{Minute}:{Second} + quotation + const int nanosecLength = 8; // .{nanoseconds} + + // +{Hour}:{Minute} + writer.EnsureCapacity(baseLength + ((nanosec == 0) ? 0 : nanosecLength) + 6); + + writer.WriteRawUnsafe((byte)'\"'); + + if (year < 10) + { + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + } + else if (year < 100) + { + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + } + else if (year < 1000) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(year); + writer.WriteRawUnsafe((byte)'-'); + + if (month < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(month); + writer.WriteRawUnsafe((byte)'-'); + + if (day < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(day); + + writer.WriteRawUnsafe((byte)'T'); + + if (hour < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(hour); + writer.WriteRawUnsafe((byte)':'); + + if (minute < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(minute); + writer.WriteRawUnsafe((byte)':'); + + if (second < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(second); + + if (nanosec != 0) + { + writer.WriteRawUnsafe((byte)'.'); + + if (nanosec < 10) + { + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + } + else if (nanosec < 100) + { + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + } + else if (nanosec < 1000) + { + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + } + else if (nanosec < 10000) + { + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + } + else if (nanosec < 100000) + { + writer.WriteRawUnsafe((byte)'0'); + writer.WriteRawUnsafe((byte)'0'); + } + else if (nanosec < 1000000) + { + writer.WriteRawUnsafe((byte)'0'); + } + + writer.WriteInt64(nanosec); + } + + var localOffset = value.Offset; + var minus = (localOffset < TimeSpan.Zero); + if (minus) localOffset = localOffset.Negate(); + var h = localOffset.Hours; + var m = localOffset.Minutes; + writer.WriteRawUnsafe(minus ? (byte)'-' : (byte)'+'); + if (h < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(h); + writer.WriteRawUnsafe((byte)':'); + if (m < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(m); + + writer.WriteRawUnsafe((byte)'\"'); + } + + public DateTimeOffset Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var str = reader.ReadStringSegmentUnsafe(); + var array = str.Array; + var i = str.Offset; + var len = str.Count; + var to = str.Offset + str.Count; + + // YYYY + if (len == 4) + { + var y = (array[i++] - (byte)'0') * 1000 + (array[i++] - (byte)'0') * 100 + (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + return new DateTimeOffset(y, 1, 1, 0, 0, 0, TimeSpan.Zero); + } + + // YYYY-MM + if (len == 7) + { + var y = (array[i++] - (byte)'0') * 1000 + (array[i++] - (byte)'0') * 100 + (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + if (array[i++] != (byte)'-') goto ERROR; + var m = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + return new DateTimeOffset(y, m, 1, 0, 0, 0, TimeSpan.Zero); + } + + // YYYY-MM-DD + if (len == 10) + { + var y = (array[i++] - (byte)'0') * 1000 + (array[i++] - (byte)'0') * 100 + (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + if (array[i++] != (byte)'-') goto ERROR; + var m = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + if (array[i++] != (byte)'-') goto ERROR; + var d = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + return new DateTimeOffset(y, m, d, 0, 0, 0, TimeSpan.Zero); + } + + // range-first section requires 19 + if (array.Length < 19) goto ERROR; + + var year = (array[i++] - (byte)'0') * 1000 + (array[i++] - (byte)'0') * 100 + (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + if (array[i++] != (byte)'-') goto ERROR; + var month = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + if (array[i++] != (byte)'-') goto ERROR; + var day = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + + if (array[i++] != (byte)'T') goto ERROR; + + var hour = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + if (array[i++] != (byte)':') goto ERROR; + var minute = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + if (array[i++] != (byte)':') goto ERROR; + var second = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + + int ticks = 0; + if (i < to && array[i] == '.') + { + i++; + + // *7. + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 1000000; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 100000; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 10000; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 1000; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 100; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 10; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 1; + i++; + + // others, lack of precision + while (i < to && NumberConverter.IsNumber(array[i])) + { + i++; + } + } + + END_TICKS: + + if (i < to && array[i] == '-' || array[i] == '+') + { + if (!(i + 5 < to)) goto ERROR; + + var minus = array[i++] == '-'; + + var h = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + i++; + var m = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + + var offset = new TimeSpan(h, m, 0); + if (minus) offset = offset.Negate(); + + return new DateTimeOffset(year, month, day, hour, minute, second, offset).AddTicks(ticks); + } + + return new DateTimeOffset(year, month, day, hour, minute, second, TimeSpan.Zero).AddTicks(ticks); + + ERROR: + throw new InvalidOperationException("invalid datetime format. value:" + StringEncoding.UTF8.GetString(str.Array, str.Offset, str.Count)); + } + } + + public sealed class TimeSpanFormatter : IJsonFormatter + { +#if NETSTANDARD + readonly string formatString; + + public TimeSpanFormatter() + { + this.formatString = null; + } + + public TimeSpanFormatter(string formatString) + { + this.formatString = formatString; + } +#endif + + public void Serialize(ref JsonWriter writer, TimeSpan value, IJsonFormatterResolver formatterResolver) + { +#if NETSTANDARD + writer.WriteString(value.ToString(formatString)); +#else + writer.WriteString(value.ToString()); +#endif + } + + public TimeSpan Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var str = reader.ReadString(); +#if NETSTANDARD + if (formatString == null) + { + return TimeSpan.Parse(str, CultureInfo.InvariantCulture); + } + else + { + return TimeSpan.ParseExact(str, formatString, CultureInfo.InvariantCulture); + } +#else + return TimeSpan.Parse(str); +#endif + } + } + + public sealed class NullableTimeSpanFormatter : IJsonFormatter + { + readonly TimeSpanFormatter innerFormatter; + + public NullableTimeSpanFormatter() + { + this.innerFormatter = new TimeSpanFormatter(); + } + +#if NETSTANDARD + public NullableTimeSpanFormatter(string formatString) + { + this.innerFormatter = new TimeSpanFormatter(formatString); + } +#endif + + public void Serialize(ref JsonWriter writer, TimeSpan? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + innerFormatter.Serialize(ref writer, value.Value, formatterResolver); + } + + public TimeSpan? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + return innerFormatter.Deserialize(ref reader, formatterResolver); + } + } + + public sealed class ISO8601TimeSpanFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new ISO8601TimeSpanFormatter(); + + static byte[] minValue = StringEncoding.UTF8.GetBytes("\"" + TimeSpan.MinValue.ToString() + "\""); + + public void Serialize(ref JsonWriter writer, TimeSpan value, IJsonFormatterResolver formatterResolver) + { + // can not negate, use cache + if (value == TimeSpan.MinValue) + { + writer.WriteRaw(minValue); + return; + } + + var minus = value < TimeSpan.Zero; + if (minus) value = value.Negate(); + var day = value.Days; + var hour = value.Hours; + var minute = value.Minutes; + var second = value.Seconds; + var nanosecond = value.Ticks % TimeSpan.TicksPerSecond; + + const int maxDayLength = 8 + 1; // {Day}. + const int baseLength = 8 + 2; // {Hour}:{Minute}:{Second} + quotation + const int nanosecLength = 8; // .{nanoseconds} + + writer.EnsureCapacity(baseLength + ((maxDayLength == 0) ? 0 : maxDayLength) + ((nanosecond == 0) ? 0 : nanosecLength) + 6); + + writer.WriteRawUnsafe((byte)'\"'); + + if (minus) + { + writer.WriteRawUnsafe((byte)'-'); + } + + if (day != 0) + { + writer.WriteInt32(day); + writer.WriteRawUnsafe((byte)'.'); + } + + if (hour < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(hour); + writer.WriteRawUnsafe((byte)':'); + + if (minute < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(minute); + writer.WriteRawUnsafe((byte)':'); + + if (second < 10) + { + writer.WriteRawUnsafe((byte)'0'); + } + writer.WriteInt32(second); + + if (nanosecond != 0) + { + writer.WriteRawUnsafe((byte)'.'); + writer.WriteInt64(nanosecond); + } + + writer.WriteRawUnsafe((byte)'\"'); + } + + public TimeSpan Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var str = reader.ReadStringSegmentUnsafe(); + var array = str.Array; + var i = str.Offset; + var len = str.Count; + var to = str.Offset + str.Count; + + // check day exists + bool hasDay = false; + { + bool foundDot = false; + bool foundColon = false; + for (int j = i; j < str.Count; j++) + { + if (array[j] == '.') + { + if (foundColon) + { + break; + } + foundDot = true; + } + else if (array[j] == ':') + { + if (foundDot) + { + hasDay = true; + } + foundColon = true; + } + } + } + + // check sign + var minus = false; + if (array[i] == '-') + { + minus = true; + i++; + } + + var day = 0; + if (hasDay) + { + var poolArray = BufferPool.Default.Rent(); + try + { + for (; array[i] != '.'; i++) + { + poolArray[day++] = array[i]; + } + day = new JsonReader(poolArray).ReadInt32(); + i++; // skip '.' + } + finally + { + BufferPool.Default.Return(poolArray); + } + } + + var hour = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + if (array[i++] != (byte)':') goto ERROR; + var minute = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + if (array[i++] != (byte)':') goto ERROR; + var second = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0'); + + int ticks = 0; + if (i < to && array[i] == '.') + { + i++; + + // *7. + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 1000000; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 100000; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 10000; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 1000; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 100; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 10; + i++; + + if (!(i < to) || !NumberConverter.IsNumber(array[i])) goto END_TICKS; + ticks += (array[i] - (byte)'0') * 1; + i++; + + // others, lack of precision + while (i < to && NumberConverter.IsNumber(array[i])) + { + i++; + } + } + + END_TICKS: + + // be careful to overflow + var ts = new TimeSpan(day, hour, minute, second); + var tk = TimeSpan.FromTicks(ticks); + return (minus) + ? ts.Negate().Subtract(tk) + : ts.Add(tk); + + ERROR: + throw new InvalidOperationException("invalid datetime format. value:" + StringEncoding.UTF8.GetString(str.Array, str.Offset, str.Count)); + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Formatters/DictionaryFormatter.cs b/Unity3D/3rdLib/Utf8Json/Formatters/DictionaryFormatter.cs new file mode 100644 index 0000000..7439615 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Formatters/DictionaryFormatter.cs @@ -0,0 +1,450 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +#if NETSTANDARD +using System.Collections.Concurrent; +#endif + +namespace Utf8Json.Formatters +{ + // unfortunately, can't use IDictionary because supports IReadOnlyDictionary. + public abstract class DictionaryFormatterBase : IJsonFormatter + where TDictionary : class, IEnumerable> + where TEnumerator : IEnumerator> + { + public void Serialize(ref JsonWriter writer, TDictionary value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + return; + } + else + { + var keyFormatter = formatterResolver.GetFormatterWithVerify() as IObjectPropertyNameFormatter; + var valueFormatter = formatterResolver.GetFormatterWithVerify(); + + writer.WriteBeginObject(); + + var e = GetSourceEnumerator(value); + try + { + if (keyFormatter != null) + { + if (e.MoveNext()) + { + var item = e.Current; + keyFormatter.SerializeToPropertyName(ref writer, item.Key, formatterResolver); + writer.WriteNameSeparator(); + valueFormatter.Serialize(ref writer, item.Value, formatterResolver); + } + else + { + goto END; + } + + while (e.MoveNext()) + { + writer.WriteValueSeparator(); + var item = e.Current; + keyFormatter.SerializeToPropertyName(ref writer, item.Key, formatterResolver); + writer.WriteNameSeparator(); + valueFormatter.Serialize(ref writer, item.Value, formatterResolver); + } + } + else + { + if (e.MoveNext()) + { + var item = e.Current; + writer.WriteString(item.Key.ToString()); + writer.WriteNameSeparator(); + valueFormatter.Serialize(ref writer, item.Value, formatterResolver); + } + else + { + goto END; + } + + while (e.MoveNext()) + { + writer.WriteValueSeparator(); + var item = e.Current; + writer.WriteString(item.Key.ToString()); + writer.WriteNameSeparator(); + valueFormatter.Serialize(ref writer, item.Value, formatterResolver); + } + } + } + finally + { + e.Dispose(); + } + + END: + writer.WriteEndObject(); + } + } + + public TDictionary Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + var keyFormatter = formatterResolver.GetFormatterWithVerify() as IObjectPropertyNameFormatter; + if (keyFormatter == null) throw new InvalidOperationException(typeof(TKey) + " does not support dictionary key deserialize."); + var valueFormatter = formatterResolver.GetFormatterWithVerify(); + + reader.ReadIsBeginObjectWithVerify(); + + var dict = Create(); + var i = 0; + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref i)) + { + var key = keyFormatter.DeserializeFromPropertyName(ref reader, formatterResolver); + reader.ReadIsNameSeparatorWithVerify(); + var value = valueFormatter.Deserialize(ref reader, formatterResolver); + Add(ref dict, i - 1, key, value); + } + + return Complete(ref dict); + } + } + + // abstraction for serialize + + // Some collections can use struct iterator, this is optimization path + protected abstract TEnumerator GetSourceEnumerator(TDictionary source); + + // abstraction for deserialize + protected abstract TIntermediate Create(); + protected abstract void Add(ref TIntermediate collection, int index, TKey key, TValue value); + protected abstract TDictionary Complete(ref TIntermediate intermediateCollection); + } + + public abstract class DictionaryFormatterBase : DictionaryFormatterBase>, TDictionary> + where TDictionary : class, IEnumerable> + { + protected override IEnumerator> GetSourceEnumerator(TDictionary source) + { + return source.GetEnumerator(); + } + } + + public abstract class DictionaryFormatterBase : DictionaryFormatterBase + where TDictionary : class, IDictionary + { + protected override TDictionary Complete(ref TDictionary intermediateCollection) + { + return intermediateCollection; + } + } + + + public sealed class DictionaryFormatter : DictionaryFormatterBase, Dictionary.Enumerator, Dictionary> + { + protected override void Add(ref Dictionary collection, int index, TKey key, TValue value) + { + collection.Add(key, value); + } + + protected override Dictionary Complete(ref Dictionary intermediateCollection) + { + return intermediateCollection; + } + + protected override Dictionary Create() + { + return new Dictionary(); + } + + protected override Dictionary.Enumerator GetSourceEnumerator(Dictionary source) + { + return source.GetEnumerator(); + } + } + + public sealed class GenericDictionaryFormatter : DictionaryFormatterBase + where TDictionary : class, IDictionary, new() + { + protected override void Add(ref TDictionary collection, int index, TKey key, TValue value) + { + collection.Add(key, value); + } + + protected override TDictionary Create() + { + return new TDictionary(); + } + } + + public sealed class InterfaceDictionaryFormatter : DictionaryFormatterBase, IDictionary> + { + protected override void Add(ref Dictionary collection, int index, TKey key, TValue value) + { + collection.Add(key, value); + } + + protected override Dictionary Create() + { + return new Dictionary(); + } + + protected override IDictionary Complete(ref Dictionary intermediateCollection) + { + return intermediateCollection; + } + } + + public sealed class SortedListFormatter : DictionaryFormatterBase> + { + protected override void Add(ref SortedList collection, int index, TKey key, TValue value) + { + collection.Add(key, value); + } + + protected override SortedList Create() + { + return new SortedList(); + } + } + + public sealed class SortedDictionaryFormatter : DictionaryFormatterBase, SortedDictionary.Enumerator, SortedDictionary> + { + protected override void Add(ref SortedDictionary collection, int index, TKey key, TValue value) + { + collection.Add(key, value); + } + + protected override SortedDictionary Complete(ref SortedDictionary intermediateCollection) + { + return intermediateCollection; + } + + protected override SortedDictionary Create() + { + return new SortedDictionary(); + } + + protected override SortedDictionary.Enumerator GetSourceEnumerator(SortedDictionary source) + { + return source.GetEnumerator(); + } + } + +#if NETSTANDARD + + public sealed class ReadOnlyDictionaryFormatter : DictionaryFormatterBase, ReadOnlyDictionary> + { + protected override void Add(ref Dictionary collection, int index, TKey key, TValue value) + { + collection.Add(key, value); + } + + protected override ReadOnlyDictionary Complete(ref Dictionary intermediateCollection) + { + return new ReadOnlyDictionary(intermediateCollection); + } + + protected override Dictionary Create() + { + return new Dictionary(); + } + } + + public sealed class InterfaceReadOnlyDictionaryFormatter : DictionaryFormatterBase, IReadOnlyDictionary> + { + protected override void Add(ref Dictionary collection, int index, TKey key, TValue value) + { + collection.Add(key, value); + } + + protected override IReadOnlyDictionary Complete(ref Dictionary intermediateCollection) + { + return intermediateCollection; + } + + protected override Dictionary Create() + { + return new Dictionary(); + } + } + + public sealed class ConcurrentDictionaryFormatter : DictionaryFormatterBase> + { + protected override void Add(ref ConcurrentDictionary collection, int index, TKey key, TValue value) + { + collection.TryAdd(key, value); + } + + protected override ConcurrentDictionary Create() + { + // concurrent dictionary can't access defaultConcurrecyLevel so does not use count overload. + return new ConcurrentDictionary(); + } + } + +#endif + + public sealed class NonGenericDictionaryFormatter : IJsonFormatter + where T : class, System.Collections.IDictionary, new() + { + public void Serialize(ref JsonWriter writer, T value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + return; + } + else + { + var valueFormatter = formatterResolver.GetFormatterWithVerify(); + + writer.WriteBeginObject(); + + var e = value.GetEnumerator(); + try + { + if (e.MoveNext()) + { + System.Collections.DictionaryEntry item = (System.Collections.DictionaryEntry)e.Current; + writer.WritePropertyName(item.Key.ToString()); + valueFormatter.Serialize(ref writer, item.Value, formatterResolver); + } + else + { + goto END; + } + + while (e.MoveNext()) + { + writer.WriteValueSeparator(); + System.Collections.DictionaryEntry item = (System.Collections.DictionaryEntry)e.Current; + writer.WritePropertyName(item.Key.ToString()); + valueFormatter.Serialize(ref writer, item.Value, formatterResolver); + } + } + finally + { + var disp = e as IDisposable; + if (disp != null) + { + disp.Dispose(); + } + } + + END: + writer.WriteEndObject(); + } + } + + public T Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return default(T); + } + else + { + var valueFormatter = formatterResolver.GetFormatterWithVerify(); + + reader.ReadIsBeginObjectWithVerify(); + + var dict = new T(); + var i = 0; + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref i)) + { + var key = reader.ReadPropertyName(); + var value = valueFormatter.Deserialize(ref reader, formatterResolver); + dict.Add(key, value); + } + + return dict; + } + } + } + + public sealed class NonGenericInterfaceDictionaryFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new NonGenericInterfaceDictionaryFormatter(); + + + public void Serialize(ref JsonWriter writer, System.Collections.IDictionary value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + return; + } + else + { + var valueFormatter = formatterResolver.GetFormatterWithVerify(); + + writer.WriteBeginObject(); + + var e = value.GetEnumerator(); + try + { + if (e.MoveNext()) + { + System.Collections.DictionaryEntry item = (System.Collections.DictionaryEntry)e.Current; + writer.WritePropertyName(item.Key.ToString()); + valueFormatter.Serialize(ref writer, item.Value, formatterResolver); + } + else + { + goto END; + } + + while (e.MoveNext()) + { + writer.WriteValueSeparator(); + System.Collections.DictionaryEntry item = (System.Collections.DictionaryEntry)e.Current; + writer.WritePropertyName(item.Key.ToString()); + valueFormatter.Serialize(ref writer, item.Value, formatterResolver); + } + } + finally + { + var disp = e as IDisposable; + if (disp != null) + { + disp.Dispose(); + } + } + + END: + writer.WriteEndObject(); + } + } + + public System.Collections.IDictionary Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + var valueFormatter = formatterResolver.GetFormatterWithVerify(); + + reader.ReadIsBeginObjectWithVerify(); + + var dict = new Dictionary(); + var i = 0; + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref i)) + { + var key = reader.ReadPropertyName(); + var value = valueFormatter.Deserialize(ref reader, formatterResolver); + dict.Add(key, value); + } + + return dict; + } + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Formatters/DynamicObjectTypeFallbackFormatter.cs b/Unity3D/3rdLib/Utf8Json/Formatters/DynamicObjectTypeFallbackFormatter.cs new file mode 100644 index 0000000..c38ae1e --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Formatters/DynamicObjectTypeFallbackFormatter.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using Utf8Json.Internal; +using Utf8Json.Internal.Emit; + +namespace Utf8Json.Formatters +{ + public sealed class DynamicObjectTypeFallbackFormatter : IJsonFormatter + { + delegate void SerializeMethod(object dynamicFormatter, ref JsonWriter writer, object value, IJsonFormatterResolver formatterResolver); + + readonly ThreadsafeTypeKeyHashTable> serializers = new ThreadsafeTypeKeyHashTable>(); + + readonly IJsonFormatterResolver[] innerResolvers; + + public DynamicObjectTypeFallbackFormatter(params IJsonFormatterResolver[] innerResolvers) + { + this.innerResolvers = innerResolvers; + } + + public void Serialize(ref JsonWriter writer, object value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + var type = value.GetType(); + + if (type == typeof(object)) + { + // serialize to empty object + writer.WriteBeginObject(); + writer.WriteEndObject(); + return; + } + + KeyValuePair formatterAndDelegate; + if (!serializers.TryGetValue(type, out formatterAndDelegate)) + { + lock (serializers) + { + if (!serializers.TryGetValue(type, out formatterAndDelegate)) + { + object formatter = null; + foreach (var innerResolver in innerResolvers) + { + formatter = innerResolver.GetFormatterDynamic(type); + if (formatter != null) break; + } + if (formatter == null) + { + throw new FormatterNotRegisteredException(type.FullName + " is not registered in this resolver. resolvers:" + string.Join(", ", innerResolvers.Select(x => x.GetType().Name).ToArray())); + } + + var t = type; + { + var dm = new DynamicMethod("Serialize", null, new[] { typeof(object), typeof(JsonWriter).MakeByRefType(), typeof(object), typeof(IJsonFormatterResolver) }, type.Module, true); + var il = dm.GetILGenerator(); + + // delegate void SerializeMethod(object dynamicFormatter, ref JsonWriter writer, object value, IJsonFormatterResolver formatterResolver); + + il.EmitLdarg(0); + il.Emit(OpCodes.Castclass, typeof(IJsonFormatter<>).MakeGenericType(t)); + il.EmitLdarg(1); + il.EmitLdarg(2); + il.EmitUnboxOrCast(t); + il.EmitLdarg(3); + + il.EmitCall(Resolvers.Internal.DynamicObjectTypeBuilder.EmitInfo.Serialize(t)); + + il.Emit(OpCodes.Ret); + + formatterAndDelegate = new KeyValuePair(formatter, (SerializeMethod)dm.CreateDelegate(typeof(SerializeMethod))); + } + + serializers.TryAdd(t, formatterAndDelegate); + } + } + } + + formatterAndDelegate.Value(formatterAndDelegate.Key, ref writer, value, formatterResolver); + } + + public object Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + return PrimitiveObjectFormatter.Default.Deserialize(ref reader, formatterResolver); + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Formatters/EnumFormatter.cs b/Unity3D/3rdLib/Utf8Json/Formatters/EnumFormatter.cs new file mode 100644 index 0000000..f614d5a --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Formatters/EnumFormatter.cs @@ -0,0 +1,297 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using Utf8Json.Internal; +using System.Runtime.Serialization; + +namespace Utf8Json.Formatters +{ + public static class EnumFormatterHelper + { + public static object GetSerializeDelegate(Type type, out bool isBoxed) + { + var underlyingType = Enum.GetUnderlyingType(type); + +#if NETSTANDARD + isBoxed = false; + var dynamicMethod = new DynamicMethod("EnumSerializeByUnderlyingValue", null, new[] { typeof(JsonWriter).MakeByRefType(), type, typeof(IJsonFormatterResolver) }, type.Module, true); + var il = dynamicMethod.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); // writer + il.Emit(OpCodes.Ldarg_1); // value + il.Emit(OpCodes.Call, typeof(JsonWriter).GetRuntimeMethod("Write" + underlyingType.Name, new[] { underlyingType })); + il.Emit(OpCodes.Ret); + return dynamicMethod.CreateDelegate(typeof(JsonSerializeAction<>).MakeGenericType(type)); +#else + // Boxed + isBoxed = true; + JsonSerializeAction f; + if (underlyingType == typeof(byte)) + { + f = (ref JsonWriter writer, object value, IJsonFormatterResolver _) => writer.WriteByte((byte)value); + } + else if (underlyingType == typeof(sbyte)) + { + f = (ref JsonWriter writer, object value, IJsonFormatterResolver _) => writer.WriteSByte((sbyte)value); + } + else if (underlyingType == typeof(short)) + { + f = (ref JsonWriter writer, object value, IJsonFormatterResolver _) => writer.WriteInt16((short)value); + } + else if (underlyingType == typeof(ushort)) + { + f = (ref JsonWriter writer, object value, IJsonFormatterResolver _) => writer.WriteUInt16((ushort)value); + } + else if (underlyingType == typeof(int)) + { + f = (ref JsonWriter writer, object value, IJsonFormatterResolver _) => writer.WriteInt32((int)value); + } + else if (underlyingType == typeof(uint)) + { + f = (ref JsonWriter writer, object value, IJsonFormatterResolver _) => writer.WriteUInt32((uint)value); + } + else if (underlyingType == typeof(long)) + { + f = (ref JsonWriter writer, object value, IJsonFormatterResolver _) => writer.WriteInt64((long)value); + } + else if (underlyingType == typeof(ulong)) + { + f = (ref JsonWriter writer, object value, IJsonFormatterResolver _) => writer.WriteUInt64((ulong)value); + } + else + { + throw new InvalidOperationException("Type is not Enum. Type:" + type); + } + return f; +#endif + } + + public static object GetDeserializeDelegate(Type type, out bool isBoxed) + { + var underlyingType = Enum.GetUnderlyingType(type); + +#if NETSTANDARD + isBoxed = false; + var dynamicMethod = new DynamicMethod("EnumDeserializeByUnderlyingValue", type, new[] { typeof(JsonReader).MakeByRefType(), typeof(IJsonFormatterResolver) }, type.Module, true); + var il = dynamicMethod.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); // reader + il.Emit(OpCodes.Call, typeof(JsonReader).GetRuntimeMethod("Read" + underlyingType.Name, Type.EmptyTypes)); + il.Emit(OpCodes.Ret); + return dynamicMethod.CreateDelegate(typeof(JsonDeserializeFunc<>).MakeGenericType(type)); +#else + // Boxed + isBoxed = true; + JsonDeserializeFunc f; + if (underlyingType == typeof(byte)) + { + f = (ref JsonReader reader, IJsonFormatterResolver _) => (object)reader.ReadByte(); + } + else if (underlyingType == typeof(sbyte)) + { + f = (ref JsonReader reader, IJsonFormatterResolver _) => (object)reader.ReadSByte(); + } + else if (underlyingType == typeof(short)) + { + f = (ref JsonReader reader, IJsonFormatterResolver _) => (object)reader.ReadInt16(); + } + else if (underlyingType == typeof(ushort)) + { + f = (ref JsonReader reader, IJsonFormatterResolver _) => (object)reader.ReadUInt16(); + } + else if (underlyingType == typeof(int)) + { + f = (ref JsonReader reader, IJsonFormatterResolver _) => (object)reader.ReadInt32(); + } + else if (underlyingType == typeof(uint)) + { + f = (ref JsonReader reader, IJsonFormatterResolver _) => (object)reader.ReadUInt32(); + } + else if (underlyingType == typeof(long)) + { + f = (ref JsonReader reader, IJsonFormatterResolver _) => (object)reader.ReadInt64(); + } + else if (underlyingType == typeof(ulong)) + { + f = (ref JsonReader reader, IJsonFormatterResolver _) => (object)reader.ReadUInt64(); + } + else + { + throw new InvalidOperationException("Type is not Enum. Type:" + type); + } + return f; +#endif + } + } +} + +namespace Utf8Json.Formatters +{ + // can inehrit for set optimize manual serialize/deserialize func. + public class EnumFormatter : IJsonFormatter, IObjectPropertyNameFormatter + { + readonly static ByteArrayStringHashTable nameValueMapping; + readonly static Dictionary valueNameMapping; + + readonly static JsonSerializeAction defaultSerializeByUnderlyingValue; + readonly static JsonDeserializeFunc defaultDeserializeByUnderlyingValue; + + static EnumFormatter() + { + var names = new List(); + var values = new List(); + + var type = typeof(T); + foreach (var item in type.GetFields().Where(fi => fi.FieldType == type)) + { + var value = item.GetValue(null); + var name = Enum.GetName(type, value); + var dataMember = item.GetCustomAttributes(typeof(DataMemberAttribute), true) + .OfType() + .FirstOrDefault(); + var enumMember = item.GetCustomAttributes(typeof(EnumMemberAttribute), true) + .OfType() + .FirstOrDefault(); + + values.Add(value); + names.Add( + (enumMember != null && enumMember.Value != null) ? enumMember.Value + : (dataMember != null && dataMember.Name != null) ? dataMember.Name + : name); + } + + nameValueMapping = new ByteArrayStringHashTable(names.Count); + valueNameMapping = new Dictionary(names.Count); + + for (int i = 0; i < names.Count; i++) + { + nameValueMapping.Add(JsonWriter.GetEncodedPropertyNameWithoutQuotation(names[i]), (T)values[i]); + valueNameMapping[(T)values[i]] = names[i]; + } + + // boxed... or generate... + { + bool isBoxed; + var serialize = EnumFormatterHelper.GetSerializeDelegate(typeof(T), out isBoxed); + if (isBoxed) + { + var boxSerialize = (JsonSerializeAction)serialize; + defaultSerializeByUnderlyingValue = (ref JsonWriter writer, T value, IJsonFormatterResolver _) => boxSerialize.Invoke(ref writer, (object)value, _); + } + else + { + defaultSerializeByUnderlyingValue = (JsonSerializeAction)serialize; + } + } + + { + bool isBoxed; + var deserialize = EnumFormatterHelper.GetDeserializeDelegate(typeof(T), out isBoxed); + if (isBoxed) + { + var boxDeserialize = (JsonDeserializeFunc)deserialize; + defaultDeserializeByUnderlyingValue = (ref JsonReader reader, IJsonFormatterResolver _) => (T)boxDeserialize.Invoke(ref reader, _); + } + else + { + defaultDeserializeByUnderlyingValue = (JsonDeserializeFunc)deserialize; + } + } + } + + readonly bool serializeByName; + readonly JsonSerializeAction serializeByUnderlyingValue; + readonly JsonDeserializeFunc deserializeByUnderlyingValue; + + public EnumFormatter(bool serializeByName) + { + this.serializeByName = serializeByName; + this.serializeByUnderlyingValue = defaultSerializeByUnderlyingValue; + this.deserializeByUnderlyingValue = defaultDeserializeByUnderlyingValue; + } + + /// + /// If can not use dynamic code-generation environment and want to avoid boxing, you can set func manually. + /// + public EnumFormatter(JsonSerializeAction valueSerializeAction, JsonDeserializeFunc valueDeserializeAction) + { + this.serializeByName = false; + this.serializeByUnderlyingValue = valueSerializeAction; + this.deserializeByUnderlyingValue = valueDeserializeAction; + } + + public void Serialize(ref JsonWriter writer, T value, IJsonFormatterResolver formatterResolver) + { + if (serializeByName) + { + string name; + if (!valueNameMapping.TryGetValue(value, out name)) + { + name = value.ToString(); // fallback for flags etc. But Enum.ToString is slow... + } + writer.WriteString(name); + } + else + { + serializeByUnderlyingValue(ref writer, value, formatterResolver); + } + } + + public T Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var token = reader.GetCurrentJsonToken(); + + if (token == JsonToken.String) + { + // avoid string decoding if possible. + var key = reader.ReadStringSegmentUnsafe(); + + T value; + if (!nameValueMapping.TryGetValue(key, out value)) + { + var str = StringEncoding.UTF8.GetString(key.Array, key.Offset, key.Count); + value = (T)Enum.Parse(typeof(T), str); // Enum.Parse is slow + } + return value; + } + else if (token == JsonToken.Number) + { + return deserializeByUnderlyingValue(ref reader, formatterResolver); + } + + throw new InvalidOperationException("Can't parse JSON to Enum format."); + } + + public void SerializeToPropertyName(ref JsonWriter writer, T value, IJsonFormatterResolver formatterResolver) + { + if (serializeByName) + { + Serialize(ref writer, value, formatterResolver); + } + else + { + writer.WriteQuotation(); + Serialize(ref writer, value, formatterResolver); + writer.WriteQuotation(); + } + } + + public T DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (serializeByName) + { + return Deserialize(ref reader, formatterResolver); + } + else + { + var token = reader.GetCurrentJsonToken(); + if (token != JsonToken.String) throw new InvalidOperationException("Can't parse JSON to Enum format."); + reader.AdvanceOffset(1); // skip \"" + var t = Deserialize(ref reader, formatterResolver); // token is Number + reader.SkipWhiteSpace(); + reader.AdvanceOffset(1); // skip \"" + return t; + } + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Formatters/IgnoreFormatter.cs b/Unity3D/3rdLib/Utf8Json/Formatters/IgnoreFormatter.cs new file mode 100644 index 0000000..f6a1579 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Formatters/IgnoreFormatter.cs @@ -0,0 +1,18 @@ +using System; + +namespace Utf8Json.Formatters +{ + public sealed class IgnoreFormatter : IJsonFormatter + { + public void Serialize(ref JsonWriter writer, T value, IJsonFormatterResolver formatterResolver) + { + writer.WriteNull(); + } + + public T Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + reader.ReadNextBlock(); + return default(T); + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Formatters/MultiDimentionalArrayFormatter.cs b/Unity3D/3rdLib/Utf8Json/Formatters/MultiDimentionalArrayFormatter.cs new file mode 100644 index 0000000..10fe105 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Formatters/MultiDimentionalArrayFormatter.cs @@ -0,0 +1,269 @@ +using Utf8Json.Internal; + +namespace Utf8Json.Formatters +{ + // multi dimentional array serialize to [[seq], [seq]] + + public sealed class TwoDimentionalArrayFormatter : IJsonFormatter + { + public void Serialize(ref JsonWriter writer, T[,] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + var formatter = formatterResolver.GetFormatterWithVerify(); + + var iLength = value.GetLength(0); + var jLength = value.GetLength(1); + + writer.WriteBeginArray(); + for (int i = 0; i < iLength; i++) + { + if (i != 0) writer.WriteValueSeparator(); + writer.WriteBeginArray(); + for (int j = 0; j < jLength; j++) + { + if (j != 0) writer.WriteValueSeparator(); + formatter.Serialize(ref writer, value[i, j], formatterResolver); + } + writer.WriteEndArray(); + } + writer.WriteEndArray(); + } + } + + public T[,] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var buffer = new ArrayBuffer>(4); + var formatter = formatterResolver.GetFormatterWithVerify(); + + var guessInnerLength = 0; + var outerCount = 0; + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref outerCount)) + { + var innerArray = new ArrayBuffer(guessInnerLength == 0 ? 4 : guessInnerLength); + var innerCount = 0; + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref innerCount)) + { + innerArray.Add(formatter.Deserialize(ref reader, formatterResolver)); + } + + guessInnerLength = innerArray.Size; + buffer.Add(innerArray); + } + + var t = new T[buffer.Size, guessInnerLength]; + for (int i = 0; i < buffer.Size; i++) + { + for (int j = 0; j < guessInnerLength; j++) + { + t[i, j] = buffer.Buffer[i].Buffer[j]; + } + } + + return t; + } + } + + public sealed class ThreeDimentionalArrayFormatter : IJsonFormatter + { + public void Serialize(ref JsonWriter writer, T[,,] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + var formatter = formatterResolver.GetFormatterWithVerify(); + + var iLength = value.GetLength(0); + var jLength = value.GetLength(1); + var kLength = value.GetLength(2); + + writer.WriteBeginArray(); + for (int i = 0; i < iLength; i++) + { + if (i != 0) writer.WriteValueSeparator(); + writer.WriteBeginArray(); + for (int j = 0; j < jLength; j++) + { + if (j != 0) writer.WriteValueSeparator(); + writer.WriteBeginArray(); + for (int k = 0; k < kLength; k++) + { + if (k != 0) writer.WriteValueSeparator(); + formatter.Serialize(ref writer, value[i, j, k], formatterResolver); + } + writer.WriteEndArray(); + } + writer.WriteEndArray(); + } + writer.WriteEndArray(); + } + } + + public T[,,] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var buffer = new ArrayBuffer>>(4); + var formatter = formatterResolver.GetFormatterWithVerify(); + + var guessInnerLength2 = 0; + var guessInnerLength = 0; + var outerCount = 0; + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref outerCount)) + { + var innerArray = new ArrayBuffer>(guessInnerLength == 0 ? 4 : guessInnerLength); + var innerCount = 0; + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref innerCount)) + { + var innerArray2 = new ArrayBuffer(guessInnerLength2 == 0 ? 4 : guessInnerLength2); + var innerCount2 = 0; + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref innerCount2)) + { + innerArray2.Add(formatter.Deserialize(ref reader, formatterResolver)); + } + + guessInnerLength2 = innerArray2.Size; + innerArray.Add(innerArray2); + } + + guessInnerLength = innerArray.Size; + buffer.Add(innerArray); + } + + var t = new T[buffer.Size, guessInnerLength, guessInnerLength2]; + for (int i = 0; i < buffer.Size; i++) + { + for (int j = 0; j < guessInnerLength; j++) + { + for (int k = 0; k < guessInnerLength2; k++) + { + t[i, j, k] = buffer.Buffer[i].Buffer[j].Buffer[k]; + } + } + } + + return t; + } + } + + public sealed class FourDimentionalArrayFormatter : IJsonFormatter + { + public void Serialize(ref JsonWriter writer, T[,,,] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + var formatter = formatterResolver.GetFormatterWithVerify(); + + var iLength = value.GetLength(0); + var jLength = value.GetLength(1); + var kLength = value.GetLength(2); + var lLength = value.GetLength(3); + + writer.WriteBeginArray(); + for (int i = 0; i < iLength; i++) + { + if (i != 0) writer.WriteValueSeparator(); + writer.WriteBeginArray(); + for (int j = 0; j < jLength; j++) + { + if (j != 0) writer.WriteValueSeparator(); + writer.WriteBeginArray(); + for (int k = 0; k < kLength; k++) + { + if (k != 0) writer.WriteValueSeparator(); + writer.WriteBeginArray(); + for (int l = 0; l < lLength; l++) + { + if (l != 0) writer.WriteValueSeparator(); + formatter.Serialize(ref writer, value[i, j, k, l], formatterResolver); + } + writer.WriteEndArray(); + } + writer.WriteEndArray(); + } + writer.WriteEndArray(); + } + writer.WriteEndArray(); + } + } + + public T[,,,] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var buffer = new ArrayBuffer>>>(4); + var formatter = formatterResolver.GetFormatterWithVerify(); + + var guessInnerLength3 = 0; + var guessInnerLength2 = 0; + var guessInnerLength = 0; + var outerCount = 0; + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref outerCount)) + { + var innerArray = new ArrayBuffer>>(guessInnerLength == 0 ? 4 : guessInnerLength); + var innerCount = 0; + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref innerCount)) + { + var innerArray2 = new ArrayBuffer>(guessInnerLength2 == 0 ? 4 : guessInnerLength2); + var innerCount2 = 0; + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref innerCount2)) + { + var innerArray3 = new ArrayBuffer(guessInnerLength3 == 0 ? 4 : guessInnerLength3); + var innerCount3 = 0; + reader.ReadIsBeginArrayWithVerify(); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref innerCount3)) + { + innerArray3.Add(formatter.Deserialize(ref reader, formatterResolver)); + } + guessInnerLength3 = innerArray3.Size; + innerArray2.Add(innerArray3); + } + + guessInnerLength2 = innerArray2.Size; + innerArray.Add(innerArray2); + } + + guessInnerLength = innerArray.Size; + buffer.Add(innerArray); + } + + var t = new T[buffer.Size, guessInnerLength, guessInnerLength2, guessInnerLength3]; + for (int i = 0; i < buffer.Size; i++) + { + for (int j = 0; j < guessInnerLength; j++) + { + for (int k = 0; k < guessInnerLength2; k++) + { + for (int l = 0; l < guessInnerLength3; l++) + { + t[i, j, k, l] = buffer.Buffer[i].Buffer[j].Buffer[k].Buffer[l]; + } + } + } + } + + return t; + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Formatters/NullableFormatter.cs b/Unity3D/3rdLib/Utf8Json/Formatters/NullableFormatter.cs new file mode 100644 index 0000000..3d3dc4f --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Formatters/NullableFormatter.cs @@ -0,0 +1,80 @@ + +using System; + +namespace Utf8Json.Formatters +{ + public sealed class NullableFormatter : IJsonFormatter + where T : struct + { + public void Serialize(ref JsonWriter writer, T? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Value, formatterResolver); + } + } + + public T? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + return formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + } + } + } + + public sealed class StaticNullableFormatter : IJsonFormatter + where T : struct + { + readonly IJsonFormatter underlyingFormatter; + + public StaticNullableFormatter(IJsonFormatter underlyingFormatter) + { + this.underlyingFormatter = underlyingFormatter; + } + + public StaticNullableFormatter(Type formatterType, object[] formatterArguments) + { + try + { + underlyingFormatter = (IJsonFormatter)Activator.CreateInstance(formatterType, formatterArguments); + } + catch (Exception ex) + { + throw new InvalidOperationException("Can not create formatter from JsonFormatterAttribute, check the target formatter is public and has constructor with right argument. FormatterType:" + formatterType.Name, ex); + } + } + + public void Serialize(ref JsonWriter writer, T? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + underlyingFormatter.Serialize(ref writer, value.Value, formatterResolver); + } + } + + public T? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + return underlyingFormatter.Deserialize(ref reader, formatterResolver); + } + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Formatters/PocoObjectFormatter.cs b/Unity3D/3rdLib/Utf8Json/Formatters/PocoObjectFormatter.cs new file mode 100644 index 0000000..ca36007 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Formatters/PocoObjectFormatter.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using Utf8Json.Resolvers; + +namespace Utf8Json.Formatters +{ + internal class PocoObjectFormatter : IJsonFormatter + { + private static ListFormatter listFormater = new ListFormatter(); + private static ListFormatter listStrFormater = new ListFormatter(); + private static ListFormatter listObjectFormater = new ListFormatter(); + private static ArrayFormatter objectArrayFormater = new ArrayFormatter(); + public static DictionaryFormatter floatDictFormater = new DictionaryFormatter(); + public void Serialize(ref JsonWriter writer, object value, IJsonFormatterResolver formatterResolver) + { + switch (value) + { + case Dictionary dict: + PocoResolver.dictFormater.Serialize(ref writer,dict,formatterResolver); + break; + case List list: + listFormater.Serialize(ref writer, list, formatterResolver); + break; + case List listStr: + listStrFormater.Serialize(ref writer, listStr, formatterResolver); + break; + case string s: + NullableStringFormatter.Default.Serialize(ref writer, s, formatterResolver); + break; + case bool b: + BooleanFormatter.Default.Serialize(ref writer, b, formatterResolver); + break; + case int i: + Int32Formatter.Default.Serialize(ref writer, i, formatterResolver); + break; + case List objList: + listObjectFormater.Serialize(ref writer, objList, formatterResolver); + break; + case float f: + SingleFormatter.Default.Serialize(ref writer, f, formatterResolver); + break; + case long l: + Int64Formatter.Default.Serialize(ref writer, l, formatterResolver); + break; + case null: + NullableStringFormatter.Default.Serialize(ref writer, null, formatterResolver); + break; + case float[] fs: + SingleArrayFormatter.Default.Serialize(ref writer, fs, formatterResolver); + break; + case Dictionary fDict: + floatDictFormater.Serialize(ref writer, fDict, formatterResolver); + break; + case object[] objectArray: + objectArrayFormater.Serialize(ref writer, objectArray, formatterResolver); + break; + default: + Debug.LogError("找不到类型:" + value.GetType()); + break; + } + } + + public object Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Formatters/PrimitiveFormatter.cs b/Unity3D/3rdLib/Utf8Json/Formatters/PrimitiveFormatter.cs new file mode 100644 index 0000000..5e417c7 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Formatters/PrimitiveFormatter.cs @@ -0,0 +1,1383 @@ +using System; +using Utf8Json.Internal; + +namespace Utf8Json.Formatters +{ + public sealed class SByteFormatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly SByteFormatter Default = new SByteFormatter(); + + public void Serialize(ref JsonWriter writer, SByte value, IJsonFormatterResolver formatterResolver) + { + writer.WriteSByte(value); + } + + public SByte Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + return reader.ReadSByte(); + } + + public void SerializeToPropertyName(ref JsonWriter writer, SByte value, IJsonFormatterResolver formatterResolver) + { + writer.WriteQuotation(); + writer.WriteSByte(value); + writer.WriteQuotation(); + } + + public SByte DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadSByte(key.Array, key.Offset, out _); + } + } + + public sealed class NullableSByteFormatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly NullableSByteFormatter Default = new NullableSByteFormatter(); + + public void Serialize(ref JsonWriter writer, SByte? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteSByte(value.Value); + } + } + + public SByte? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + return reader.ReadSByte(); + } + } + + public void SerializeToPropertyName(ref JsonWriter writer, SByte? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteQuotation(); + writer.WriteSByte(value.Value); + writer.WriteQuotation(); + } + + public SByte? DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadSByte(key.Array, key.Offset, out _); + } + } + + public sealed class SByteArrayFormatter : IJsonFormatter + { + public static readonly SByteArrayFormatter Default = new SByteArrayFormatter(); + + public void Serialize(ref JsonWriter writer, SByte[] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteBeginArray(); + + if (value.Length != 0) + { + writer.WriteSByte(value[0]); + } + for (int i = 1; i < value.Length; i++) + { + writer.WriteValueSeparator(); + writer.WriteSByte(value[i]); + } + + writer.WriteEndArray(); + } + } + + public SByte[] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + reader.ReadIsBeginArrayWithVerify(); + var array = new SByte[4]; + var count = 0; + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + if (array.Length < count) + { + Array.Resize(ref array, count * 2); + } + array[count - 1] = reader.ReadSByte(); + } + + Array.Resize(ref array, count); + return array; + } + } + } + + public sealed class Int16Formatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly Int16Formatter Default = new Int16Formatter(); + + public void Serialize(ref JsonWriter writer, Int16 value, IJsonFormatterResolver formatterResolver) + { + writer.WriteInt16(value); + } + + public Int16 Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + return reader.ReadInt16(); + } + + public void SerializeToPropertyName(ref JsonWriter writer, Int16 value, IJsonFormatterResolver formatterResolver) + { + writer.WriteQuotation(); + writer.WriteInt16(value); + writer.WriteQuotation(); + } + + public Int16 DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadInt16(key.Array, key.Offset, out _); + } + } + + public sealed class NullableInt16Formatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly NullableInt16Formatter Default = new NullableInt16Formatter(); + + public void Serialize(ref JsonWriter writer, Int16? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteInt16(value.Value); + } + } + + public Int16? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + return reader.ReadInt16(); + } + } + + public void SerializeToPropertyName(ref JsonWriter writer, Int16? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteQuotation(); + writer.WriteInt16(value.Value); + writer.WriteQuotation(); + } + + public Int16? DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadInt16(key.Array, key.Offset, out _); + } + } + + public sealed class Int16ArrayFormatter : IJsonFormatter + { + public static readonly Int16ArrayFormatter Default = new Int16ArrayFormatter(); + + public void Serialize(ref JsonWriter writer, Int16[] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteBeginArray(); + + if (value.Length != 0) + { + writer.WriteInt16(value[0]); + } + for (int i = 1; i < value.Length; i++) + { + writer.WriteValueSeparator(); + writer.WriteInt16(value[i]); + } + + writer.WriteEndArray(); + } + } + + public Int16[] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + reader.ReadIsBeginArrayWithVerify(); + var array = new Int16[4]; + var count = 0; + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + if (array.Length < count) + { + Array.Resize(ref array, count * 2); + } + array[count - 1] = reader.ReadInt16(); + } + + Array.Resize(ref array, count); + return array; + } + } + } + + public sealed class Int32Formatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly Int32Formatter Default = new Int32Formatter(); + + public void Serialize(ref JsonWriter writer, Int32 value, IJsonFormatterResolver formatterResolver) + { + writer.WriteInt32(value); + } + + public Int32 Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + return reader.ReadInt32(); + } + + public void SerializeToPropertyName(ref JsonWriter writer, Int32 value, IJsonFormatterResolver formatterResolver) + { + writer.WriteQuotation(); + writer.WriteInt32(value); + writer.WriteQuotation(); + } + + public Int32 DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadInt32(key.Array, key.Offset, out _); + } + } + + public sealed class NullableInt32Formatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly NullableInt32Formatter Default = new NullableInt32Formatter(); + + public void Serialize(ref JsonWriter writer, Int32? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteInt32(value.Value); + } + } + + public Int32? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + return reader.ReadInt32(); + } + } + + public void SerializeToPropertyName(ref JsonWriter writer, Int32? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteQuotation(); + writer.WriteInt32(value.Value); + writer.WriteQuotation(); + } + + public Int32? DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadInt32(key.Array, key.Offset, out _); + } + } + + public sealed class Int32ArrayFormatter : IJsonFormatter + { + public static readonly Int32ArrayFormatter Default = new Int32ArrayFormatter(); + + public void Serialize(ref JsonWriter writer, Int32[] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteBeginArray(); + + if (value.Length != 0) + { + writer.WriteInt32(value[0]); + } + for (int i = 1; i < value.Length; i++) + { + writer.WriteValueSeparator(); + writer.WriteInt32(value[i]); + } + + writer.WriteEndArray(); + } + } + + public Int32[] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + reader.ReadIsBeginArrayWithVerify(); + var array = new Int32[4]; + var count = 0; + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + if (array.Length < count) + { + Array.Resize(ref array, count * 2); + } + array[count - 1] = reader.ReadInt32(); + } + + Array.Resize(ref array, count); + return array; + } + } + } + + public sealed class Int64Formatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly Int64Formatter Default = new Int64Formatter(); + + public void Serialize(ref JsonWriter writer, Int64 value, IJsonFormatterResolver formatterResolver) + { + writer.WriteInt64(value); + } + + public Int64 Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + return reader.ReadInt64(); + } + + public void SerializeToPropertyName(ref JsonWriter writer, Int64 value, IJsonFormatterResolver formatterResolver) + { + writer.WriteQuotation(); + writer.WriteInt64(value); + writer.WriteQuotation(); + } + + public Int64 DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadInt64(key.Array, key.Offset, out _); + } + } + + public sealed class NullableInt64Formatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly NullableInt64Formatter Default = new NullableInt64Formatter(); + + public void Serialize(ref JsonWriter writer, Int64? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteInt64(value.Value); + } + } + + public Int64? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + return reader.ReadInt64(); + } + } + + public void SerializeToPropertyName(ref JsonWriter writer, Int64? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteQuotation(); + writer.WriteInt64(value.Value); + writer.WriteQuotation(); + } + + public Int64? DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadInt64(key.Array, key.Offset, out _); + } + } + + public sealed class Int64ArrayFormatter : IJsonFormatter + { + public static readonly Int64ArrayFormatter Default = new Int64ArrayFormatter(); + + public void Serialize(ref JsonWriter writer, Int64[] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteBeginArray(); + + if (value.Length != 0) + { + writer.WriteInt64(value[0]); + } + for (int i = 1; i < value.Length; i++) + { + writer.WriteValueSeparator(); + writer.WriteInt64(value[i]); + } + + writer.WriteEndArray(); + } + } + + public Int64[] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + reader.ReadIsBeginArrayWithVerify(); + var array = new Int64[4]; + var count = 0; + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + if (array.Length < count) + { + Array.Resize(ref array, count * 2); + } + array[count - 1] = reader.ReadInt64(); + } + + Array.Resize(ref array, count); + return array; + } + } + } + + public sealed class ByteFormatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly ByteFormatter Default = new ByteFormatter(); + + public void Serialize(ref JsonWriter writer, Byte value, IJsonFormatterResolver formatterResolver) + { + writer.WriteByte(value); + } + + public Byte Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + return reader.ReadByte(); + } + + public void SerializeToPropertyName(ref JsonWriter writer, Byte value, IJsonFormatterResolver formatterResolver) + { + writer.WriteQuotation(); + writer.WriteByte(value); + writer.WriteQuotation(); + } + + public Byte DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadByte(key.Array, key.Offset, out _); + } + } + + public sealed class NullableByteFormatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly NullableByteFormatter Default = new NullableByteFormatter(); + + public void Serialize(ref JsonWriter writer, Byte? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteByte(value.Value); + } + } + + public Byte? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + return reader.ReadByte(); + } + } + + public void SerializeToPropertyName(ref JsonWriter writer, Byte? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteQuotation(); + writer.WriteByte(value.Value); + writer.WriteQuotation(); + } + + public Byte? DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadByte(key.Array, key.Offset, out _); + } + } + + + public sealed class UInt16Formatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly UInt16Formatter Default = new UInt16Formatter(); + + public void Serialize(ref JsonWriter writer, UInt16 value, IJsonFormatterResolver formatterResolver) + { + writer.WriteUInt16(value); + } + + public UInt16 Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + return reader.ReadUInt16(); + } + + public void SerializeToPropertyName(ref JsonWriter writer, UInt16 value, IJsonFormatterResolver formatterResolver) + { + writer.WriteQuotation(); + writer.WriteUInt16(value); + writer.WriteQuotation(); + } + + public UInt16 DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadUInt16(key.Array, key.Offset, out _); + } + } + + public sealed class NullableUInt16Formatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly NullableUInt16Formatter Default = new NullableUInt16Formatter(); + + public void Serialize(ref JsonWriter writer, UInt16? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteUInt16(value.Value); + } + } + + public UInt16? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + return reader.ReadUInt16(); + } + } + + public void SerializeToPropertyName(ref JsonWriter writer, UInt16? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteQuotation(); + writer.WriteUInt16(value.Value); + writer.WriteQuotation(); + } + + public UInt16? DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadUInt16(key.Array, key.Offset, out _); + } + } + + public sealed class UInt16ArrayFormatter : IJsonFormatter + { + public static readonly UInt16ArrayFormatter Default = new UInt16ArrayFormatter(); + + public void Serialize(ref JsonWriter writer, UInt16[] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteBeginArray(); + + if (value.Length != 0) + { + writer.WriteUInt16(value[0]); + } + for (int i = 1; i < value.Length; i++) + { + writer.WriteValueSeparator(); + writer.WriteUInt16(value[i]); + } + + writer.WriteEndArray(); + } + } + + public UInt16[] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + reader.ReadIsBeginArrayWithVerify(); + var array = new UInt16[4]; + var count = 0; + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + if (array.Length < count) + { + Array.Resize(ref array, count * 2); + } + array[count - 1] = reader.ReadUInt16(); + } + + Array.Resize(ref array, count); + return array; + } + } + } + + public sealed class UInt32Formatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly UInt32Formatter Default = new UInt32Formatter(); + + public void Serialize(ref JsonWriter writer, UInt32 value, IJsonFormatterResolver formatterResolver) + { + writer.WriteUInt32(value); + } + + public UInt32 Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + return reader.ReadUInt32(); + } + + public void SerializeToPropertyName(ref JsonWriter writer, UInt32 value, IJsonFormatterResolver formatterResolver) + { + writer.WriteQuotation(); + writer.WriteUInt32(value); + writer.WriteQuotation(); + } + + public UInt32 DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadUInt32(key.Array, key.Offset, out _); + } + } + + public sealed class NullableUInt32Formatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly NullableUInt32Formatter Default = new NullableUInt32Formatter(); + + public void Serialize(ref JsonWriter writer, UInt32? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteUInt32(value.Value); + } + } + + public UInt32? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + return reader.ReadUInt32(); + } + } + + public void SerializeToPropertyName(ref JsonWriter writer, UInt32? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteQuotation(); + writer.WriteUInt32(value.Value); + writer.WriteQuotation(); + } + + public UInt32? DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadUInt32(key.Array, key.Offset, out _); + } + } + + public sealed class UInt32ArrayFormatter : IJsonFormatter + { + public static readonly UInt32ArrayFormatter Default = new UInt32ArrayFormatter(); + + public void Serialize(ref JsonWriter writer, UInt32[] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteBeginArray(); + + if (value.Length != 0) + { + writer.WriteUInt32(value[0]); + } + for (int i = 1; i < value.Length; i++) + { + writer.WriteValueSeparator(); + writer.WriteUInt32(value[i]); + } + + writer.WriteEndArray(); + } + } + + public UInt32[] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + reader.ReadIsBeginArrayWithVerify(); + var array = new UInt32[4]; + var count = 0; + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + if (array.Length < count) + { + Array.Resize(ref array, count * 2); + } + array[count - 1] = reader.ReadUInt32(); + } + + Array.Resize(ref array, count); + return array; + } + } + } + + public sealed class UInt64Formatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly UInt64Formatter Default = new UInt64Formatter(); + + public void Serialize(ref JsonWriter writer, UInt64 value, IJsonFormatterResolver formatterResolver) + { + writer.WriteUInt64(value); + } + + public UInt64 Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + return reader.ReadUInt64(); + } + + public void SerializeToPropertyName(ref JsonWriter writer, UInt64 value, IJsonFormatterResolver formatterResolver) + { + writer.WriteQuotation(); + writer.WriteUInt64(value); + writer.WriteQuotation(); + } + + public UInt64 DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadUInt64(key.Array, key.Offset, out _); + } + } + + public sealed class NullableUInt64Formatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly NullableUInt64Formatter Default = new NullableUInt64Formatter(); + + public void Serialize(ref JsonWriter writer, UInt64? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteUInt64(value.Value); + } + } + + public UInt64? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + return reader.ReadUInt64(); + } + } + + public void SerializeToPropertyName(ref JsonWriter writer, UInt64? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteQuotation(); + writer.WriteUInt64(value.Value); + writer.WriteQuotation(); + } + + public UInt64? DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadUInt64(key.Array, key.Offset, out _); + } + } + + public sealed class UInt64ArrayFormatter : IJsonFormatter + { + public static readonly UInt64ArrayFormatter Default = new UInt64ArrayFormatter(); + + public void Serialize(ref JsonWriter writer, UInt64[] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteBeginArray(); + + if (value.Length != 0) + { + writer.WriteUInt64(value[0]); + } + for (int i = 1; i < value.Length; i++) + { + writer.WriteValueSeparator(); + writer.WriteUInt64(value[i]); + } + + writer.WriteEndArray(); + } + } + + public UInt64[] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + reader.ReadIsBeginArrayWithVerify(); + var array = new UInt64[4]; + var count = 0; + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + if (array.Length < count) + { + Array.Resize(ref array, count * 2); + } + array[count - 1] = reader.ReadUInt64(); + } + + Array.Resize(ref array, count); + return array; + } + } + } + + public sealed class SingleFormatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly SingleFormatter Default = new SingleFormatter(); + + public void Serialize(ref JsonWriter writer, Single value, IJsonFormatterResolver formatterResolver) + { + writer.WriteSingle(value); + } + + public Single Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + return reader.ReadSingle(); + } + + public void SerializeToPropertyName(ref JsonWriter writer, Single value, IJsonFormatterResolver formatterResolver) + { + writer.WriteQuotation(); + writer.WriteSingle(value); + writer.WriteQuotation(); + } + + public Single DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadSingle(key.Array, key.Offset, out _); + } + } + + public sealed class NullableSingleFormatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly NullableSingleFormatter Default = new NullableSingleFormatter(); + + public void Serialize(ref JsonWriter writer, Single? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteSingle(value.Value); + } + } + + public Single? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + return reader.ReadSingle(); + } + } + + public void SerializeToPropertyName(ref JsonWriter writer, Single? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteQuotation(); + writer.WriteSingle(value.Value); + writer.WriteQuotation(); + } + + public Single? DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadSingle(key.Array, key.Offset, out _); + } + } + + public sealed class SingleArrayFormatter : IJsonFormatter + { + public static readonly SingleArrayFormatter Default = new SingleArrayFormatter(); + + public void Serialize(ref JsonWriter writer, Single[] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteBeginArray(); + + if (value.Length != 0) + { + writer.WriteSingle(value[0]); + } + for (int i = 1; i < value.Length; i++) + { + writer.WriteValueSeparator(); + writer.WriteSingle(value[i]); + } + + writer.WriteEndArray(); + } + } + + public Single[] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + reader.ReadIsBeginArrayWithVerify(); + var array = new Single[4]; + var count = 0; + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + if (array.Length < count) + { + Array.Resize(ref array, count * 2); + } + array[count - 1] = reader.ReadSingle(); + } + + Array.Resize(ref array, count); + return array; + } + } + } + + public sealed class DoubleFormatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly DoubleFormatter Default = new DoubleFormatter(); + + public void Serialize(ref JsonWriter writer, Double value, IJsonFormatterResolver formatterResolver) + { + writer.WriteDouble(value); + } + + public Double Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + return reader.ReadDouble(); + } + + public void SerializeToPropertyName(ref JsonWriter writer, Double value, IJsonFormatterResolver formatterResolver) + { + writer.WriteQuotation(); + writer.WriteDouble(value); + writer.WriteQuotation(); + } + + public Double DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadDouble(key.Array, key.Offset, out _); + } + } + + public sealed class NullableDoubleFormatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly NullableDoubleFormatter Default = new NullableDoubleFormatter(); + + public void Serialize(ref JsonWriter writer, Double? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteDouble(value.Value); + } + } + + public Double? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + return reader.ReadDouble(); + } + } + + public void SerializeToPropertyName(ref JsonWriter writer, Double? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteQuotation(); + writer.WriteDouble(value.Value); + writer.WriteQuotation(); + } + + public Double? DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadDouble(key.Array, key.Offset, out _); + } + } + + public sealed class DoubleArrayFormatter : IJsonFormatter + { + public static readonly DoubleArrayFormatter Default = new DoubleArrayFormatter(); + + public void Serialize(ref JsonWriter writer, Double[] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteBeginArray(); + + if (value.Length != 0) + { + writer.WriteDouble(value[0]); + } + for (int i = 1; i < value.Length; i++) + { + writer.WriteValueSeparator(); + writer.WriteDouble(value[i]); + } + + writer.WriteEndArray(); + } + } + + public Double[] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + reader.ReadIsBeginArrayWithVerify(); + var array = new Double[4]; + var count = 0; + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + if (array.Length < count) + { + Array.Resize(ref array, count * 2); + } + array[count - 1] = reader.ReadDouble(); + } + + Array.Resize(ref array, count); + return array; + } + } + } + + public sealed class BooleanFormatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly BooleanFormatter Default = new BooleanFormatter(); + + public void Serialize(ref JsonWriter writer, Boolean value, IJsonFormatterResolver formatterResolver) + { + writer.WriteBoolean(value); + } + + public Boolean Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + return reader.ReadBoolean(); + } + + public void SerializeToPropertyName(ref JsonWriter writer, Boolean value, IJsonFormatterResolver formatterResolver) + { + writer.WriteQuotation(); + writer.WriteBoolean(value); + writer.WriteQuotation(); + } + + public Boolean DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadBoolean(key.Array, key.Offset, out _); + } + } + + public sealed class NullableBooleanFormatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly NullableBooleanFormatter Default = new NullableBooleanFormatter(); + + public void Serialize(ref JsonWriter writer, Boolean? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteBoolean(value.Value); + } + } + + public Boolean? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + return reader.ReadBoolean(); + } + } + + public void SerializeToPropertyName(ref JsonWriter writer, Boolean? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteQuotation(); + writer.WriteBoolean(value.Value); + writer.WriteQuotation(); + } + + public Boolean? DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var key = reader.ReadStringSegmentRaw(); + int _; + return NumberConverter.ReadBoolean(key.Array, key.Offset, out _); + } + } + + public sealed class BooleanArrayFormatter : IJsonFormatter + { + public static readonly BooleanArrayFormatter Default = new BooleanArrayFormatter(); + + public void Serialize(ref JsonWriter writer, Boolean[] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteBeginArray(); + + if (value.Length != 0) + { + writer.WriteBoolean(value[0]); + } + for (int i = 1; i < value.Length; i++) + { + writer.WriteValueSeparator(); + writer.WriteBoolean(value[i]); + } + + writer.WriteEndArray(); + } + } + + public Boolean[] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + reader.ReadIsBeginArrayWithVerify(); + var array = new Boolean[4]; + var count = 0; + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + if (array.Length < count) + { + Array.Resize(ref array, count * 2); + } + array[count - 1] = reader.ReadBoolean(); + } + + Array.Resize(ref array, count); + return array; + } + } + } + +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Formatters/PrimitiveObjectFormatter.cs b/Unity3D/3rdLib/Utf8Json/Formatters/PrimitiveObjectFormatter.cs new file mode 100644 index 0000000..50f2bcf --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Formatters/PrimitiveObjectFormatter.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Utf8Json.Internal; + +namespace Utf8Json.Formatters +{ + public sealed class PrimitiveObjectFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new PrimitiveObjectFormatter(); + + static readonly Dictionary typeToJumpCode = new Dictionary() + { + { typeof(Boolean), 0 }, + { typeof(Char), 1 }, + { typeof(SByte), 2 }, + { typeof(Byte), 3 }, + { typeof(Int16), 4 }, + { typeof(UInt16), 5 }, + { typeof(Int32), 6 }, + { typeof(UInt32), 7 }, + { typeof(Int64), 8 }, + { typeof(UInt64),9 }, + { typeof(Single), 10 }, + { typeof(Double), 11 }, + { typeof(DateTime), 12 }, + { typeof(string), 13 }, + { typeof(byte[]), 14 } + }; + + public void Serialize(ref JsonWriter writer, object value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + return; + } + + var t = value.GetType(); + + int key; + if (typeToJumpCode.TryGetValue(t, out key)) + { + switch (key) + { + case 0: writer.WriteBoolean((bool)value); return; + case 1: CharFormatter.Default.Serialize(ref writer, (char)value, formatterResolver); return; + case 2: writer.WriteSByte((sbyte)value); return; + case 3: writer.WriteByte((byte)value); return; + case 4: writer.WriteInt16((Int16)value); return; + case 5: writer.WriteUInt16((UInt16)value); return; + case 6: writer.WriteInt32((int)value); return; + case 7: writer.WriteUInt32((UInt32)value); return; + case 8: writer.WriteInt64((long)value); return; + case 9: writer.WriteUInt64((UInt64)value); return; + case 10: writer.WriteSingle((Single)value); return; + case 11: writer.WriteDouble((double)value); return; + case 12: ISO8601DateTimeFormatter.Default.Serialize(ref writer, (DateTime)value, formatterResolver); return; + case 13: writer.WriteString((string)value); return; + case 14: ByteArrayFormatter.Default.Serialize(ref writer, (byte[])value, formatterResolver); return; + default: + break; + } + } + + if (t.IsEnum) + { + writer.WriteString(t.ToString()); // enum as stringq + return; + } + + var dict = value as IDictionary; // check dictionary first + if (dict != null) + { + var count = 0; + writer.WriteBeginObject(); + foreach (DictionaryEntry item in dict) + { + if (count != 0) + { + writer.WriteValueSeparator(); + } + writer.WritePropertyName((string)item.Key); + Serialize(ref writer, item.Value, formatterResolver); + count++; + } + writer.WriteEndObject(); + return; + } + + var collection = value as ICollection; + if (collection != null) + { + var count = 0; + writer.WriteBeginArray(); + foreach (var item in collection) + { + if (count != 0) + { + writer.WriteValueSeparator(); + } + + Serialize(ref writer, item, formatterResolver); + count++; + } + writer.WriteEndArray(); + return; + } + + throw new InvalidOperationException("Not supported primitive object resolver. type:" + t.Name); + } + + public object Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var token = reader.GetCurrentJsonToken(); + switch (token) + { + case JsonToken.BeginObject: + { + var dict = new Dictionary(); + reader.ReadIsBeginObjectWithVerify(); + var count = 0; + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var key = reader.ReadPropertyName(); + var value = Deserialize(ref reader, formatterResolver); + dict.Add(key, value); + } + return dict; + } + case JsonToken.BeginArray: + { + var list = new List(4); + reader.ReadIsBeginArrayWithVerify(); + var count = 0; + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + list.Add(Deserialize(ref reader, formatterResolver)); + } + return list; + } + case JsonToken.Number: + return reader.ReadDouble(); + case JsonToken.String: + return reader.ReadString(); + case JsonToken.True: + return reader.ReadBoolean(); // require advance + case JsonToken.False: + return reader.ReadBoolean(); // require advance + case JsonToken.ValueSeparator: + case JsonToken.NameSeparator: + case JsonToken.EndArray: + case JsonToken.EndObject: + throw new InvalidOperationException("Invalid Json Token:" + token); + case JsonToken.Null: + reader.ReadIsNull(); + return null; + case JsonToken.None: + default: + return null; + } + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Formatters/StandardClassLibraryFormatters.cs b/Unity3D/3rdLib/Utf8Json/Formatters/StandardClassLibraryFormatters.cs new file mode 100644 index 0000000..16af0be --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Formatters/StandardClassLibraryFormatters.cs @@ -0,0 +1,707 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using Utf8Json.Formatters.Internal; +using Utf8Json.Internal; +using System.Text.RegularExpressions; + +#if NETSTANDARD +using System.Dynamic; +using System.Numerics; +using System.Threading.Tasks; +#endif + +namespace Utf8Json.Formatters +{ + // MEMO:should write/read base64 directly like corefxlab/System.Binary.Base64 + // https://github.com/dotnet/corefxlab/tree/master/src/System.Binary.Base64/System/Binary + public sealed class ByteArrayFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new ByteArrayFormatter(); + + public void Serialize(ref JsonWriter writer, byte[] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteString(Convert.ToBase64String(value, Base64FormattingOptions.None)); + } + + public byte[] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var str = reader.ReadString(); + return Convert.FromBase64String(str); + } + } + + public sealed class ByteArraySegmentFormatter : IJsonFormatter> + { + public static readonly IJsonFormatter> Default = new ByteArraySegmentFormatter(); + + public void Serialize(ref JsonWriter writer, ArraySegment value, IJsonFormatterResolver formatterResolver) + { + if (value.Array == null) { writer.WriteNull(); return; } + + writer.WriteString(Convert.ToBase64String(value.Array, value.Offset, value.Count, Base64FormattingOptions.None)); + } + + public ArraySegment Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return default(ArraySegment); + + var str = reader.ReadString(); + var bytes = Convert.FromBase64String(str); + return new ArraySegment(bytes, 0, bytes.Length); + } + } + + public sealed class NullableStringFormatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly IJsonFormatter Default = new NullableStringFormatter(); + + public void Serialize(ref JsonWriter writer, string value, IJsonFormatterResolver formatterResolver) + { + writer.WriteString(value); + } + + public string Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + return reader.ReadString(); + } + + public void SerializeToPropertyName(ref JsonWriter writer, string value, IJsonFormatterResolver formatterResolver) + { + writer.WriteString(value); + } + + public string DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + return reader.ReadString(); + } + } + + public sealed class NullableStringArrayFormatter : IJsonFormatter + { + public static readonly NullableStringArrayFormatter Default = new NullableStringArrayFormatter(); + + public void Serialize(ref JsonWriter writer, string[] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteBeginArray(); + + if (value.Length != 0) + { + writer.WriteString(value[0]); + } + for (int i = 1; i < value.Length; i++) + { + writer.WriteValueSeparator(); + writer.WriteString(value[i]); + } + + writer.WriteEndArray(); + } + } + + public string[] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + reader.ReadIsBeginArrayWithVerify(); + var array = new string[4]; + var count = 0; + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + if (array.Length < count) + { + Array.Resize(ref array, count * 2); + } + array[count - 1] = reader.ReadString(); + } + + Array.Resize(ref array, count); + return array; + } + } + } + + public sealed class CharFormatter : IJsonFormatter + { + public static readonly CharFormatter Default = new CharFormatter(); + + // MEMO:can be improvement write directly + public void Serialize(ref JsonWriter writer, char value, IJsonFormatterResolver formatterResolver) + { + writer.WriteString(value.ToString(CultureInfo.InvariantCulture)); + } + + public char Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + return reader.ReadString()[0]; + } + } + + public sealed class NullableCharFormatter : IJsonFormatter + { + public static readonly NullableCharFormatter Default = new NullableCharFormatter(); + + public void Serialize(ref JsonWriter writer, Char? value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + CharFormatter.Default.Serialize(ref writer, value.Value, formatterResolver); + } + } + + public Char? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + return CharFormatter.Default.Deserialize(ref reader, formatterResolver); + } + } + } + + public sealed class CharArrayFormatter : IJsonFormatter + { + public static readonly CharArrayFormatter Default = new CharArrayFormatter(); + + public void Serialize(ref JsonWriter writer, char[] value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteBeginArray(); + + if (value.Length != 0) + { + CharFormatter.Default.Serialize(ref writer, value[0], formatterResolver); + } + for (int i = 1; i < value.Length; i++) + { + writer.WriteValueSeparator(); + CharFormatter.Default.Serialize(ref writer, value[i], formatterResolver); + } + + writer.WriteEndArray(); + } + } + + public char[] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + reader.ReadIsBeginArrayWithVerify(); + var array = new char[4]; + var count = 0; + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) + { + if (array.Length < count) + { + Array.Resize(ref array, count * 2); + } + array[count - 1] = CharFormatter.Default.Deserialize(ref reader, formatterResolver); + } + + Array.Resize(ref array, count); + return array; + } + } + } + + public sealed class GuidFormatter : IJsonFormatter, IObjectPropertyNameFormatter + { + public static readonly IJsonFormatter Default = new GuidFormatter(); + + public void Serialize(ref JsonWriter writer, Guid value, IJsonFormatterResolver formatterResolver) + { + writer.EnsureCapacity(38); // unsafe, control underlying buffer manually + + writer.WriteRawUnsafe((byte)'\"'); + + var rawData = writer.GetBuffer(); + new GuidBits(ref value).Write(rawData.Array, writer.CurrentOffset); // len = 36 + writer.AdvanceOffset(36); + + writer.WriteRawUnsafe((byte)'\"'); + } + + public Guid Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var segment = reader.ReadStringSegmentUnsafe(); + return new GuidBits(ref segment).Value; + } + + public void SerializeToPropertyName(ref JsonWriter writer, Guid value, IJsonFormatterResolver formatterResolver) + { + Serialize(ref writer, value, formatterResolver); + } + + public Guid DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + return Deserialize(ref reader, formatterResolver); + } + } + + public sealed class DecimalFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new DecimalFormatter(); + + readonly bool serializeAsString; + + public DecimalFormatter() + : this(false) + { + + } + + public DecimalFormatter(bool serializeAsString) + { + this.serializeAsString = serializeAsString; + } + + public void Serialize(ref JsonWriter writer, decimal value, IJsonFormatterResolver formatterResolver) + { + if (serializeAsString) + { + writer.WriteString(value.ToString(CultureInfo.InvariantCulture)); + } + else + { + // write as number format. + writer.WriteRaw(StringEncoding.UTF8.GetBytes(value.ToString(CultureInfo.InvariantCulture))); + } + } + + public decimal Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var token = reader.GetCurrentJsonToken(); + if (token == JsonToken.Number) + { + var number = reader.ReadNumberSegment(); + return decimal.Parse(StringEncoding.UTF8.GetString(number.Array, number.Offset, number.Count), NumberStyles.Float, CultureInfo.InvariantCulture); + } + else if (token == JsonToken.String) + { + return decimal.Parse(reader.ReadString(), NumberStyles.Float, CultureInfo.InvariantCulture); + } + else + { + throw new InvalidOperationException("Invalid Json Token for DecimalFormatter:" + token); + } + } + } + + public sealed class UriFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new UriFormatter(); + + public void Serialize(ref JsonWriter writer, Uri value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteString(value.ToString()); + } + } + + public Uri Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + return new Uri(reader.ReadString(), UriKind.RelativeOrAbsolute); + } + } + } + + public sealed class VersionFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new VersionFormatter(); + + public void Serialize(ref JsonWriter writer, Version value, IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + writer.WriteString(value.ToString()); + } + } + + public Version Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) + { + return null; + } + else + { + return new Version(reader.ReadString()); + } + } + } + + public sealed class KeyValuePairFormatter : IJsonFormatter> + { + public void Serialize(ref JsonWriter writer, KeyValuePair value, IJsonFormatterResolver formatterResolver) + { + writer.WriteRaw(StandardClassLibraryFormatterHelper.keyValuePairName[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Key, formatterResolver); + writer.WriteRaw(StandardClassLibraryFormatterHelper.keyValuePairName[1]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Value, formatterResolver); + + writer.WriteEndObject(); + } + + public KeyValuePair Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) throw new InvalidOperationException("Data is Nil, KeyValuePair can not be null."); + + TKey resultKey = default(TKey); + TValue resultValue = default(TValue); + + reader.ReadIsBeginObjectWithVerify(); + + var count = 0; + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + StandardClassLibraryFormatterHelper.keyValuePairAutomata.TryGetValue(keyString, out key); +#else + StandardClassLibraryFormatterHelper.keyValuePairAutomata.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + resultKey = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 1: + resultValue = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new KeyValuePair(resultKey, resultValue); + } + } + + public sealed class StringBuilderFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new StringBuilderFormatter(); + + public void Serialize(ref JsonWriter writer, StringBuilder value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + writer.WriteString(value.ToString()); + } + + public StringBuilder Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + return new StringBuilder(reader.ReadString()); + } + } + + // BitArray can be represents other format... + public sealed class BitArrayFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new BitArrayFormatter(); + + public void Serialize(ref JsonWriter writer, BitArray value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteBeginArray(); + for (int i = 0; i < value.Length; i++) + { + if (i != 0) writer.WriteValueSeparator(); + writer.WriteBoolean(value[i]); + } + writer.WriteEndArray(); + } + + public BitArray Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + reader.ReadIsBeginArrayWithVerify(); + var c = 0; + var buffer = new ArrayBuffer(4); + while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref c)) + { + buffer.Add(reader.ReadBoolean()); + } + return new BitArray(buffer.ToArray()); + } + } + + public sealed class TypeFormatter : IJsonFormatter + { + public static readonly TypeFormatter Default = new TypeFormatter(); + +#if NETSTANDARD + static readonly Regex SubtractFullNameRegex = new Regex(@", Version=\d+.\d+.\d+.\d+, Culture=\w+, PublicKeyToken=\w+", RegexOptions.Compiled); +#else + static readonly Regex SubtractFullNameRegex = new Regex(@", Version=\d+.\d+.\d+.\d+, Culture=\w+, PublicKeyToken=\w+"); +#endif + + bool serializeAssemblyQualifiedName; + bool deserializeSubtractAssemblyQualifiedName; + bool throwOnError; + + public TypeFormatter() + : this(true, true, true) + { + + } + + public TypeFormatter(bool serializeAssemblyQualifiedName, bool deserializeSubtractAssemblyQualifiedName, bool throwOnError) + { + this.serializeAssemblyQualifiedName = serializeAssemblyQualifiedName; + this.deserializeSubtractAssemblyQualifiedName = deserializeSubtractAssemblyQualifiedName; + this.throwOnError = throwOnError; + } + + public void Serialize(ref JsonWriter writer, Type value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + if (serializeAssemblyQualifiedName) + { + writer.WriteString(value.AssemblyQualifiedName); + } + else + { + writer.WriteString(value.FullName); + } + } + + public Type Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var s = reader.ReadString(); + if (deserializeSubtractAssemblyQualifiedName) + { + s = SubtractFullNameRegex.Replace(s, ""); + } + + return Type.GetType(s, throwOnError); + } + } + + +#if NETSTANDARD + + public sealed class BigIntegerFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new BigIntegerFormatter(); + + public void Serialize(ref JsonWriter writer, BigInteger value, IJsonFormatterResolver formatterResolver) + { + // JSON.NET writes Integer format, not compatible. + writer.WriteString(value.ToString(CultureInfo.InvariantCulture)); + } + + public BigInteger Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var s = reader.ReadString(); + return BigInteger.Parse(s, CultureInfo.InvariantCulture); + } + } + + // Convert to [Real, Imaginary] + public sealed class ComplexFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new ComplexFormatter(); + + public void Serialize(ref JsonWriter writer, Complex value, IJsonFormatterResolver formatterResolver) + { + writer.WriteBeginArray(); + writer.WriteDouble(value.Real); + writer.WriteValueSeparator(); + writer.WriteDouble(value.Imaginary); + writer.WriteEndArray(); + } + + public Complex Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + reader.ReadIsBeginArrayWithVerify(); + var real = reader.ReadDouble(); + reader.ReadIsValueSeparatorWithVerify(); + var imaginary = reader.ReadDouble(); + reader.ReadIsEndArrayWithVerify(); + + return new Complex(real, imaginary); + } + } + + public sealed class ExpandoObjectFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new ExpandoObjectFormatter(); + + public void Serialize(ref JsonWriter writer, ExpandoObject value, IJsonFormatterResolver formatterResolver) + { + var formatter = formatterResolver.GetFormatterWithVerify>(); + formatter.Serialize(ref writer, (IDictionary)value, formatterResolver); + } + + public ExpandoObject Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var result = new ExpandoObject() as IDictionary; + + var objectFormatter = formatterResolver.GetFormatterWithVerify(); + var c = 0; + while (reader.ReadIsInObject(ref c)) + { + var propName = reader.ReadPropertyName(); + var value = objectFormatter.Deserialize(ref reader, formatterResolver); + result.Add(propName, value); + } + + return (ExpandoObject)result; + } + } + + public sealed class LazyFormatter : IJsonFormatter> + { + public void Serialize(ref JsonWriter writer, Lazy value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Value, formatterResolver); + } + + public Lazy Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + // deserialize immediately(no delay, because capture byte[] causes memory leak) + var v = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); +#if NETSTANDARD + return new Lazy(v.AsFunc()); +#else + return new Lazy(() => v); +#endif + } + } + + public sealed class TaskUnitFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new TaskUnitFormatter(); + static readonly Task CompletedTask = Task.FromResult(null); + + public void Serialize(ref JsonWriter writer, Task value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + value.Wait(); // wait! + writer.WriteNull(); + } + + public Task Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (!reader.ReadIsNull()) throw new InvalidOperationException("Invalid input"); + + return CompletedTask; + } + } + + public sealed class TaskValueFormatter : IJsonFormatter> + { + public void Serialize(ref JsonWriter writer, Task value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + // value.Result -> wait...! + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Result, formatterResolver); + } + + public Task Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + var v = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + return Task.FromResult(v); + } + } + + public sealed class ValueTaskFormatter : IJsonFormatter> + { + public void Serialize(ref JsonWriter writer, ValueTask value, IJsonFormatterResolver formatterResolver) + { + // value.Result -> wait...! + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Result, formatterResolver); + } + + public ValueTask Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var v = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + return new ValueTask(v); + } + } + +#endif +} + +namespace Utf8Json.Formatters.Internal +{ + internal static class StandardClassLibraryFormatterHelper + { + internal static readonly byte[][] keyValuePairName; + internal static readonly AutomataDictionary keyValuePairAutomata; + + static StandardClassLibraryFormatterHelper() + { + keyValuePairName = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Key"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Value"), + }; + keyValuePairAutomata = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Key"), 0 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Value"), 1 }, + }; + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Formatters/TupleFormatter.cs b/Unity3D/3rdLib/Utf8Json/Formatters/TupleFormatter.cs new file mode 100644 index 0000000..b814e46 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Formatters/TupleFormatter.cs @@ -0,0 +1,711 @@ +#if NETSTANDARD + +using System; +using Utf8Json.Internal; +using Utf8Json.Formatters.Internal; + +namespace Utf8Json.Formatters.Internal +{ + // reduce static constructor generate size on generics(especially IL2CPP on Unity) + internal static class TupleFormatterHelper + { + internal static readonly byte[][] nameCache1; + internal static readonly AutomataDictionary dictionary1; + internal static readonly byte[][] nameCache2; + internal static readonly AutomataDictionary dictionary2; + internal static readonly byte[][] nameCache3; + internal static readonly AutomataDictionary dictionary3; + internal static readonly byte[][] nameCache4; + internal static readonly AutomataDictionary dictionary4; + internal static readonly byte[][] nameCache5; + internal static readonly AutomataDictionary dictionary5; + internal static readonly byte[][] nameCache6; + internal static readonly AutomataDictionary dictionary6; + internal static readonly byte[][] nameCache7; + internal static readonly AutomataDictionary dictionary7; + internal static readonly byte[][] nameCache8; + internal static readonly AutomataDictionary dictionary8; + + static TupleFormatterHelper() + { + nameCache1 = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Item1"), + }; + dictionary1 = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item1"), 0 }, + }; + nameCache2 = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Item1"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item2"), + }; + dictionary2 = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item1"), 0 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item2"), 1 }, + }; + nameCache3 = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Item1"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item2"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item3"), + }; + dictionary3 = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item1"), 0 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item2"), 1 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item3"), 2 }, + }; + nameCache4 = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Item1"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item2"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item3"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item4"), + }; + dictionary4 = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item1"), 0 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item2"), 1 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item3"), 2 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item4"), 3 }, + }; + nameCache5 = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Item1"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item2"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item3"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item4"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item5"), + }; + dictionary5 = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item1"), 0 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item2"), 1 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item3"), 2 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item4"), 3 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item5"), 4 }, + }; + nameCache6 = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Item1"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item2"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item3"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item4"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item5"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item6"), + }; + dictionary6 = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item1"), 0 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item2"), 1 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item3"), 2 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item4"), 3 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item5"), 4 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item6"), 5 }, + }; + nameCache7 = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Item1"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item2"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item3"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item4"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item5"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item6"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item7"), + }; + dictionary7 = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item1"), 0 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item2"), 1 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item3"), 2 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item4"), 3 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item5"), 4 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item6"), 5 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item7"), 6 }, + }; + nameCache8 = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Item1"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item2"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item3"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item4"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item5"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item6"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item7"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Rest"), + }; + dictionary8 = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item1"), 0 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item2"), 1 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item3"), 2 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item4"), 3 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item5"), 4 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item6"), 5 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item7"), 6 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Rest"), 7 }, + }; + } + } +} + +namespace Utf8Json.Formatters +{ + + public sealed class TupleFormatter : IJsonFormatter> + { + static readonly byte[][] cache = TupleFormatterHelper.nameCache1; + static readonly AutomataDictionary dictionary = TupleFormatterHelper.dictionary1; + + public void Serialize(ref JsonWriter writer, Tuple value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteRaw(cache[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, formatterResolver); + writer.WriteEndObject(); + } + + public Tuple Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + T1 item1 = default(T1); + + var count = 0; + reader.ReadIsBeginObjectWithVerify(); + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + dictionary.TryGetValue(keyString, out key); +#else + dictionary.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + item1 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new Tuple(item1); + } + } + + + public sealed class TupleFormatter : IJsonFormatter> + { + static readonly byte[][] cache = TupleFormatterHelper.nameCache2; + static readonly AutomataDictionary dictionary = TupleFormatterHelper.dictionary2; + + public void Serialize(ref JsonWriter writer, Tuple value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteRaw(cache[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, formatterResolver); + writer.WriteRaw(cache[1]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, formatterResolver); + writer.WriteEndObject(); + } + + public Tuple Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + T1 item1 = default(T1); + T2 item2 = default(T2); + + var count = 0; + reader.ReadIsBeginObjectWithVerify(); + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + dictionary.TryGetValue(keyString, out key); +#else + dictionary.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + item1 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 1: + item2 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new Tuple(item1, item2); + } + } + + + public sealed class TupleFormatter : IJsonFormatter> + { + static readonly byte[][] cache = TupleFormatterHelper.nameCache3; + static readonly AutomataDictionary dictionary = TupleFormatterHelper.dictionary3; + + public void Serialize(ref JsonWriter writer, Tuple value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteRaw(cache[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, formatterResolver); + writer.WriteRaw(cache[1]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, formatterResolver); + writer.WriteRaw(cache[2]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, formatterResolver); + writer.WriteEndObject(); + } + + public Tuple Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + T1 item1 = default(T1); + T2 item2 = default(T2); + T3 item3 = default(T3); + + var count = 0; + reader.ReadIsBeginObjectWithVerify(); + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + dictionary.TryGetValue(keyString, out key); +#else + dictionary.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + item1 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 1: + item2 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 2: + item3 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new Tuple(item1, item2, item3); + } + } + + + public sealed class TupleFormatter : IJsonFormatter> + { + static readonly byte[][] cache = TupleFormatterHelper.nameCache4; + static readonly AutomataDictionary dictionary = TupleFormatterHelper.dictionary4; + + public void Serialize(ref JsonWriter writer, Tuple value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteRaw(cache[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, formatterResolver); + writer.WriteRaw(cache[1]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, formatterResolver); + writer.WriteRaw(cache[2]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, formatterResolver); + writer.WriteRaw(cache[3]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, formatterResolver); + writer.WriteEndObject(); + } + + public Tuple Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + T1 item1 = default(T1); + T2 item2 = default(T2); + T3 item3 = default(T3); + T4 item4 = default(T4); + + var count = 0; + reader.ReadIsBeginObjectWithVerify(); + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + dictionary.TryGetValue(keyString, out key); +#else + dictionary.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + item1 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 1: + item2 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 2: + item3 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 3: + item4 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new Tuple(item1, item2, item3, item4); + } + } + + + public sealed class TupleFormatter : IJsonFormatter> + { + static readonly byte[][] cache = TupleFormatterHelper.nameCache5; + static readonly AutomataDictionary dictionary = TupleFormatterHelper.dictionary5; + + public void Serialize(ref JsonWriter writer, Tuple value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteRaw(cache[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, formatterResolver); + writer.WriteRaw(cache[1]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, formatterResolver); + writer.WriteRaw(cache[2]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, formatterResolver); + writer.WriteRaw(cache[3]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, formatterResolver); + writer.WriteRaw(cache[4]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, formatterResolver); + writer.WriteEndObject(); + } + + public Tuple Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + T1 item1 = default(T1); + T2 item2 = default(T2); + T3 item3 = default(T3); + T4 item4 = default(T4); + T5 item5 = default(T5); + + var count = 0; + reader.ReadIsBeginObjectWithVerify(); + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + dictionary.TryGetValue(keyString, out key); +#else + dictionary.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + item1 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 1: + item2 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 2: + item3 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 3: + item4 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 4: + item5 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new Tuple(item1, item2, item3, item4, item5); + } + } + + + public sealed class TupleFormatter : IJsonFormatter> + { + static readonly byte[][] cache = TupleFormatterHelper.nameCache6; + static readonly AutomataDictionary dictionary = TupleFormatterHelper.dictionary6; + + public void Serialize(ref JsonWriter writer, Tuple value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteRaw(cache[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, formatterResolver); + writer.WriteRaw(cache[1]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, formatterResolver); + writer.WriteRaw(cache[2]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, formatterResolver); + writer.WriteRaw(cache[3]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, formatterResolver); + writer.WriteRaw(cache[4]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, formatterResolver); + writer.WriteRaw(cache[5]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, formatterResolver); + writer.WriteEndObject(); + } + + public Tuple Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + T1 item1 = default(T1); + T2 item2 = default(T2); + T3 item3 = default(T3); + T4 item4 = default(T4); + T5 item5 = default(T5); + T6 item6 = default(T6); + + var count = 0; + reader.ReadIsBeginObjectWithVerify(); + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + dictionary.TryGetValue(keyString, out key); +#else + dictionary.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + item1 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 1: + item2 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 2: + item3 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 3: + item4 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 4: + item5 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 5: + item6 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new Tuple(item1, item2, item3, item4, item5, item6); + } + } + + + public sealed class TupleFormatter : IJsonFormatter> + { + static readonly byte[][] cache = TupleFormatterHelper.nameCache7; + static readonly AutomataDictionary dictionary = TupleFormatterHelper.dictionary7; + + public void Serialize(ref JsonWriter writer, Tuple value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteRaw(cache[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, formatterResolver); + writer.WriteRaw(cache[1]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, formatterResolver); + writer.WriteRaw(cache[2]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, formatterResolver); + writer.WriteRaw(cache[3]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, formatterResolver); + writer.WriteRaw(cache[4]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, formatterResolver); + writer.WriteRaw(cache[5]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, formatterResolver); + writer.WriteRaw(cache[6]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, formatterResolver); + writer.WriteEndObject(); + } + + public Tuple Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + T1 item1 = default(T1); + T2 item2 = default(T2); + T3 item3 = default(T3); + T4 item4 = default(T4); + T5 item5 = default(T5); + T6 item6 = default(T6); + T7 item7 = default(T7); + + var count = 0; + reader.ReadIsBeginObjectWithVerify(); + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + dictionary.TryGetValue(keyString, out key); +#else + dictionary.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + item1 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 1: + item2 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 2: + item3 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 3: + item4 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 4: + item5 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 5: + item6 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 6: + item7 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new Tuple(item1, item2, item3, item4, item5, item6, item7); + } + } + + + public sealed class TupleFormatter : IJsonFormatter> + { + static readonly byte[][] cache = TupleFormatterHelper.nameCache8; + static readonly AutomataDictionary dictionary = TupleFormatterHelper.dictionary8; + + public void Serialize(ref JsonWriter writer, Tuple value, IJsonFormatterResolver formatterResolver) + { + if (value == null) { writer.WriteNull(); return; } + + writer.WriteRaw(cache[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, formatterResolver); + writer.WriteRaw(cache[1]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, formatterResolver); + writer.WriteRaw(cache[2]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, formatterResolver); + writer.WriteRaw(cache[3]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, formatterResolver); + writer.WriteRaw(cache[4]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, formatterResolver); + writer.WriteRaw(cache[5]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, formatterResolver); + writer.WriteRaw(cache[6]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, formatterResolver); + writer.WriteRaw(cache[7]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Rest, formatterResolver); + writer.WriteEndObject(); + } + + public Tuple Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) return null; + + T1 item1 = default(T1); + T2 item2 = default(T2); + T3 item3 = default(T3); + T4 item4 = default(T4); + T5 item5 = default(T5); + T6 item6 = default(T6); + T7 item7 = default(T7); + TRest item8 = default(TRest); + + var count = 0; + reader.ReadIsBeginObjectWithVerify(); + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + dictionary.TryGetValue(keyString, out key); +#else + dictionary.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + item1 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 1: + item2 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 2: + item3 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 3: + item4 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 4: + item5 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 5: + item6 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 6: + item7 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 7: + item8 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new Tuple(item1, item2, item3, item4, item5, item6, item7, item8); + } + } + +} + +#endif \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Formatters/ValueTupleFormatter.cs b/Unity3D/3rdLib/Utf8Json/Formatters/ValueTupleFormatter.cs new file mode 100644 index 0000000..471c43b --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Formatters/ValueTupleFormatter.cs @@ -0,0 +1,695 @@ +#if NETSTANDARD + +using System; +using Utf8Json.Internal; +using Utf8Json.Formatters.Internal; + +namespace Utf8Json.Formatters.Internal +{ + // reduce static constructor generate size on generics(especially IL2CPP on Unity) + internal static class ValueTupleFormatterHelper + { + internal static readonly byte[][] nameCache1; + internal static readonly AutomataDictionary dictionary1; + internal static readonly byte[][] nameCache2; + internal static readonly AutomataDictionary dictionary2; + internal static readonly byte[][] nameCache3; + internal static readonly AutomataDictionary dictionary3; + internal static readonly byte[][] nameCache4; + internal static readonly AutomataDictionary dictionary4; + internal static readonly byte[][] nameCache5; + internal static readonly AutomataDictionary dictionary5; + internal static readonly byte[][] nameCache6; + internal static readonly AutomataDictionary dictionary6; + internal static readonly byte[][] nameCache7; + internal static readonly AutomataDictionary dictionary7; + internal static readonly byte[][] nameCache8; + internal static readonly AutomataDictionary dictionary8; + + static ValueTupleFormatterHelper() + { + nameCache1 = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Item1"), + }; + dictionary1 = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item1"), 0 }, + }; + nameCache2 = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Item1"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item2"), + }; + dictionary2 = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item1"), 0 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item2"), 1 }, + }; + nameCache3 = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Item1"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item2"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item3"), + }; + dictionary3 = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item1"), 0 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item2"), 1 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item3"), 2 }, + }; + nameCache4 = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Item1"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item2"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item3"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item4"), + }; + dictionary4 = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item1"), 0 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item2"), 1 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item3"), 2 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item4"), 3 }, + }; + nameCache5 = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Item1"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item2"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item3"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item4"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item5"), + }; + dictionary5 = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item1"), 0 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item2"), 1 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item3"), 2 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item4"), 3 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item5"), 4 }, + }; + nameCache6 = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Item1"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item2"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item3"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item4"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item5"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item6"), + }; + dictionary6 = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item1"), 0 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item2"), 1 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item3"), 2 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item4"), 3 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item5"), 4 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item6"), 5 }, + }; + nameCache7 = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Item1"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item2"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item3"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item4"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item5"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item6"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item7"), + }; + dictionary7 = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item1"), 0 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item2"), 1 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item3"), 2 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item4"), 3 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item5"), 4 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item6"), 5 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item7"), 6 }, + }; + nameCache8 = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("Item1"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item2"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item3"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item4"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item5"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item6"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Item7"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Rest"), + }; + dictionary8 = new AutomataDictionary + { + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item1"), 0 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item2"), 1 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item3"), 2 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item4"), 3 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item5"), 4 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item6"), 5 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Item7"), 6 }, + {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Rest"), 7 }, + }; + } + } +} + +namespace Utf8Json.Formatters +{ + + public sealed class ValueTupleFormatter : IJsonFormatter> + { + static readonly byte[][] cache = TupleFormatterHelper.nameCache1; + static readonly AutomataDictionary dictionary = TupleFormatterHelper.dictionary1; + + public void Serialize(ref JsonWriter writer, ValueTuple value, IJsonFormatterResolver formatterResolver) + { + writer.WriteRaw(cache[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, formatterResolver); + writer.WriteEndObject(); + } + + public ValueTuple Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) throw new InvalidOperationException("Data is Nil, ValueTuple can not be null."); + + T1 item1 = default(T1); + + var count = 0; + reader.ReadIsBeginObjectWithVerify(); + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + dictionary.TryGetValue(keyString, out key); +#else + dictionary.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + item1 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new ValueTuple(item1); + } + } + + + public sealed class ValueTupleFormatter : IJsonFormatter> + { + static readonly byte[][] cache = TupleFormatterHelper.nameCache2; + static readonly AutomataDictionary dictionary = TupleFormatterHelper.dictionary2; + + public void Serialize(ref JsonWriter writer, ValueTuple value, IJsonFormatterResolver formatterResolver) + { + writer.WriteRaw(cache[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, formatterResolver); + writer.WriteRaw(cache[1]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, formatterResolver); + writer.WriteEndObject(); + } + + public ValueTuple Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) throw new InvalidOperationException("Data is Nil, ValueTuple can not be null."); + + T1 item1 = default(T1); + T2 item2 = default(T2); + + var count = 0; + reader.ReadIsBeginObjectWithVerify(); + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + dictionary.TryGetValue(keyString, out key); +#else + dictionary.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + item1 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 1: + item2 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new ValueTuple(item1, item2); + } + } + + + public sealed class ValueTupleFormatter : IJsonFormatter> + { + static readonly byte[][] cache = TupleFormatterHelper.nameCache3; + static readonly AutomataDictionary dictionary = TupleFormatterHelper.dictionary3; + + public void Serialize(ref JsonWriter writer, ValueTuple value, IJsonFormatterResolver formatterResolver) + { + writer.WriteRaw(cache[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, formatterResolver); + writer.WriteRaw(cache[1]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, formatterResolver); + writer.WriteRaw(cache[2]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, formatterResolver); + writer.WriteEndObject(); + } + + public ValueTuple Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) throw new InvalidOperationException("Data is Nil, ValueTuple can not be null."); + + T1 item1 = default(T1); + T2 item2 = default(T2); + T3 item3 = default(T3); + + var count = 0; + reader.ReadIsBeginObjectWithVerify(); + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + dictionary.TryGetValue(keyString, out key); +#else + dictionary.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + item1 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 1: + item2 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 2: + item3 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new ValueTuple(item1, item2, item3); + } + } + + + public sealed class ValueTupleFormatter : IJsonFormatter> + { + static readonly byte[][] cache = TupleFormatterHelper.nameCache4; + static readonly AutomataDictionary dictionary = TupleFormatterHelper.dictionary4; + + public void Serialize(ref JsonWriter writer, ValueTuple value, IJsonFormatterResolver formatterResolver) + { + writer.WriteRaw(cache[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, formatterResolver); + writer.WriteRaw(cache[1]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, formatterResolver); + writer.WriteRaw(cache[2]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, formatterResolver); + writer.WriteRaw(cache[3]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, formatterResolver); + writer.WriteEndObject(); + } + + public ValueTuple Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) throw new InvalidOperationException("Data is Nil, ValueTuple can not be null."); + + T1 item1 = default(T1); + T2 item2 = default(T2); + T3 item3 = default(T3); + T4 item4 = default(T4); + + var count = 0; + reader.ReadIsBeginObjectWithVerify(); + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + dictionary.TryGetValue(keyString, out key); +#else + dictionary.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + item1 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 1: + item2 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 2: + item3 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 3: + item4 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new ValueTuple(item1, item2, item3, item4); + } + } + + + public sealed class ValueTupleFormatter : IJsonFormatter> + { + static readonly byte[][] cache = TupleFormatterHelper.nameCache5; + static readonly AutomataDictionary dictionary = TupleFormatterHelper.dictionary5; + + public void Serialize(ref JsonWriter writer, ValueTuple value, IJsonFormatterResolver formatterResolver) + { + writer.WriteRaw(cache[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, formatterResolver); + writer.WriteRaw(cache[1]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, formatterResolver); + writer.WriteRaw(cache[2]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, formatterResolver); + writer.WriteRaw(cache[3]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, formatterResolver); + writer.WriteRaw(cache[4]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, formatterResolver); + writer.WriteEndObject(); + } + + public ValueTuple Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) throw new InvalidOperationException("Data is Nil, ValueTuple can not be null."); + + T1 item1 = default(T1); + T2 item2 = default(T2); + T3 item3 = default(T3); + T4 item4 = default(T4); + T5 item5 = default(T5); + + var count = 0; + reader.ReadIsBeginObjectWithVerify(); + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + dictionary.TryGetValue(keyString, out key); +#else + dictionary.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + item1 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 1: + item2 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 2: + item3 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 3: + item4 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 4: + item5 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new ValueTuple(item1, item2, item3, item4, item5); + } + } + + + public sealed class ValueTupleFormatter : IJsonFormatter> + { + static readonly byte[][] cache = TupleFormatterHelper.nameCache6; + static readonly AutomataDictionary dictionary = TupleFormatterHelper.dictionary6; + + public void Serialize(ref JsonWriter writer, ValueTuple value, IJsonFormatterResolver formatterResolver) + { + writer.WriteRaw(cache[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, formatterResolver); + writer.WriteRaw(cache[1]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, formatterResolver); + writer.WriteRaw(cache[2]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, formatterResolver); + writer.WriteRaw(cache[3]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, formatterResolver); + writer.WriteRaw(cache[4]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, formatterResolver); + writer.WriteRaw(cache[5]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, formatterResolver); + writer.WriteEndObject(); + } + + public ValueTuple Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) throw new InvalidOperationException("Data is Nil, ValueTuple can not be null."); + + T1 item1 = default(T1); + T2 item2 = default(T2); + T3 item3 = default(T3); + T4 item4 = default(T4); + T5 item5 = default(T5); + T6 item6 = default(T6); + + var count = 0; + reader.ReadIsBeginObjectWithVerify(); + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + dictionary.TryGetValue(keyString, out key); +#else + dictionary.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + item1 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 1: + item2 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 2: + item3 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 3: + item4 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 4: + item5 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 5: + item6 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new ValueTuple(item1, item2, item3, item4, item5, item6); + } + } + + + public sealed class ValueTupleFormatter : IJsonFormatter> + { + static readonly byte[][] cache = TupleFormatterHelper.nameCache7; + static readonly AutomataDictionary dictionary = TupleFormatterHelper.dictionary7; + + public void Serialize(ref JsonWriter writer, ValueTuple value, IJsonFormatterResolver formatterResolver) + { + writer.WriteRaw(cache[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, formatterResolver); + writer.WriteRaw(cache[1]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, formatterResolver); + writer.WriteRaw(cache[2]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, formatterResolver); + writer.WriteRaw(cache[3]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, formatterResolver); + writer.WriteRaw(cache[4]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, formatterResolver); + writer.WriteRaw(cache[5]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, formatterResolver); + writer.WriteRaw(cache[6]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, formatterResolver); + writer.WriteEndObject(); + } + + public ValueTuple Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) throw new InvalidOperationException("Data is Nil, ValueTuple can not be null."); + + T1 item1 = default(T1); + T2 item2 = default(T2); + T3 item3 = default(T3); + T4 item4 = default(T4); + T5 item5 = default(T5); + T6 item6 = default(T6); + T7 item7 = default(T7); + + var count = 0; + reader.ReadIsBeginObjectWithVerify(); + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + dictionary.TryGetValue(keyString, out key); +#else + dictionary.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + item1 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 1: + item2 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 2: + item3 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 3: + item4 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 4: + item5 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 5: + item6 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 6: + item7 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new ValueTuple(item1, item2, item3, item4, item5, item6, item7); + } + } + + + public sealed class ValueTupleFormatter : IJsonFormatter> where TRest : struct + { + static readonly byte[][] cache = TupleFormatterHelper.nameCache8; + static readonly AutomataDictionary dictionary = TupleFormatterHelper.dictionary8; + + public void Serialize(ref JsonWriter writer, ValueTuple value, IJsonFormatterResolver formatterResolver) + { + writer.WriteRaw(cache[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, formatterResolver); + writer.WriteRaw(cache[1]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, formatterResolver); + writer.WriteRaw(cache[2]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, formatterResolver); + writer.WriteRaw(cache[3]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, formatterResolver); + writer.WriteRaw(cache[4]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, formatterResolver); + writer.WriteRaw(cache[5]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, formatterResolver); + writer.WriteRaw(cache[6]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, formatterResolver); + writer.WriteRaw(cache[7]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Rest, formatterResolver); + writer.WriteEndObject(); + } + + public ValueTuple Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (reader.ReadIsNull()) throw new InvalidOperationException("Data is Nil, ValueTuple can not be null."); + + T1 item1 = default(T1); + T2 item2 = default(T2); + T3 item3 = default(T3); + T4 item4 = default(T4); + T5 item5 = default(T5); + T6 item6 = default(T6); + T7 item7 = default(T7); + TRest item8 = default(TRest); + + var count = 0; + reader.ReadIsBeginObjectWithVerify(); + while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) + { + var keyString = reader.ReadPropertyNameSegmentRaw(); + int key; +#if NETSTANDARD + dictionary.TryGetValue(keyString, out key); +#else + dictionary.TryGetValueSafe(keyString, out key); +#endif + + switch (key) + { + case 0: + item1 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 1: + item2 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 2: + item3 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 3: + item4 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 4: + item5 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 5: + item6 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 6: + item7 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + case 7: + item8 = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); + break; + default: + reader.ReadNextBlock(); + break; + } + } + + return new ValueTuple(item1, item2, item3, item4, item5, item6, item7, item8); + } + } + +} + +#endif \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/IJsonFormatter.cs b/Unity3D/3rdLib/Utf8Json/IJsonFormatter.cs new file mode 100644 index 0000000..96f71e0 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/IJsonFormatter.cs @@ -0,0 +1,44 @@ +using System; + +namespace Utf8Json +{ + public delegate void JsonSerializeAction(ref JsonWriter writer, T value, IJsonFormatterResolver resolver); + public delegate T JsonDeserializeFunc(ref JsonReader reader, IJsonFormatterResolver resolver); + + public interface IJsonFormatter + { + } + + public interface IJsonFormatter : IJsonFormatter + { + void Serialize(ref JsonWriter writer, T value, IJsonFormatterResolver formatterResolver); + T Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver); + } + + public interface IObjectPropertyNameFormatter + { + void SerializeToPropertyName(ref JsonWriter writer, T value, IJsonFormatterResolver formatterResolver); + T DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver); + } + + public interface IOverwriteJsonFormatter : IJsonFormatter + { + void DeserializeTo(ref T value, ref JsonReader reader, IJsonFormatterResolver formatterResolver); + } + + public enum CollectionDeserializeToBehaviour + { + Add, // default is add(protobuf-merge, json.net-populateobject + OverwriteReplace + } + + public static class JsonFormatterExtensions + { + public static string ToJsonString(this IJsonFormatter formatter, T value, IJsonFormatterResolver formatterResolver) + { + var writer = new JsonWriter(); + formatter.Serialize(ref writer, value, formatterResolver); + return writer.ToString(); + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/IJsonFormatterResolver.cs b/Unity3D/3rdLib/Utf8Json/IJsonFormatterResolver.cs new file mode 100644 index 0000000..cd00921 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/IJsonFormatterResolver.cs @@ -0,0 +1,69 @@ +using System; +using System.Reflection; + +namespace Utf8Json +{ + public interface IJsonFormatterResolver + { + IJsonFormatter GetFormatter(); + } + + public static class JsonFormatterResolverExtensions + { + public static IJsonFormatter GetFormatterWithVerify(this IJsonFormatterResolver resolver) + { + IJsonFormatter formatter; + try + { + formatter = resolver.GetFormatter(); + } + catch (TypeInitializationException ex) + { + Exception inner = ex; + while (inner.InnerException != null) + { + inner = inner.InnerException; + } + + throw inner; + } + + if (formatter == null) + { + throw new FormatterNotRegisteredException(typeof(T).FullName + " is not registered in this resolver. resolver:" + resolver.GetType().Name); + } + + return formatter; + } + + public static object GetFormatterDynamic(this IJsonFormatterResolver resolver, Type type) + { + var methodInfo = typeof(IJsonFormatterResolver).GetRuntimeMethod("GetFormatter", Type.EmptyTypes); + + var formatter = methodInfo.MakeGenericMethod(type).Invoke(resolver, null); + return formatter; + } + + public static void DeserializeToWithFallbackReplace(this IJsonFormatterResolver formatterResolver, ref T value, ref JsonReader reader) + { + var formatter = formatterResolver.GetFormatterWithVerify(); + var overwriteFormatter = formatter as IOverwriteJsonFormatter; + if (overwriteFormatter != null) + { + overwriteFormatter.DeserializeTo(ref value, ref reader, formatterResolver); + } + else + { + // deserialize new value and replace with it. + value = formatter.Deserialize(ref reader, formatterResolver); + } + } + } + + public class FormatterNotRegisteredException : Exception + { + public FormatterNotRegisteredException(string message) : base(message) + { + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/ArrayBuffer.cs b/Unity3D/3rdLib/Utf8Json/Internal/ArrayBuffer.cs new file mode 100644 index 0000000..05134c8 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/ArrayBuffer.cs @@ -0,0 +1,38 @@ +using System; + +namespace Utf8Json.Internal +{ + public struct ArrayBuffer + { + public T[] Buffer; + public int Size; + + public ArrayBuffer(int initialSize) + { + this.Buffer = new T[initialSize]; + this.Size = 0; + } + + public void Add(T value) + { + if (Size >= this.Buffer.Length) + { + Array.Resize(ref Buffer, Size * 2); + } + + Buffer[Size++] = value; + } + + public T[] ToArray() + { + if (Buffer.Length == Size) + { + return Buffer; + } + + var result = new T[Size]; + Array.Copy(Buffer, result, Size); + return result; + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/ArrayPool.cs b/Unity3D/3rdLib/Utf8Json/Internal/ArrayPool.cs new file mode 100644 index 0000000..29989d4 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/ArrayPool.cs @@ -0,0 +1,67 @@ +using System; + +namespace Utf8Json.Internal +{ + internal sealed class BufferPool : ArrayPool + { + public static readonly BufferPool Default = new BufferPool(65535); + + public BufferPool(int bufferLength) + : base(bufferLength) + { + } + } + + internal class ArrayPool + { + readonly int bufferLength; + readonly object gate; + int index; + T[][] buffers; + + public ArrayPool(int bufferLength) + { + this.bufferLength = bufferLength; + this.buffers = new T[4][]; + this.gate = new object(); + } + + public T[] Rent() + { + lock (gate) + { + if (index >= buffers.Length) + { + Array.Resize(ref buffers, buffers.Length * 2); + } + + if (buffers[index] == null) + { + buffers[index] = new T[bufferLength]; + } + + var buffer = buffers[index]; + buffers[index] = null; + index++; + + return buffer; + } + } + + public void Return(T[] array) + { + if (array.Length != bufferLength) + { + throw new InvalidOperationException("return buffer is not from pool"); + } + + lock (gate) + { + if (index != 0) + { + buffers[--index] = array; + } + } + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Internal/AutomataDictionary.cs b/Unity3D/3rdLib/Utf8Json/Internal/AutomataDictionary.cs new file mode 100644 index 0000000..4304c1e --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/AutomataDictionary.cs @@ -0,0 +1,693 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Linq; +using System.Reflection.Emit; +using System.Reflection; +using Utf8Json.Internal.Emit; + +namespace Utf8Json.Internal +{ + // Key = long, Value = int for UTF8String Dictionary + + public class AutomataDictionary : IEnumerable> + { + readonly AutomataNode root; + + public AutomataDictionary() + { + root = new AutomataNode(0); + } + +#if NETSTANDARD + public unsafe void Add(string str, int value) + { + Add(JsonWriter.GetEncodedPropertyNameWithoutQuotation(str), value); + } + + public unsafe void Add(byte[] bytes, int value) + { + fixed (byte* buffer = &bytes[0]) + { + var node = root; + + var p = buffer; + var rest = bytes.Length; + while (rest != 0) + { + var key = AutomataKeyGen.GetKey(ref p, ref rest); + + if (rest == 0) + { + node = node.Add(key, value, Encoding.UTF8.GetString(bytes)); + } + else + { + node = node.Add(key); + } + } + } + } + + public unsafe bool TryGetValue(ArraySegment bytes, out int value) + { + return TryGetValue(bytes.Array, bytes.Offset, bytes.Count, out value); + } + + public unsafe bool TryGetValue(byte[] bytes, int offset, int count, out int value) + { + fixed (byte* p = &bytes[offset]) + { + var p1 = p; + var node = root; + var rest = count; + + while (rest != 0 && node != null) + { + node = node.SearchNext(ref p1, ref rest); + } + + if (node == null) + { + value = -1; + return false; + } + else + { + value = node.Value; + return true; + } + } + } +#else + // for Unity, use safe only. + + public void Add(string str, int value) + { + Add(JsonWriter.GetEncodedPropertyNameWithoutQuotation(str), value); + } + + public unsafe void Add(byte[] bytes, int value) + { + var offset = 0; + + var node = root; + + var rest = bytes.Length; + while (rest != 0) + { + var key = AutomataKeyGen.GetKeySafe(bytes, ref offset, ref rest); + + if (rest == 0) + { + node = node.Add(key, value, Encoding.UTF8.GetString(bytes)); + } + else + { + node = node.Add(key); + } + } + } + +#endif + + + public bool TryGetValueSafe(ArraySegment key, out int value) + { + var node = root; + var bytes = key.Array; + var offset = key.Offset; + var rest = key.Count; + + while (rest != 0 && node != null) + { + node = node.SearchNextSafe(bytes, ref offset, ref rest); + } + + if (node == null) + { + value = -1; + return false; + } + else + { + value = node.Value; + return true; + } + } + + // for debugging + public override string ToString() + { + var sb = new StringBuilder(); + ToStringCore(root.YieldChildren(), sb, 0); + return sb.ToString(); + } + + static void ToStringCore(IEnumerable nexts, StringBuilder sb, int depth) + { + foreach (var item in nexts) + { + if (depth != 0) + { + sb.Append(' ', depth * 2); + } + sb.Append("[" + item.Key + "]"); + if (item.Value != -1) + { + sb.Append("(" + item.originalKey + ")"); + sb.Append(" = "); + sb.Append(item.Value); + } + sb.AppendLine(); + ToStringCore(item.YieldChildren(), sb, depth + 1); + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public IEnumerator> GetEnumerator() + { + return YieldCore(this.root.YieldChildren()).GetEnumerator(); + } + + static IEnumerable> YieldCore(IEnumerable nexts) + { + foreach (var item in nexts) + { + if (item.Value != -1) yield return new KeyValuePair(item.originalKey, item.Value); + foreach (var x in YieldCore(item.YieldChildren())) yield return x; + } + } + + // IL Emit + + public void EmitMatch(ILGenerator il, LocalBuilder p, LocalBuilder rest, LocalBuilder key, Action> onFound, Action onNotFound) + { + root.EmitSearchNext(il, p, rest, key, onFound, onNotFound); + } + + class AutomataNode : IComparable + { + static readonly AutomataNode[] emptyNodes = new AutomataNode[0]; + static readonly ulong[] emptyKeys = new ulong[0]; + + public ulong Key; + public int Value; + public string originalKey; + + AutomataNode[] nexts; + ulong[] nextKeys; + int count; + + public bool HasChildren { get { return count != 0; } } + + public AutomataNode(ulong key) + { + this.Key = key; + this.Value = -1; + this.nexts = emptyNodes; + this.nextKeys = emptyKeys; + this.count = 0; + this.originalKey = null; + } + + public AutomataNode Add(ulong key) + { + var index = Array.BinarySearch(nextKeys, 0, count, key); + if (index < 0) + { + if (nexts.Length == count) + { + Array.Resize(ref nexts, (count == 0) ? 4 : (count * 2)); + Array.Resize(ref nextKeys, (count == 0) ? 4 : (count * 2)); + } + count++; + + var nextNode = new AutomataNode(key); + nexts[count - 1] = nextNode; + nextKeys[count - 1] = key; + Array.Sort(nexts, 0, count); + Array.Sort(nextKeys, 0, count); + return nextNode; + } + else + { + return nexts[index]; + } + } + + public AutomataNode Add(ulong key, int value, string originalKey) + { + var v = Add(key); + v.Value = value; + v.originalKey = originalKey; + return v; + } + + public unsafe AutomataNode SearchNext(ref byte* p, ref int rest) + { + var key = AutomataKeyGen.GetKey(ref p, ref rest); + if (count < 4) + { + // linear search + for (int i = 0; i < count; i++) + { + if (nextKeys[i] == key) + { + return nexts[i]; + } + } + } + else + { + // binary search + var index = BinarySearch(nextKeys, 0, count, key); + if (index >= 0) + { + return nexts[index]; + } + } + + return null; + } + + public unsafe AutomataNode SearchNextSafe(byte[] p, ref int offset, ref int rest) + { + var key = AutomataKeyGen.GetKeySafe(p, ref offset, ref rest); + if (count < 4) + { + // linear search + for (int i = 0; i < count; i++) + { + if (nextKeys[i] == key) + { + return nexts[i]; + } + } + } + else + { + // binary search + var index = BinarySearch(nextKeys, 0, count, key); + if (index >= 0) + { + return nexts[index]; + } + } + + return null; + } + + internal static int BinarySearch(ulong[] array, int index, int length, ulong value) + { + int lo = index; + int hi = index + length - 1; + while (lo <= hi) + { + int i = lo + ((hi - lo) >> 1); + + var arrayValue = array[i]; + int order; + if (arrayValue < value) order = -1; + else if (arrayValue > value) order = 1; + else order = 0; + + if (order == 0) return i; + if (order < 0) + { + lo = i + 1; + } + else + { + hi = i - 1; + } + } + + return ~lo; + } + + public int CompareTo(AutomataNode other) + { + return this.Key.CompareTo(other.Key); + } + + public IEnumerable YieldChildren() + { + for (int i = 0; i < count; i++) + { + yield return nexts[i]; + } + } + + // SearchNext(ref byte* p, ref int rest, ref ulong key) + public void EmitSearchNext(ILGenerator il, LocalBuilder p, LocalBuilder rest, LocalBuilder key, Action> onFound, Action onNotFound) + { + // key = AutomataKeyGen.GetKey(ref p, ref rest); + il.EmitLdloca(p); + il.EmitLdloca(rest); + il.EmitCall(AutomataKeyGen.GetKeyMethod); + il.EmitStloc(key); + + // match children. + EmitSearchNextCore(il, p, rest, key, onFound, onNotFound, nexts, count); + } + + static void EmitSearchNextCore(ILGenerator il, LocalBuilder p, LocalBuilder rest, LocalBuilder key, Action> onFound, Action onNotFound, AutomataNode[] nexts, int count) + { + if (count < 4) + { + // linear-search + var valueExists = nexts.Take(count).Where(x => x.Value != -1).ToArray(); + var childrenExists = nexts.Take(count).Where(x => x.HasChildren).ToArray(); + var gotoSearchNext = il.DefineLabel(); + var gotoNotFound = il.DefineLabel(); + + { + il.EmitLdloc(rest); + if (childrenExists.Length != 0 && valueExists.Length == 0) + { + + il.Emit(OpCodes.Brfalse, gotoNotFound); // if(rest == 0) + } + else + { + il.Emit(OpCodes.Brtrue, gotoSearchNext); // if(rest != 0) + } + } + { + var ifValueNexts = Enumerable.Range(0, Math.Max(valueExists.Length - 1, 0)).Select(_ => il.DefineLabel()).ToArray(); + for (int i = 0; i < valueExists.Length; i++) + { + var notFoundLabel = il.DefineLabel(); + if (i != 0) + { + il.MarkLabel(ifValueNexts[i - 1]); + } + + il.EmitLdloc(key); + il.EmitULong(valueExists[i].Key); + il.Emit(OpCodes.Bne_Un, notFoundLabel); + // found + onFound(new KeyValuePair(valueExists[i].originalKey, valueExists[i].Value)); + + // notfound + il.MarkLabel(notFoundLabel); + if (i != valueExists.Length - 1) + { + il.Emit(OpCodes.Br, ifValueNexts[i]); + } + else + { + onNotFound(); + } + } + } + + il.MarkLabel(gotoSearchNext); + var ifRecNext = Enumerable.Range(0, Math.Max(childrenExists.Length - 1, 0)).Select(_ => il.DefineLabel()).ToArray(); + for (int i = 0; i < childrenExists.Length; i++) + { + var notFoundLabel = il.DefineLabel(); + if (i != 0) + { + il.MarkLabel(ifRecNext[i - 1]); + } + + il.EmitLdloc(key); + il.EmitULong(childrenExists[i].Key); + il.Emit(OpCodes.Bne_Un, notFoundLabel); + // found + childrenExists[i].EmitSearchNext(il, p, rest, key, onFound, onNotFound); + // notfound + il.MarkLabel(notFoundLabel); + if (i != childrenExists.Length - 1) + { + il.Emit(OpCodes.Br, ifRecNext[i]); + } + else + { + onNotFound(); + } + } + + il.MarkLabel(gotoNotFound); + onNotFound(); + } + else + { + // binary-search + var midline = count / 2; + var mid = nexts[midline].Key; + var l = nexts.Take(count).Take(midline).ToArray(); + var r = nexts.Take(count).Skip(midline).ToArray(); + + var gotoRight = il.DefineLabel(); + + // if(key < mid) + il.EmitLdloc(key); + il.EmitULong(mid); + il.Emit(OpCodes.Bge, gotoRight); + EmitSearchNextCore(il, p, rest, key, onFound, onNotFound, l, l.Length); + + // else + il.MarkLabel(gotoRight); + EmitSearchNextCore(il, p, rest, key, onFound, onNotFound, r, r.Length); + } + } + } + } + + public static class AutomataKeyGen + { + public static readonly MethodInfo GetKeyMethod = typeof(AutomataKeyGen).GetRuntimeMethod("GetKey", new[] { typeof(byte*).MakeByRefType(), typeof(int).MakeByRefType() }); + // public static readonly MethodInfo GetKeySafeMethod = typeof(AutomataKeyGen).GetRuntimeMethod("GetKeySafe", new[] { typeof(byte[]), typeof(int).MakeByRefType(), typeof(int).MakeByRefType() }); + + public static unsafe ulong GetKey(ref byte* p, ref int rest) + { + int readSize; + ulong key; + + unchecked + { + if (rest >= 8) + { + key = *(ulong*)p; + readSize = 8; + } + else + { + switch (rest) + { + case 1: + { + key = *(byte*)p; + readSize = 1; + break; + } + case 2: + { + key = *(ushort*)p; + readSize = 2; + break; + } + case 3: + { + var a = *p; + var b = *(ushort*)(p + 1); + key = ((ulong)a | (ulong)b << 8); + readSize = 3; + break; + } + case 4: + { + key = *(uint*)p; + readSize = 4; + break; + } + case 5: + { + var a = *p; + var b = *(uint*)(p + 1); + key = ((ulong)a | (ulong)b << 8); + readSize = 5; + break; + } + case 6: + { + ulong a = *(ushort*)p; + ulong b = *(uint*)(p + 2); + key = (a | (b << 16)); + readSize = 6; + break; + } + case 7: + { + var a = *(byte*)p; + var b = *(ushort*)(p + 1); + var c = *(uint*)(p + 3); + key = ((ulong)a | (ulong)b << 8 | (ulong)c << 24); + readSize = 7; + break; + } + default: + throw new InvalidOperationException("Not Supported Length"); + } + } + + p += readSize; + rest -= readSize; + return key; + } + } + + public static ulong GetKeySafe(byte[] bytes, ref int offset, ref int rest) + { + int readSize; + ulong key; + + if (BitConverter.IsLittleEndian) + { + unchecked + { + if (rest >= 8) + { + key = (ulong)bytes[offset] << 0 | (ulong)bytes[offset + 1] << 8 | (ulong)bytes[offset + 2] << 16 | (ulong)bytes[offset + 3] << 24 + | (ulong)bytes[offset + 4] << 32 | (ulong)bytes[offset + 5] << 40 | (ulong)bytes[offset + 6] << 48 | (ulong)bytes[offset + 7] << 56; + readSize = 8; + } + else + { + switch (rest) + { + case 1: + { + key = bytes[offset]; + readSize = 1; + break; + } + case 2: + { + key = (ulong)bytes[offset] << 0 | (ulong)bytes[offset + 1] << 8; + readSize = 2; + break; + } + case 3: + { + key = (ulong)bytes[offset] << 0 | (ulong)bytes[offset + 1] << 8 | (ulong)bytes[offset + 2] << 16; + readSize = 3; + break; + } + case 4: + { + key = (ulong)bytes[offset] << 0 | (ulong)bytes[offset + 1] << 8 | (ulong)bytes[offset + 2] << 16 | (ulong)bytes[offset + 3] << 24; + readSize = 4; + break; + } + case 5: + { + key = (ulong)bytes[offset] << 0 | (ulong)bytes[offset + 1] << 8 | (ulong)bytes[offset + 2] << 16 | (ulong)bytes[offset + 3] << 24 + | (ulong)bytes[offset + 4] << 32; + readSize = 5; + break; + } + case 6: + { + key = (ulong)bytes[offset] << 0 | (ulong)bytes[offset + 1] << 8 | (ulong)bytes[offset + 2] << 16 | (ulong)bytes[offset + 3] << 24 + | (ulong)bytes[offset + 4] << 32 | (ulong)bytes[offset + 5] << 40; + readSize = 6; + break; + } + case 7: + { + key = (ulong)bytes[offset] << 0 | (ulong)bytes[offset + 1] << 8 | (ulong)bytes[offset + 2] << 16 | (ulong)bytes[offset + 3] << 24 + | (ulong)bytes[offset + 4] << 32 | (ulong)bytes[offset + 5] << 40 | (ulong)bytes[offset + 6] << 48; + readSize = 7; + break; + } + default: + throw new InvalidOperationException("Not Supported Length"); + } + } + + offset += readSize; + rest -= readSize; + return key; + } + } + else + { + unchecked + { + if (rest >= 8) + { + key = (ulong)bytes[offset] << 56 | (ulong)bytes[offset + 1] << 48 | (ulong)bytes[offset + 2] << 40 | (ulong)bytes[offset + 3] << 32 + | (ulong)bytes[offset + 4] << 24 | (ulong)bytes[offset + 5] << 16 | (ulong)bytes[offset + 6] << 8 | (ulong)bytes[offset + 7]; + readSize = 8; + } + else + { + switch (rest) + { + case 1: + { + key = bytes[offset]; + readSize = 1; + break; + } + case 2: + { + key = (ulong)bytes[offset] << 8 | (ulong)bytes[offset + 1] << 0; + readSize = 2; + break; + } + case 3: + { + key = (ulong)bytes[offset] << 16 | (ulong)bytes[offset + 1] << 8 | (ulong)bytes[offset + 2] << 0; + readSize = 3; + break; + } + case 4: + { + key = (ulong)bytes[offset] << 24 | (ulong)bytes[offset + 1] << 16 | (ulong)bytes[offset + 2] << 8 | (ulong)bytes[offset + 3] << 0; + readSize = 4; + break; + } + case 5: + { + key = (ulong)bytes[offset] << 32 | (ulong)bytes[offset + 1] << 24 | (ulong)bytes[offset + 2] << 16 | (ulong)bytes[offset + 3] << 8 + | (ulong)bytes[offset + 4] << 0; + readSize = 5; + break; + } + case 6: + { + key = (ulong)bytes[offset] << 40 | (ulong)bytes[offset + 1] << 32 | (ulong)bytes[offset + 2] << 24 | (ulong)bytes[offset + 3] << 16 + | (ulong)bytes[offset + 4] << 8 | (ulong)bytes[offset + 5] << 0; + readSize = 6; + break; + } + case 7: + { + key = (ulong)bytes[offset] << 48 | (ulong)bytes[offset + 1] << 40 | (ulong)bytes[offset + 2] << 32 | (ulong)bytes[offset + 3] << 24 + | (ulong)bytes[offset + 4] << 16 | (ulong)bytes[offset + 5] << 8 | (ulong)bytes[offset + 6] << 0; + readSize = 7; + break; + } + default: + throw new InvalidOperationException("Not Supported Length"); + } + } + + offset += readSize; + rest -= readSize; + return key; + } + } + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/BinaryUtil.cs b/Unity3D/3rdLib/Utf8Json/Internal/BinaryUtil.cs new file mode 100644 index 0000000..ba9107c --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/BinaryUtil.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Text; + +#if NETSTANDARD +using System.Runtime.CompilerServices; +#endif + +namespace Utf8Json.Internal +{ + public static class BinaryUtil + { + const int ArrayMaxSize = 0x7FFFFFC7; // https://msdn.microsoft.com/en-us/library/system.array + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static void EnsureCapacity(ref byte[] bytes, int offset, int appendLength) + { + var newLength = offset + appendLength; + + // If null(most case fisrt time) fill byte. + if (bytes == null) + { + bytes = new byte[newLength]; + return; + } + + // like MemoryStream.EnsureCapacity + var current = bytes.Length; + if (newLength > current) + { + int num = newLength; + if (num < 256) + { + num = 256; + FastResize(ref bytes, num); + return; + } + + if (current == ArrayMaxSize) + { + throw new InvalidOperationException("byte[] size reached maximum size of array(0x7FFFFFC7), can not write to single byte[]. Details: https://msdn.microsoft.com/en-us/library/system.array"); + } + + var newSize = unchecked((current * 2)); + if (newSize < 0) // overflow + { + num = ArrayMaxSize; + } + else + { + if (num < newSize) + { + num = newSize; + } + } + + FastResize(ref bytes, num); + } + } + + // Buffer.BlockCopy version of Array.Resize +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static void FastResize(ref byte[] array, int newSize) + { + if (newSize < 0) throw new ArgumentOutOfRangeException("newSize"); + + byte[] array2 = array; + if (array2 == null) + { + array = new byte[newSize]; + return; + } + + if (array2.Length != newSize) + { + byte[] array3 = new byte[newSize]; + Buffer.BlockCopy(array2, 0, array3, 0, (array2.Length > newSize) ? newSize : array2.Length); + array = array3; + } + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static +#if NETSTANDARD + unsafe +#endif + byte[] FastCloneWithResize(byte[] src, int newSize) + { + if (newSize < 0) throw new ArgumentOutOfRangeException("newSize"); + if (src.Length < newSize) throw new ArgumentException("length < newSize"); + + if (src == null) return new byte[newSize]; + + byte[] dst = new byte[newSize]; + +#if NETSTANDARD && !NET45 + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &dst[0]) + { + Buffer.MemoryCopy(pSrc, pDst, dst.Length, newSize); + } +#else + Buffer.BlockCopy(src, 0, dst, 0, newSize); +#endif + + return dst; + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Internal/ByteArrayComparer.cs b/Unity3D/3rdLib/Utf8Json/Internal/ByteArrayComparer.cs new file mode 100644 index 0000000..9884fc4 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/ByteArrayComparer.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Utf8Json.Internal +{ + public static class ByteArrayComparer + { +#if NETSTANDARD + +#if NETSTANDARD + + static readonly bool Is32Bit = (IntPtr.Size == 4); + + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + public static int GetHashCode(byte[] bytes, int offset, int count) + { + if (Is32Bit) + { + return unchecked((int)FarmHash.Hash32(bytes, offset, count)); + } + else + { + return unchecked((int)FarmHash.Hash64(bytes, offset, count)); + } + } + +#endif + +#if NETSTANDARD + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] +#endif + public static unsafe bool Equals(byte[] xs, int xsOffset, int xsCount, byte[] ys) + { + return Equals(xs, xsOffset, xsCount, ys, 0, ys.Length); + } + +#if NETSTANDARD + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] +#endif + public static unsafe bool Equals(byte[] xs, int xsOffset, int xsCount, byte[] ys, int ysOffset, int ysCount) + { + if (xs == null || ys == null || xsCount != ysCount) + { + return false; + } + if (xsCount == 0 && ysCount == 0) return true; + + fixed (byte* p1 = &xs[xsOffset]) + fixed (byte* p2 = &ys[ysOffset]) + { + switch (xsCount) + { + case 0: + return true; + case 1: + return *p1 == *p2; + case 2: + return *(short*)p1 == *(short*)p2; + case 3: + if (*(byte*)p1 != *(byte*)p2) return false; + return *(short*)(p1 + 1) == *(short*)(p2 + 1); + case 4: + return *(int*)p1 == *(int*)p2; + case 5: + if (*(byte*)p1 != *(byte*)p2) return false; + return *(int*)(p1 + 1) == *(int*)(p2 + 1); + case 6: + if (*(short*)p1 != *(short*)p2) return false; + return *(int*)(p1 + 2) == *(int*)(p2 + 2); + case 7: + if (*(byte*)p1 != *(byte*)p2) return false; + if (*(short*)(p1 + 1) != *(short*)(p2 + 1)) return false; + return *(int*)(p1 + 3) == *(int*)(p2 + 3); + default: + { + var x1 = p1; + var x2 = p2; + + byte* xEnd = p1 + xsCount - 8; + byte* yEnd = p2 + ysCount - 8; + + while (x1 < xEnd) + { + if (*(long*)x1 != *(long*)x2) + { + return false; + } + + x1 += 8; + x2 += 8; + } + + return *(long*)xEnd == *(long*)yEnd; + } + } + } + } + +#else +#if NETSTANDARD + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] +#endif + public static bool Equals(byte[] xs, int xsOffset, int xsCount, byte[] ys) + { + if (xs == null || ys == null || xsCount != ys.Length) + { + return false; + } + + for (int i = 0; i < ys.Length; i++) + { + if (xs[xsOffset++] != ys[i]) return false; + } + + return true; + } + +#if NETSTANDARD + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] +#endif + public static bool Equals(byte[] xs, int xsOffset, int xsCount, byte[] ys, int ysOffset, int ysCount) + { + if (xs == null || ys == null || xsCount != ysCount) + { + return false; + } + + for (int i = 0; i < xsCount; i++) + { + if (xs[xsOffset++] != ys[ysOffset++]) return false; + } + + return true; + } + +#endif + + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/ByteArrayStringHashTable.cs b/Unity3D/3rdLib/Utf8Json/Internal/ByteArrayStringHashTable.cs new file mode 100644 index 0000000..b8bdb27 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/ByteArrayStringHashTable.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace Utf8Json.Internal +{ + // like ArraySegment hashtable. + // Add is safe for construction phase only and requires capacity(does not do rehash) + + internal class ByteArrayStringHashTable : IEnumerable> + { + readonly Entry[][] buckets; // immutable array(faster than linkedlist) + readonly ulong indexFor; + + public ByteArrayStringHashTable(int capacity) + : this(capacity, 0.42f) // default: 0.75f -> 0.42f + { + } + + public ByteArrayStringHashTable(int capacity, float loadFactor) + { + var tableSize = CalculateCapacity(capacity, loadFactor); + this.buckets = new Entry[tableSize][]; + this.indexFor = (ulong)buckets.Length - 1; + } + + public void Add(string key, T value) + { + if (!TryAddInternal(Encoding.UTF8.GetBytes(key), value)) + { + throw new ArgumentException("Key was already exists. Key:" + key); + } + } + + public void Add(byte[] key, T value) + { + if (!TryAddInternal(key, value)) + { + throw new ArgumentException("Key was already exists. Key:" + key); + } + } + + bool TryAddInternal(byte[] key, T value) + { + var h = ByteArrayGetHashCode(key, 0, key.Length); + var entry = new Entry { Key = key, Value = value }; + + var array = buckets[h & (indexFor)]; + if (array == null) + { + buckets[h & (indexFor)] = new[] { entry }; + } + else + { + // check duplicate + for (int i = 0; i < array.Length; i++) + { + var e = array[i].Key; + if (ByteArrayComparer.Equals(key, 0, key.Length, e)) + { + return false; + } + } + + var newArray = new Entry[array.Length + 1]; + Array.Copy(array, newArray, array.Length); + array = newArray; + array[array.Length - 1] = entry; + buckets[h & (indexFor)] = array; + } + + return true; + } + + public bool TryGetValue(ArraySegment key, out T value) + { + var table = buckets; + var hash = ByteArrayGetHashCode(key.Array, key.Offset, key.Count); + var entry = table[hash & indexFor]; + + if (entry == null) goto NOT_FOUND; + + { + var v = entry[0]; + if (ByteArrayComparer.Equals(key.Array, key.Offset, key.Count, v.Key)) + { + value = v.Value; + return true; + } + } + + for (int i = 1; i < entry.Length; i++) + { + var v = entry[i]; + if (ByteArrayComparer.Equals(key.Array, key.Offset, key.Count, v.Key)) + { + value = v.Value; + return true; + } + } + + NOT_FOUND: + value = default(T); + return false; + } + +#if NETSTANDARD + static readonly bool Is32Bit = (IntPtr.Size == 4); +#endif + +#if NETSTANDARD + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] +#endif + static ulong ByteArrayGetHashCode(byte[] x, int offset, int count) + { +#if NETSTANDARD + // FarmHash https://github.com/google/farmhash + if (x == null || x.Length == 0 || count == 0) return 0; + + if (Is32Bit) + { + return (ulong)FarmHash.Hash32(x, offset, count); + } + else + { + return FarmHash.Hash64(x, offset, count); + } + +#else + + // FNV1-1a 32bit https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function + uint hash = 0; + if (x != null) + { + var max = offset + count; + + hash = 2166136261; + for (int i = offset; i < max; i++) + { + hash = unchecked((x[i] ^ hash) * 16777619); + } + } + + return (ulong)hash; + +#endif + } + + static int CalculateCapacity(int collectionSize, float loadFactor) + { + var initialCapacity = (int)(((float)collectionSize) / loadFactor); + var capacity = 1; + while (capacity < initialCapacity) + { + capacity <<= 1; + } + + if (capacity < 8) + { + return 8; + } + + return capacity; + } + + // only for Debug use + public IEnumerator> GetEnumerator() + { + var b = this.buckets; + + foreach (var item in b) + { + if (item == null) continue; + foreach (var item2 in item) + { + yield return new KeyValuePair(Encoding.UTF8.GetString(item2.Key), item2.Value); + } + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + struct Entry + { + public byte[] Key; + public T Value; + + // for debugging + public override string ToString() + { + return "(" + Encoding.UTF8.GetString(Key) + ", " + Value + ")"; + } + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/DiyFp.cs b/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/DiyFp.cs new file mode 100644 index 0000000..2ad4096 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/DiyFp.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Utf8Json.Internal.DoubleConversion +{ + // https://github.com/google/double-conversion/blob/master/double-conversion/diy-fp.cc + // https://github.com/google/double-conversion/blob/master/double-conversion/diy-fp.h + + internal struct DiyFp + { + public const int kSignificandSize = 64; + public const ulong kUint64MSB = 0x8000000000000000; // 0x80000000_00000000; + + // uint64_t f_; + // int e_; + // long f() const { return f_; } + // int e() const { return e_; } + // void set_f(long new_value) { f_ = new_value; } + // void set_e(int new_value) { e_ = new_value; } + + // public field, not safe... + public ulong f; + public int e; + + public DiyFp(ulong significand, int exponent) + { + this.f = significand; + this.e = exponent; + } + + // this = this - other. + // The exponents of both numbers must be the same and the significand of this + // must be bigger than the significand of other. + // The result will not be normalized. + public void Subtract(ref DiyFp other) + { + f -= other.f; + } + + // Returns a - b. + // The exponents of both numbers must be the same and this must be bigger + // than other. The result will not be normalized. + public static DiyFp Minus(ref DiyFp a, ref DiyFp b) + { + DiyFp result = a; + result.Subtract(ref b); + return result; + } + + public static DiyFp operator -(DiyFp lhs, DiyFp rhs) + { + return Minus(ref lhs, ref rhs); + } + + // this = this * other. + public void Multiply(ref DiyFp other) + { + // Simply "emulates" a 128 bit multiplication. + // However: the resulting number only contains 64 bits. The least + // significant 64 bits are only used for rounding the most significant 64 + // bits. + const long kM32 = 0xFFFFFFFFU; + ulong a = f >> 32; + ulong b = f & kM32; + ulong c = other.f >> 32; + ulong d = other.f & kM32; + ulong ac = a * c; + ulong bc = b * c; + ulong ad = a * d; + ulong bd = b * d; + ulong tmp = (bd >> 32) + (ad & kM32) + (bc & kM32); + // By adding 1U << 31 to tmp we round the final result. + // Halfway cases will be round up. + tmp += 1U << 31; + ulong result_f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32); + e += other.e + 64; + f = result_f; + } + + // returns a * b; + public static DiyFp Times(ref DiyFp a, ref DiyFp b) + { + DiyFp result = a; + result.Multiply(ref b); + return result; + } + + public static DiyFp operator *(DiyFp lhs, DiyFp rhs) + { + return Times(ref lhs, ref rhs); + } + + public void Normalize() + { + ulong significand = f; + int exponent = e; + + // This method is mainly called for normalizing boundaries. In general + // boundaries need to be shifted by 10 bits. We thus optimize for this case. + const ulong k10MSBits = 0xFFC0000000000000; // UINT64_2PART_C(0xFFC00000, 00000000); + while ((significand & k10MSBits) == 0) + { + significand <<= 10; + exponent -= 10; + } + while ((significand & kUint64MSB) == 0) + { + significand <<= 1; + exponent--; + } + f = significand; + e = exponent; + } + + public static DiyFp Normalize(ref DiyFp a) + { + DiyFp result = a; + result.Normalize(); + return result; + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/DoubleToStringConverter.cs b/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/DoubleToStringConverter.cs new file mode 100644 index 0000000..b371a6a --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/DoubleToStringConverter.cs @@ -0,0 +1,858 @@ +using System; +using System.Globalization; + +namespace Utf8Json.Internal.DoubleConversion +{ + using uint64_t = System.UInt64; + using uint32_t = System.UInt32; + using System.Collections.Generic; + + internal struct StringBuilder + { + public byte[] buffer; + public int offset; + + public StringBuilder(byte[] buffer, int position) + { + this.buffer = buffer; + this.offset = position; + } + + public void AddCharacter(byte str) + { + BinaryUtil.EnsureCapacity(ref buffer, offset, 1); + buffer[offset++] = str; + } + + public void AddString(byte[] str) + { + BinaryUtil.EnsureCapacity(ref buffer, offset, str.Length); + for (int i = 0; i < str.Length; i++) + { + buffer[offset + i] = str[i]; + } + offset += str.Length; + } + + public void AddSubstring(byte[] str, int length) + { + BinaryUtil.EnsureCapacity(ref buffer, offset, length); + for (int i = 0; i < length; i++) + { + buffer[offset + i] = str[i]; + } + offset += length; + } + + public void AddSubstring(byte[] str, int start, int length) + { + BinaryUtil.EnsureCapacity(ref buffer, offset, length); + for (int i = 0; i < length; i++) + { + buffer[offset + i] = str[start + i]; + } + offset += length; + } + + public void AddPadding(byte c, int count) + { + BinaryUtil.EnsureCapacity(ref buffer, offset, count); + for (int i = 0; i < count; i++) + { + buffer[offset + i] = c; + } + offset += count; + } + + public void AddStringSlow(string str) + { + BinaryUtil.EnsureCapacity(ref buffer, offset, StringEncoding.UTF8.GetMaxByteCount(str.Length)); + offset += StringEncoding.UTF8.GetBytes(str, 0, str.Length, buffer, offset); + } + } + + // C# API + internal static partial class DoubleToStringConverter + { + [ThreadStatic] + static byte[] decimalRepBuffer; + + [ThreadStatic] + static byte[] exponentialRepBuffer; + + [ThreadStatic] + static byte[] toStringBuffer; + + static byte[] GetDecimalRepBuffer(int size) + { + if (decimalRepBuffer == null) + { + decimalRepBuffer = new byte[size]; + } + return decimalRepBuffer; + } + + static byte[] GetExponentialRepBuffer(int size) + { + if (exponentialRepBuffer == null) + { + exponentialRepBuffer = new byte[size]; + } + return exponentialRepBuffer; + } + + static byte[] GetToStringBuffer() + { + if (toStringBuffer == null) + { + toStringBuffer = new byte[24]; + } + return toStringBuffer; + } + + public static int GetBytes(ref byte[] buffer, int offset, float value) + { + var sb = new StringBuilder(buffer, offset); + if (!ToShortestIeeeNumber(value, ref sb, DtoaMode.SHORTEST_SINGLE)) + { + throw new InvalidOperationException("not support float value:" + value); + } + + buffer = sb.buffer; + return sb.offset - offset; + } + + public static int GetBytes(ref byte[] buffer, int offset, double value) + { + var sb = new StringBuilder(buffer, offset); + if (!ToShortestIeeeNumber(value, ref sb, DtoaMode.SHORTEST)) + { + throw new InvalidOperationException("not support double value:" + value); + } + + buffer = sb.buffer; + return sb.offset - offset; + } + } + + // private porting methods + // https://github.com/google/double-conversion/blob/master/double-conversion/fast-dtoa.h + // https://github.com/google/double-conversion/blob/master/double-conversion/fast-dtoa.cc + + internal static partial class DoubleToStringConverter + { + enum FastDtoaMode + { + // Computes the shortest representation of the given input. The returned + // result will be the most accurate number of this length. Longer + // representations might be more accurate. + FAST_DTOA_SHORTEST, + // Same as FAST_DTOA_SHORTEST but for single-precision floats. + FAST_DTOA_SHORTEST_SINGLE, + // Computes a representation where the precision (number of digits) is + // given as input. The precision is independent of the decimal point. + // FAST_DTOA_PRECISION + }; + + enum DtoaMode + { + SHORTEST, + SHORTEST_SINGLE, + // FIXED, + // PRECISION + } + + enum Flags + { + NO_FLAGS = 0, + EMIT_POSITIVE_EXPONENT_SIGN = 1, + EMIT_TRAILING_DECIMAL_POINT = 2, + EMIT_TRAILING_ZERO_AFTER_POINT = 4, + UNIQUE_ZERO = 8 + }; + + // C# constants + static readonly byte[] infinity_symbol_ = StringEncoding.UTF8.GetBytes(double.PositiveInfinity.ToString()); + static readonly byte[] nan_symbol_ = StringEncoding.UTF8.GetBytes(double.NaN.ToString()); + + // constructor parameter, same as EcmaScriptConverter + //DoubleToStringConverter(int flags, + // const char* infinity_symbol, + // const char* nan_symbol, + // char exponent_character, + // int decimal_in_shortest_low, + // int decimal_in_shortest_high, + // int max_leading_padding_zeroes_in_precision_mode, + // int max_trailing_padding_zeroes_in_precision_mode) + + //const char exponent_character_; + //const int decimal_in_shortest_low_; + //const int decimal_in_shortest_high_; + //const int max_leading_padding_zeroes_in_precision_mode_; + //const int max_trailing_padding_zeroes_in_precision_mode_; + + static readonly Flags flags_ = Flags.UNIQUE_ZERO | Flags.EMIT_POSITIVE_EXPONENT_SIGN; + static readonly char exponent_character_ = 'E'; + static readonly int decimal_in_shortest_low_ = -4; // C# ToString("G") + static readonly int decimal_in_shortest_high_ = 15;// C# ToString("G") + + const int kBase10MaximalLength = 17; + + const int kFastDtoaMaximalLength = 17; + // Same for single-precision numbers. + const int kFastDtoaMaximalSingleLength = 9; + + // The minimal and maximal target exponent define the range of w's binary + // exponent, where 'w' is the result of multiplying the input by a cached power + // of ten. + // + // A different range might be chosen on a different platform, to optimize digit + // generation, but a smaller range requires more powers of ten to be cached. + const int kMinimalTargetExponent = -60; + const int kMaximalTargetExponent = -32; + + // Adjusts the last digit of the generated number, and screens out generated + // solutions that may be inaccurate. A solution may be inaccurate if it is + // outside the safe interval, or if we cannot prove that it is closer to the + // input than a neighboring representation of the same length. + // + // Input: * buffer containing the digits of too_high / 10^kappa + // * the buffer's length + // * distance_too_high_w == (too_high - w).f() * unit + // * unsafe_interval == (too_high - too_low).f() * unit + // * rest = (too_high - buffer * 10^kappa).f() * unit + // * ten_kappa = 10^kappa * unit + // * unit = the common multiplier + // Output: returns true if the buffer is guaranteed to contain the closest + // representable number to the input. + // Modifies the generated digits in the buffer to approach (round towards) w. + static bool RoundWeed(byte[] buffer, + int length, + uint64_t distance_too_high_w, + uint64_t unsafe_interval, + uint64_t rest, + uint64_t ten_kappa, + uint64_t unit) + { + uint64_t small_distance = distance_too_high_w - unit; + uint64_t big_distance = distance_too_high_w + unit; + // Let w_low = too_high - big_distance, and + // w_high = too_high - small_distance. + // Note: w_low < w < w_high + // + // The real w (* unit) must lie somewhere inside the interval + // ]w_low; w_high[ (often written as "(w_low; w_high)") + + // Basically the buffer currently contains a number in the unsafe interval + // ]too_low; too_high[ with too_low < w < too_high + // + // too_high - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // ^v 1 unit ^ ^ ^ ^ + // boundary_high --------------------- . . . . + // ^v 1 unit . . . . + // - - - - - - - - - - - - - - - - - - - + - - + - - - - - - . . + // . . ^ . . + // . big_distance . . . + // . . . . rest + // small_distance . . . . + // v . . . . + // w_high - - - - - - - - - - - - - - - - - - . . . . + // ^v 1 unit . . . . + // w ---------------------------------------- . . . . + // ^v 1 unit v . . . + // w_low - - - - - - - - - - - - - - - - - - - - - . . . + // . . v + // buffer --------------------------------------------------+-------+-------- + // . . + // safe_interval . + // v . + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - . + // ^v 1 unit . + // boundary_low ------------------------- unsafe_interval + // ^v 1 unit v + // too_low - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // + // Note that the value of buffer could lie anywhere inside the range too_low + // to too_high. + // + // boundary_low, boundary_high and w are approximations of the real boundaries + // and v (the input number). They are guaranteed to be precise up to one unit. + // In fact the error is guaranteed to be strictly less than one unit. + // + // Anything that lies outside the unsafe interval is guaranteed not to round + // to v when read again. + // Anything that lies inside the safe interval is guaranteed to round to v + // when read again. + // If the number inside the buffer lies inside the unsafe interval but not + // inside the safe interval then we simply do not know and bail out (returning + // false). + // + // Similarly we have to take into account the imprecision of 'w' when finding + // the closest representation of 'w'. If we have two potential + // representations, and one is closer to both w_low and w_high, then we know + // it is closer to the actual value v. + // + // By generating the digits of too_high we got the largest (closest to + // too_high) buffer that is still in the unsafe interval. In the case where + // w_high < buffer < too_high we try to decrement the buffer. + // This way the buffer approaches (rounds towards) w. + // There are 3 conditions that stop the decrementation process: + // 1) the buffer is already below w_high + // 2) decrementing the buffer would make it leave the unsafe interval + // 3) decrementing the buffer would yield a number below w_high and farther + // away than the current number. In other words: + // (buffer{-1} < w_high) && w_high - buffer{-1} > buffer - w_high + // Instead of using the buffer directly we use its distance to too_high. + // Conceptually rest ~= too_high - buffer + // We need to do the following tests in this order to avoid over- and + // underflows. + while (rest < small_distance && // Negated condition 1 + unsafe_interval - rest >= ten_kappa && // Negated condition 2 + (rest + ten_kappa < small_distance || // buffer{-1} > w_high + small_distance - rest >= rest + ten_kappa - small_distance)) + { + buffer[length - 1]--; + rest += ten_kappa; + } + + // We have approached w+ as much as possible. We now test if approaching w- + // would require changing the buffer. If yes, then we have two possible + // representations close to w, but we cannot decide which one is closer. + if (rest < big_distance && + unsafe_interval - rest >= ten_kappa && + (rest + ten_kappa < big_distance || + big_distance - rest > rest + ten_kappa - big_distance)) + { + return false; + } + + // Weeding test. + // The safe interval is [too_low + 2 ulp; too_high - 2 ulp] + // Since too_low = too_high - unsafe_interval this is equivalent to + // [too_high - unsafe_interval + 4 ulp; too_high - 2 ulp] + // Conceptually we have: rest ~= too_high - buffer + return (2 * unit <= rest) && (rest <= unsafe_interval - 4 * unit); + } + + // Returns the biggest power of ten that is less than or equal to the given + // number. We furthermore receive the maximum number of bits 'number' has. + // + // Returns power == 10^(exponent_plus_one-1) such that + // power <= number < power * 10. + // If number_bits == 0 then 0^(0-1) is returned. + // The number of bits must be <= 32. + // Precondition: number < (1 << (number_bits + 1)). + + // Inspired by the method for finding an integer log base 10 from here: + // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 + static readonly uint[] kSmallPowersOfTen = new uint[] { 0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + + static void BiggestPowerTen(uint32_t number, + int number_bits, + out uint32_t power, + out int exponent_plus_one) + { + // 1233/4096 is approximately 1/lg(10). + int exponent_plus_one_guess = ((number_bits + 1) * 1233 >> 12); + // We increment to skip over the first entry in the kPowersOf10 table. + // Note: kPowersOf10[i] == 10^(i-1). + exponent_plus_one_guess++; + // We don't have any guarantees that 2^number_bits <= number. + if (number < kSmallPowersOfTen[exponent_plus_one_guess]) + { + exponent_plus_one_guess--; + } + power = kSmallPowersOfTen[exponent_plus_one_guess]; + exponent_plus_one = exponent_plus_one_guess; + } + + // Generates the digits of input number w. + // w is a floating-point number (DiyFp), consisting of a significand and an + // exponent. Its exponent is bounded by kMinimalTargetExponent and + // kMaximalTargetExponent. + // Hence -60 <= w.e() <= -32. + // + // Returns false if it fails, in which case the generated digits in the buffer + // should not be used. + // Preconditions: + // * low, w and high are correct up to 1 ulp (unit in the last place). That + // is, their error must be less than a unit of their last digits. + // * low.e() == w.e() == high.e() + // * low < w < high, and taking into account their error: low~ <= high~ + // * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent + // Postconditions: returns false if procedure fails. + // otherwise: + // * buffer is not null-terminated, but len contains the number of digits. + // * buffer contains the shortest possible decimal digit-sequence + // such that LOW < buffer * 10^kappa < HIGH, where LOW and HIGH are the + // correct values of low and high (without their error). + // * if more than one decimal representation gives the minimal number of + // decimal digits then the one closest to W (where W is the correct value + // of w) is chosen. + // Remark: this procedure takes into account the imprecision of its input + // numbers. If the precision is not enough to guarantee all the postconditions + // then false is returned. This usually happens rarely (~0.5%). + // + // Say, for the sake of example, that + // w.e() == -48, and w.f() == 0x1234567890abcdef + // w's value can be computed by w.f() * 2^w.e() + // We can obtain w's integral digits by simply shifting w.f() by -w.e(). + // -> w's integral part is 0x1234 + // w's fractional part is therefore 0x567890abcdef. + // Printing w's integral part is easy (simply print 0x1234 in decimal). + // In order to print its fraction we repeatedly multiply the fraction by 10 and + // get each digit. Example the first digit after the point would be computed by + // (0x567890abcdef * 10) >> 48. -> 3 + // The whole thing becomes slightly more complicated because we want to stop + // once we have enough digits. That is, once the digits inside the buffer + // represent 'w' we can stop. Everything inside the interval low - high + // represents w. However we have to pay attention to low, high and w's + // imprecision. + static bool DigitGen(DiyFp low, + DiyFp w, + DiyFp high, + byte[] buffer, + out int length, + out int kappa) + { + // low, w and high are imprecise, but by less than one ulp (unit in the last + // place). + // If we remove (resp. add) 1 ulp from low (resp. high) we are certain that + // the new numbers are outside of the interval we want the final + // representation to lie in. + // Inversely adding (resp. removing) 1 ulp from low (resp. high) would yield + // numbers that are certain to lie in the interval. We will use this fact + // later on. + // We will now start by generating the digits within the uncertain + // interval. Later we will weed out representations that lie outside the safe + // interval and thus _might_ lie outside the correct interval. + uint64_t unit = 1; + DiyFp too_low = new DiyFp(low.f - unit, low.e); + DiyFp too_high = new DiyFp(high.f + unit, high.e); + // too_low and too_high are guaranteed to lie outside the interval we want the + // generated number in. + DiyFp unsafe_interval = DiyFp.Minus(ref too_high, ref too_low); + // We now cut the input number into two parts: the integral digits and the + // fractionals. We will not write any decimal separator though, but adapt + // kappa instead. + // Reminder: we are currently computing the digits (stored inside the buffer) + // such that: too_low < buffer * 10^kappa < too_high + // We use too_high for the digit_generation and stop as soon as possible. + // If we stop early we effectively round down. + DiyFp one = new DiyFp((uint64_t)(1) << -w.e, w.e); + // Division by one is a shift. + uint32_t integrals = (uint32_t)(too_high.f >> -one.e); + // Modulo by one is an and. + uint64_t fractionals = too_high.f & (one.f - 1); + uint32_t divisor; + int divisor_exponent_plus_one; + BiggestPowerTen(integrals, DiyFp.kSignificandSize - (-one.e), + out divisor, out divisor_exponent_plus_one); + kappa = divisor_exponent_plus_one; + length = 0; + // Loop invariant: buffer = too_high / 10^kappa (integer division) + // The invariant holds for the first iteration: kappa has been initialized + // with the divisor exponent + 1. And the divisor is the biggest power of ten + // that is smaller than integrals. + while (kappa > 0) + { + int digit = unchecked((int)(integrals / divisor)); + buffer[length] = (byte)((byte)'0' + digit); + (length)++; + integrals %= divisor; + (kappa)--; + // Note that kappa now equals the exponent of the divisor and that the + // invariant thus holds again. + uint64_t rest = + ((uint64_t)(integrals) << -one.e) + fractionals; + // Invariant: too_high = buffer * 10^kappa + DiyFp(rest, one.e()) + // Reminder: unsafe_interval.e() == one.e() + if (rest < unsafe_interval.f) + { + // Rounding down (by not emitting the remaining digits) yields a number + // that lies within the unsafe interval. + return RoundWeed(buffer, length, DiyFp.Minus(ref too_high, ref w).f, + unsafe_interval.f, rest, + (uint64_t)(divisor) << -one.e, unit); + } + divisor /= 10; + } + + // The integrals have been generated. We are at the point of the decimal + // separator. In the following loop we simply multiply the remaining digits by + // 10 and divide by one. We just need to pay attention to multiply associated + // data (like the interval or 'unit'), too. + // Note that the multiplication by 10 does not overflow, because w.e >= -60 + // and thus one.e >= -60. + for (; ; ) + { + fractionals *= 10; + unit *= 10; + unsafe_interval.f = (unsafe_interval.f * 10); + // Integer division by one. + int digit = (int)(fractionals >> -one.e); + buffer[length] = (byte)((byte)'0' + digit); + (length)++; + fractionals &= one.f - 1; // Modulo by one. + (kappa)--; + if (fractionals < unsafe_interval.f) + { + return RoundWeed(buffer, length, DiyFp.Minus(ref too_high, ref w).f * unit, + unsafe_interval.f, fractionals, one.f, unit); + } + } + } + + // Provides a decimal representation of v. + // Returns true if it succeeds, otherwise the result cannot be trusted. + // There will be *length digits inside the buffer (not null-terminated). + // If the function returns true then + // v == (double) (buffer * 10^decimal_exponent). + // The digits in the buffer are the shortest representation possible: no + // 0.09999999999999999 instead of 0.1. The shorter representation will even be + // chosen even if the longer one would be closer to v. + // The last digit will be closest to the actual v. That is, even if several + // digits might correctly yield 'v' when read again, the closest will be + // computed. + static bool Grisu3(double v, + FastDtoaMode mode, + byte[] buffer, + out int length, + out int decimal_exponent) + { + DiyFp w = new Double(v).AsNormalizedDiyFp(); + // boundary_minus and boundary_plus are the boundaries between v and its + // closest floating-point neighbors. Any number strictly between + // boundary_minus and boundary_plus will round to v when convert to a double. + // Grisu3 will never output representations that lie exactly on a boundary. + DiyFp boundary_minus, boundary_plus; + if (mode == FastDtoaMode.FAST_DTOA_SHORTEST) + { + new Double(v).NormalizedBoundaries(out boundary_minus, out boundary_plus); + } + else if (mode == FastDtoaMode.FAST_DTOA_SHORTEST_SINGLE) + { + float single_v = (float)(v); + new Single(single_v).NormalizedBoundaries(out boundary_minus, out boundary_plus); + } + else + { + throw new Exception("Invalid Mode."); + } + + DiyFp ten_mk; // Cached power of ten: 10^-k + int mk; // -k + int ten_mk_minimal_binary_exponent = + kMinimalTargetExponent - (w.e + DiyFp.kSignificandSize); + int ten_mk_maximal_binary_exponent = + kMaximalTargetExponent - (w.e + DiyFp.kSignificandSize); + PowersOfTenCache.GetCachedPowerForBinaryExponentRange( + ten_mk_minimal_binary_exponent, + ten_mk_maximal_binary_exponent, + out ten_mk, out mk); + + // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a + // 64 bit significand and ten_mk is thus only precise up to 64 bits. + + // The DiyFp::Times procedure rounds its result, and ten_mk is approximated + // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now + // off by a small amount. + // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w. + // In other words: let f = scaled_w.f() and e = scaled_w.e(), then + // (f-1) * 2^e < w*10^k < (f+1) * 2^e + DiyFp scaled_w = DiyFp.Times(ref w, ref ten_mk); + + // In theory it would be possible to avoid some recomputations by computing + // the difference between w and boundary_minus/plus (a power of 2) and to + // compute scaled_boundary_minus/plus by subtracting/adding from + // scaled_w. However the code becomes much less readable and the speed + // enhancements are not terriffic. + DiyFp scaled_boundary_minus = DiyFp.Times(ref boundary_minus, ref ten_mk); + DiyFp scaled_boundary_plus = DiyFp.Times(ref boundary_plus, ref ten_mk); + + // DigitGen will generate the digits of scaled_w. Therefore we have + // v == (double) (scaled_w * 10^-mk). + // Set decimal_exponent == -mk and pass it to DigitGen. If scaled_w is not an + // integer than it will be updated. For instance if scaled_w == 1.23 then + // the buffer will be filled with "123" und the decimal_exponent will be + // decreased by 2. + int kappa; + bool result = DigitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus, + buffer, out length, out kappa); + decimal_exponent = -mk + kappa; + return result; + } + + static bool FastDtoa(double v, + FastDtoaMode mode, + // int requested_digits, + byte[] buffer, + out int length, + out int decimal_point) + { + bool result = false; + int decimal_exponent = 0; + switch (mode) + { + case FastDtoaMode.FAST_DTOA_SHORTEST: + case FastDtoaMode.FAST_DTOA_SHORTEST_SINGLE: + result = Grisu3(v, mode, buffer, out length, out decimal_exponent); + break; + // case FastDtoaMode.FAST_DTOA_PRECISION: + //result = Grisu3Counted(v, requested_digits, buffer, length, &decimal_exponent); + default: + throw new Exception("unreachable code."); + } + if (result) + { + decimal_point = length + decimal_exponent; + } + else + { + decimal_point = -1; + } + return result; + } + + // https://github.com/google/double-conversion/blob/master/double-conversion/double-conversion.cc + + static bool HandleSpecialValues( + double value, + ref StringBuilder result_builder) + { + Double double_inspect = new Double(value); + if (double_inspect.IsInfinite()) + { + if (infinity_symbol_ == null) return false; + if (value < 0) + { + result_builder.AddCharacter((byte)'-'); + } + result_builder.AddString(infinity_symbol_); + return true; + } + if (double_inspect.IsNan()) + { + if (nan_symbol_ == null) return false; + result_builder.AddString(nan_symbol_); + return true; + } + return false; + } + + static bool ToShortestIeeeNumber( + double value, + ref StringBuilder result_builder, + DtoaMode mode) + { + if (new Double(value).IsSpecial()) + { + return HandleSpecialValues(value, ref result_builder); + } + + int decimal_point; + bool sign; + const int kDecimalRepCapacity = kBase10MaximalLength + 1; + var decimal_rep = GetDecimalRepBuffer(kDecimalRepCapacity); // byte[] decimal_rep = new byte[kDecimalRepCapacity]; + int decimal_rep_length; + + var fastworked = DoubleToAscii(value, mode, 0, decimal_rep, + out sign, out decimal_rep_length, out decimal_point); + + if (!fastworked) + { + // C# custom, slow path + var str = value.ToString("G17", CultureInfo.InvariantCulture); + result_builder.AddStringSlow(str); + return true; + } + + bool unique_zero = (flags_ & Flags.UNIQUE_ZERO) != 0; + if (sign && (value != 0.0 || !unique_zero)) + { + result_builder.AddCharacter((byte)'-'); + } + + int exponent = decimal_point - 1; + if ((decimal_in_shortest_low_ <= exponent) && + (exponent < decimal_in_shortest_high_)) + { + CreateDecimalRepresentation(decimal_rep, decimal_rep_length, + decimal_point, + Math.Max(0, decimal_rep_length - decimal_point), + ref result_builder); + } + else + { + CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent, + ref result_builder); + } + + return true; + } + + static void CreateDecimalRepresentation( + byte[] decimal_digits, + int length, + int decimal_point, + int digits_after_point, + ref StringBuilder result_builder) + { + // Create a representation that is padded with zeros if needed. + if (decimal_point <= 0) + { + // "0.00000decimal_rep" or "0.000decimal_rep00". + result_builder.AddCharacter((byte)'0'); + if (digits_after_point > 0) + { + result_builder.AddCharacter((byte)'.'); + result_builder.AddPadding((byte)'0', -decimal_point); + result_builder.AddSubstring(decimal_digits, length); + int remaining_digits = digits_after_point - (-decimal_point) - length; + result_builder.AddPadding((byte)'0', remaining_digits); + } + } + else if (decimal_point >= length) + { + // "decimal_rep0000.00000" or "decimal_rep.0000". + result_builder.AddSubstring(decimal_digits, length); + result_builder.AddPadding((byte)'0', decimal_point - length); + if (digits_after_point > 0) + { + result_builder.AddCharacter((byte)'.'); + result_builder.AddPadding((byte)'0', digits_after_point); + } + } + else + { + // "decima.l_rep000". + result_builder.AddSubstring(decimal_digits, decimal_point); + result_builder.AddCharacter((byte)'.'); + result_builder.AddSubstring(decimal_digits, decimal_point, length - decimal_point); + int remaining_digits = digits_after_point - (length - decimal_point); + result_builder.AddPadding((byte)'0', remaining_digits); + } + if (digits_after_point == 0) + { + if ((flags_ & Flags.EMIT_TRAILING_DECIMAL_POINT) != 0) + { + result_builder.AddCharacter((byte)'.'); + } + if ((flags_ & Flags.EMIT_TRAILING_ZERO_AFTER_POINT) != 0) + { + result_builder.AddCharacter((byte)'0'); + } + } + } + + static void CreateExponentialRepresentation( + byte[] decimal_digits, + int length, + int exponent, + ref StringBuilder result_builder) + { + result_builder.AddCharacter(decimal_digits[0]); + if (length != 1) + { + result_builder.AddCharacter((byte)'.'); + result_builder.AddSubstring(decimal_digits, 1, length - 1); + } + result_builder.AddCharacter((byte)exponent_character_); + if (exponent < 0) + { + result_builder.AddCharacter((byte)'-'); + exponent = -exponent; + } + else + { + if ((flags_ & Flags.EMIT_POSITIVE_EXPONENT_SIGN) != 0) + { + result_builder.AddCharacter((byte)'+'); + } + } + if (exponent == 0) + { + result_builder.AddCharacter((byte)'0'); + return; + } + const int kMaxExponentLength = 5; + byte[] buffer = GetExponentialRepBuffer(kMaxExponentLength + 1); + buffer[kMaxExponentLength] = (byte)'\0'; + int first_char_pos = kMaxExponentLength; + while (exponent > 0) + { + buffer[--first_char_pos] = (byte)((byte)'0' + (exponent % 10)); + exponent /= 10; + } + result_builder.AddSubstring(buffer, first_char_pos, kMaxExponentLength - first_char_pos); + } + + // modified, return fast_worked. + static bool DoubleToAscii(double v, + DtoaMode mode, + int requested_digits, + //byte[] buffer, + //int buffer_length, + byte[] vector, // already allocate + out bool sign, + out int length, + out int point) + { + if (new Double(v).Sign() < 0) + { + sign = true; + v = -v; + } + else + { + sign = false; + } + + //if (mode == DtoaMode.PRECISION && requested_digits == 0) + //{ + // vector[0] = '\0'; + // *length = 0; + // return; + //} + + if (v == 0) + { + vector[0] = (byte)'0'; + // vector[1] = '\0'; + length = 1; + point = 1; + return true; + } + + bool fast_worked; + switch (mode) + { + case DtoaMode.SHORTEST: + fast_worked = FastDtoa(v, FastDtoaMode.FAST_DTOA_SHORTEST, vector, out length, out point); + break; + case DtoaMode.SHORTEST_SINGLE: + fast_worked = FastDtoa(v, FastDtoaMode.FAST_DTOA_SHORTEST_SINGLE, vector, out length, out point); + break; + //case FIXED: + // fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point); + // break; + //case PRECISION: + // fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits, + // vector, length, point); + // break; + default: + fast_worked = false; + throw new Exception("Unreachable code."); + } + // if (fast_worked) return; + + // If the fast dtoa didn't succeed use the slower bignum version. + // BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode); + // BignumDtoa(v, bignum_mode, requested_digits, vector, length, point); + // vector[*length] = '\0'; + + return fast_worked; + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/IEEE.cs b/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/IEEE.cs new file mode 100644 index 0000000..8d7d470 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/IEEE.cs @@ -0,0 +1,441 @@ +using System; +using System.Runtime.InteropServices; + +namespace Utf8Json.Internal.DoubleConversion +{ + using uint32_t = UInt32; + + [StructLayout(LayoutKind.Explicit, Pack = 1)] + internal struct UnionDoubleULong + { + [FieldOffset(0)] + public double d; + [FieldOffset(0)] + public ulong u64; + } + + [StructLayout(LayoutKind.Explicit, Pack = 1)] + internal struct UnionFloatUInt + { + [FieldOffset(0)] + public float f; + [FieldOffset(0)] + public uint u32; + } + + // https://github.com/google/double-conversion/blob/master/double-conversion/ieee.h + + internal struct Double + { + public const ulong kSignMask = (0x8000000000000000); + public const ulong kExponentMask = (0x7FF0000000000000); + public const ulong kSignificandMask = (0x000FFFFFFFFFFFFF); + public const ulong kHiddenBit = (0x0010000000000000); + public const int kPhysicalSignificandSize = 52; // Excludes the hidden bit. + public const int kSignificandSize = 53; + + const int kExponentBias = 0x3FF + kPhysicalSignificandSize; + const int kDenormalExponent = -kExponentBias + 1; + const int kMaxExponent = 0x7FF - kExponentBias; + const ulong kInfinity = (0x7FF0000000000000); + const ulong kNaN = (0x7FF8000000000000); + + ulong d64_; + + public Double(double d) + { + d64_ = new UnionDoubleULong { d = d }.u64; + } + + public Double(DiyFp d) + { + d64_ = DiyFpToUint64(d); + } + + // The value encoded by this Double must be greater or equal to +0.0. + // It must not be special (infinity, or NaN). + public DiyFp AsDiyFp() + { + return new DiyFp(Significand(), Exponent()); + } + + // The value encoded by this Double must be strictly greater than 0. + public DiyFp AsNormalizedDiyFp() + { + ulong f = Significand(); + int e = Exponent(); + + // The current double could be a denormal. + while ((f & kHiddenBit) == 0) + { + f <<= 1; + e--; + } + // Do the final shifts in one go. + f <<= DiyFp.kSignificandSize - kSignificandSize; + e -= DiyFp.kSignificandSize - kSignificandSize; + return new DiyFp(f, e); + } + + // Returns the double's bit as uint64. + public ulong AsUint64() + { + return d64_; + } + + // Returns the next greater double. Returns +infinity on input +infinity. + public double NextDouble() + { + if (d64_ == kInfinity) return new Double(kInfinity).value(); + if (Sign() < 0 && Significand() == 0) + { + // -0.0 + return 0.0; + } + if (Sign() < 0) + { + return new Double(d64_ - 1).value(); + } + else + { + return new Double(d64_ + 1).value(); + } + } + + public double PreviousDouble() + { + if (d64_ == (kInfinity | kSignMask)) return -Infinity(); + if (Sign() < 0) + { + return new Double(d64_ + 1).value(); + } + else + { + if (Significand() == 0) return -0.0; + return new Double(d64_ - 1).value(); + } + } + + public int Exponent() + { + if (IsDenormal()) return kDenormalExponent; + + ulong d64 = AsUint64(); + int biased_e = + (int)((d64 & kExponentMask) >> kPhysicalSignificandSize); + return biased_e - kExponentBias; + } + + public ulong Significand() + { + ulong d64 = AsUint64(); + ulong significand = d64 & kSignificandMask; + if (!IsDenormal()) + { + return significand + kHiddenBit; + } + else + { + return significand; + } + } + + // Returns true if the double is a denormal. + public bool IsDenormal() + { + ulong d64 = AsUint64(); + return (d64 & kExponentMask) == 0; + } + + // We consider denormals not to be special. + // Hence only Infinity and NaN are special. + public bool IsSpecial() + { + ulong d64 = AsUint64(); + return (d64 & kExponentMask) == kExponentMask; + } + + public bool IsNan() + { + ulong d64 = AsUint64(); + return ((d64 & kExponentMask) == kExponentMask) && + ((d64 & kSignificandMask) != 0); + } + + public bool IsInfinite() + { + ulong d64 = AsUint64(); + return ((d64 & kExponentMask) == kExponentMask) && + ((d64 & kSignificandMask) == 0); + } + + public int Sign() + { + ulong d64 = AsUint64(); + return (d64 & kSignMask) == 0 ? 1 : -1; + } + + // Precondition: the value encoded by this Double must be greater or equal + // than +0.0. + public DiyFp UpperBoundary() + { + return new DiyFp(Significand() * 2 + 1, Exponent() - 1); + } + + // Computes the two boundaries of this. + // The bigger boundary (m_plus) is normalized. The lower boundary has the same + // exponent as m_plus. + // Precondition: the value encoded by this Double must be greater than 0. + public void NormalizedBoundaries(out DiyFp out_m_minus, out DiyFp out_m_plus) + { + DiyFp v = this.AsDiyFp(); + var __ = new DiyFp((v.f << 1) + 1, v.e - 1); + var m_plus = DiyFp.Normalize(ref __); + + DiyFp m_minus; + if (LowerBoundaryIsCloser()) + { + m_minus = new DiyFp((v.f << 2) - 1, v.e - 2); + } + else + { + m_minus = new DiyFp((v.f << 1) - 1, v.e - 1); + } + m_minus.f = m_minus.f << (m_minus.e - m_plus.e); + m_minus.e = (m_plus.e); + out_m_plus = m_plus; + out_m_minus = m_minus; + } + + public bool LowerBoundaryIsCloser() + { + // The boundary is closer if the significand is of the form f == 2^p-1 then + // the lower boundary is closer. + // Think of v = 1000e10 and v- = 9999e9. + // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but + // at a distance of 1e8. + // The only exception is for the smallest normal: the largest denormal is + // at the same distance as its successor. + // Note: denormals have the same exponent as the smallest normals. + bool physical_significand_is_zero = ((AsUint64() & kSignificandMask) == 0); + return physical_significand_is_zero && (Exponent() != kDenormalExponent); + } + + public double value() + { + return new UnionDoubleULong { u64 = d64_ }.d; + } + + // Returns the significand size for a given order of magnitude. + // If v = f*2^e with 2^p-1 <= f <= 2^p then p+e is v's order of magnitude. + // This function returns the number of significant binary digits v will have + // once it's encoded into a double. In almost all cases this is equal to + // kSignificandSize. The only exceptions are denormals. They start with + // leading zeroes and their effective significand-size is hence smaller. + public static int SignificandSizeForOrderOfMagnitude(int order) + { + if (order >= (kDenormalExponent + kSignificandSize)) + { + return kSignificandSize; + } + if (order <= kDenormalExponent) return 0; + return order - kDenormalExponent; + } + + public static double Infinity() + { + return new Double(kInfinity).value(); + } + + public static double NaN() + { + return new Double(kNaN).value(); + } + + public static ulong DiyFpToUint64(DiyFp diy_fp) + { + ulong significand = diy_fp.f; + int exponent = diy_fp.e; + while (significand > kHiddenBit + kSignificandMask) + { + significand >>= 1; + exponent++; + } + if (exponent >= kMaxExponent) + { + return kInfinity; + } + if (exponent < kDenormalExponent) + { + return 0; + } + while (exponent > kDenormalExponent && (significand & kHiddenBit) == 0) + { + significand <<= 1; + exponent--; + } + ulong biased_exponent; + if (exponent == kDenormalExponent && (significand & kHiddenBit) == 0) + { + biased_exponent = 0; + } + else + { + biased_exponent = (ulong)(exponent + kExponentBias); + } + return (significand & kSignificandMask) | + (biased_exponent << kPhysicalSignificandSize); + } + } + + internal struct Single + { + const int kExponentBias = 0x7F + kPhysicalSignificandSize; + const int kDenormalExponent = -kExponentBias + 1; + const int kMaxExponent = 0xFF - kExponentBias; + const uint32_t kInfinity = 0x7F800000; + const uint32_t kNaN = 0x7FC00000; + + public const uint32_t kSignMask = 0x80000000; + public const uint32_t kExponentMask = 0x7F800000; + public const uint32_t kSignificandMask = 0x007FFFFF; + public const uint32_t kHiddenBit = 0x00800000; + public const int kPhysicalSignificandSize = 23; // Excludes the hidden bit. + public const int kSignificandSize = 24; + + uint32_t d32_; + + public Single(float f) + { + this.d32_ = new UnionFloatUInt { f = f }.u32; + } + + // The value encoded by this Single must be greater or equal to +0.0. + // It must not be special (infinity, or NaN). + public DiyFp AsDiyFp() + { + return new DiyFp(Significand(), Exponent()); + } + + // Returns the single's bit as uint64. + public uint32_t AsUint32() + { + return d32_; + } + + public int Exponent() + { + if (IsDenormal()) return kDenormalExponent; + + uint32_t d32 = AsUint32(); + int biased_e = (int)((d32 & kExponentMask) >> kPhysicalSignificandSize); + return biased_e - kExponentBias; + } + + public uint32_t Significand() + { + uint32_t d32 = AsUint32(); + uint32_t significand = d32 & kSignificandMask; + if (!IsDenormal()) + { + return significand + kHiddenBit; + } + else + { + return significand; + } + } + + // Returns true if the single is a denormal. + public bool IsDenormal() + { + uint32_t d32 = AsUint32(); + return (d32 & kExponentMask) == 0; + } + + // We consider denormals not to be special. + // Hence only Infinity and NaN are special. + public bool IsSpecial() + { + uint32_t d32 = AsUint32(); + return (d32 & kExponentMask) == kExponentMask; + } + + public bool IsNan() + { + uint32_t d32 = AsUint32(); + return ((d32 & kExponentMask) == kExponentMask) && + ((d32 & kSignificandMask) != 0); + } + + public bool IsInfinite() + { + uint32_t d32 = AsUint32(); + return ((d32 & kExponentMask) == kExponentMask) && + ((d32 & kSignificandMask) == 0); + } + + public int Sign() + { + uint32_t d32 = AsUint32(); + return (d32 & kSignMask) == 0 ? 1 : -1; + } + + // Computes the two boundaries of this. + // The bigger boundary (m_plus) is normalized. The lower boundary has the same + // exponent as m_plus. + // Precondition: the value encoded by this Single must be greater than 0. + public void NormalizedBoundaries(out DiyFp out_m_minus, out DiyFp out_m_plus) + { + DiyFp v = this.AsDiyFp(); + var __ = new DiyFp((v.f << 1) + 1, v.e - 1); + DiyFp m_plus = DiyFp.Normalize(ref __); + DiyFp m_minus; + if (LowerBoundaryIsCloser()) + { + m_minus = new DiyFp((v.f << 2) - 1, v.e - 2); + } + else + { + m_minus = new DiyFp((v.f << 1) - 1, v.e - 1); + } + m_minus.f = (m_minus.f << (m_minus.e - m_plus.e)); + m_minus.e = (m_plus.e); + out_m_plus = m_plus; + out_m_minus = m_minus; + } + + // Precondition: the value encoded by this Single must be greater or equal + // than +0.0. + public DiyFp UpperBoundary() + { + return new DiyFp(Significand() * 2 + 1, Exponent() - 1); + } + + public bool LowerBoundaryIsCloser() + { + // The boundary is closer if the significand is of the form f == 2^p-1 then + // the lower boundary is closer. + // Think of v = 1000e10 and v- = 9999e9. + // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but + // at a distance of 1e8. + // The only exception is for the smallest normal: the largest denormal is + // at the same distance as its successor. + // Note: denormals have the same exponent as the smallest normals. + bool physical_significand_is_zero = ((AsUint32() & kSignificandMask) == 0); + return physical_significand_is_zero && (Exponent() != kDenormalExponent); + } + + public float value() { return new UnionFloatUInt { u32 = d32_ }.f; } + + public static float Infinity() + { + return new Single(kInfinity).value(); + } + + public static float NaN() + { + return new Single(kNaN).value(); + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/PowersOfTenCache.cs b/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/PowersOfTenCache.cs new file mode 100644 index 0000000..e7e5265 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/PowersOfTenCache.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Utf8Json.Internal.DoubleConversion +{ + using uint64_t = UInt64; + using int16_t = Int16; + + // https://github.com/google/double-conversion/blob/master/double-conversion/cached-powers.h + // https://github.com/google/double-conversion/blob/master/double-conversion/cached-powers.cc + + internal struct CachedPower + { + public readonly uint64_t significand; + public readonly int16_t binary_exponent; + public readonly int16_t decimal_exponent; + + public CachedPower(ulong significand, short binary_exponent, short decimal_exponent) + { + this.significand = significand; + this.binary_exponent = binary_exponent; + this.decimal_exponent = decimal_exponent; + } + }; + + internal static class PowersOfTenCache + { + static readonly CachedPower[] kCachedPowers = new CachedPower[] + { + new CachedPower (0xfa8fd5a0081c0288, -1220, -348), + new CachedPower (0xbaaee17fa23ebf76, -1193, -340), + new CachedPower (0x8b16fb203055ac76, -1166, -332), + new CachedPower (0xcf42894a5dce35ea, -1140, -324), + new CachedPower (0x9a6bb0aa55653b2d, -1113, -316), + new CachedPower (0xe61acf033d1a45df, -1087, -308), + new CachedPower (0xab70fe17c79ac6ca, -1060, -300), + new CachedPower (0xff77b1fcbebcdc4f, -1034, -292), + new CachedPower (0xbe5691ef416bd60c, -1007, -284), + new CachedPower (0x8dd01fad907ffc3c, -980, -276), + new CachedPower (0xd3515c2831559a83, -954, -268), + new CachedPower (0x9d71ac8fada6c9b5, -927, -260), + new CachedPower (0xea9c227723ee8bcb, -901, -252), + new CachedPower (0xaecc49914078536d, -874, -244), + new CachedPower (0x823c12795db6ce57, -847, -236), + new CachedPower (0xc21094364dfb5637, -821, -228), + new CachedPower (0x9096ea6f3848984f, -794, -220), + new CachedPower (0xd77485cb25823ac7, -768, -212), + new CachedPower (0xa086cfcd97bf97f4, -741, -204), + new CachedPower (0xef340a98172aace5, -715, -196), + new CachedPower (0xb23867fb2a35b28e, -688, -188), + new CachedPower (0x84c8d4dfd2c63f3b, -661, -180), + new CachedPower (0xc5dd44271ad3cdba, -635, -172), + new CachedPower (0x936b9fcebb25c996, -608, -164), + new CachedPower (0xdbac6c247d62a584, -582, -156), + new CachedPower (0xa3ab66580d5fdaf6, -555, -148), + new CachedPower (0xf3e2f893dec3f126, -529, -140), + new CachedPower (0xb5b5ada8aaff80b8, -502, -132), + new CachedPower (0x87625f056c7c4a8b, -475, -124), + new CachedPower (0xc9bcff6034c13053, -449, -116), + new CachedPower (0x964e858c91ba2655, -422, -108), + new CachedPower (0xdff9772470297ebd, -396, -100), + new CachedPower (0xa6dfbd9fb8e5b88f, -369, -92), + new CachedPower (0xf8a95fcf88747d94, -343, -84), + new CachedPower (0xb94470938fa89bcf, -316, -76), + new CachedPower (0x8a08f0f8bf0f156b, -289, -68), + new CachedPower (0xcdb02555653131b6, -263, -60), + new CachedPower (0x993fe2c6d07b7fac, -236, -52), + new CachedPower (0xe45c10c42a2b3b06, -210, -44), + new CachedPower (0xaa242499697392d3, -183, -36), + new CachedPower (0xfd87b5f28300ca0e, -157, -28), + new CachedPower (0xbce5086492111aeb, -130, -20), + new CachedPower (0x8cbccc096f5088cc, -103, -12), + new CachedPower (0xd1b71758e219652c, -77, -4), + new CachedPower (0x9c40000000000000, -50, 4), + new CachedPower (0xe8d4a51000000000, -24, 12), + new CachedPower (0xad78ebc5ac620000, 3, 20), + new CachedPower (0x813f3978f8940984, 30, 28), + new CachedPower (0xc097ce7bc90715b3, 56, 36), + new CachedPower (0x8f7e32ce7bea5c70, 83, 44), + new CachedPower (0xd5d238a4abe98068, 109, 52), + new CachedPower (0x9f4f2726179a2245, 136, 60), + new CachedPower (0xed63a231d4c4fb27, 162, 68), + new CachedPower (0xb0de65388cc8ada8, 189, 76), + new CachedPower (0x83c7088e1aab65db, 216, 84), + new CachedPower (0xc45d1df942711d9a, 242, 92), + new CachedPower (0x924d692ca61be758, 269, 100), + new CachedPower (0xda01ee641a708dea, 295, 108), + new CachedPower (0xa26da3999aef774a, 322, 116), + new CachedPower (0xf209787bb47d6b85, 348, 124), + new CachedPower (0xb454e4a179dd1877, 375, 132), + new CachedPower (0x865b86925b9bc5c2, 402, 140), + new CachedPower (0xc83553c5c8965d3d, 428, 148), + new CachedPower (0x952ab45cfa97a0b3, 455, 156), + new CachedPower (0xde469fbd99a05fe3, 481, 164), + new CachedPower (0xa59bc234db398c25, 508, 172), + new CachedPower (0xf6c69a72a3989f5c, 534, 180), + new CachedPower (0xb7dcbf5354e9bece, 561, 188), + new CachedPower (0x88fcf317f22241e2, 588, 196), + new CachedPower (0xcc20ce9bd35c78a5, 614, 204), + new CachedPower (0x98165af37b2153df, 641, 212), + new CachedPower (0xe2a0b5dc971f303a, 667, 220), + new CachedPower (0xa8d9d1535ce3b396, 694, 228), + new CachedPower (0xfb9b7cd9a4a7443c, 720, 236), + new CachedPower (0xbb764c4ca7a44410, 747, 244), + new CachedPower (0x8bab8eefb6409c1a, 774, 252), + new CachedPower (0xd01fef10a657842c, 800, 260), + new CachedPower (0x9b10a4e5e9913129, 827, 268), + new CachedPower (0xe7109bfba19c0c9d, 853, 276), + new CachedPower (0xac2820d9623bf429, 880, 284), + new CachedPower (0x80444b5e7aa7cf85, 907, 292), + new CachedPower (0xbf21e44003acdd2d, 933, 300), + new CachedPower (0x8e679c2f5e44ff8f, 960, 308), + new CachedPower (0xd433179d9c8cb841, 986, 316), + new CachedPower (0x9e19db92b4e31ba9, 1013, 324), + new CachedPower (0xeb96bf6ebadf77d9, 1039, 332), + new CachedPower (0xaf87023b9bf0ee6b, 1066, 340), + }; + + public const int kCachedPowersOffset = 348; // -1 * the first decimal_exponent. + public const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10) + // Difference between the decimal exponents in the table above. + public const int kDecimalExponentDistance = 8; + public const int kMinDecimalExponent = -348; + public const int kMaxDecimalExponent = 340; + + public static void GetCachedPowerForBinaryExponentRange( + int min_exponent, + int max_exponent, + out DiyFp power, + out int decimal_exponent) + { + int kQ = DiyFp.kSignificandSize; + double k = Math.Ceiling((min_exponent + kQ - 1) * kD_1_LOG2_10); + int foo = kCachedPowersOffset; + int index = (foo + (int)(k) - 1) / kDecimalExponentDistance + 1; + + CachedPower cached_power = kCachedPowers[index]; + // (void)max_exponent; // Mark variable as used. + decimal_exponent = cached_power.decimal_exponent; + power = new DiyFp(cached_power.significand, cached_power.binary_exponent); + } + + public static void GetCachedPowerForDecimalExponent(int requested_exponent, + out DiyFp power, + out int found_exponent) + { + int index = (requested_exponent + kCachedPowersOffset) / kDecimalExponentDistance; + CachedPower cached_power = kCachedPowers[index]; + power = new DiyFp(cached_power.significand, cached_power.binary_exponent); + found_exponent = cached_power.decimal_exponent; + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/StringToDouble.cs b/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/StringToDouble.cs new file mode 100644 index 0000000..0dc2275 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/StringToDouble.cs @@ -0,0 +1,535 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Utf8Json.Internal.DoubleConversion +{ + using uint64_t = UInt64; + + internal struct Vector + { + public readonly byte[] bytes; + public readonly int start; + public readonly int _length; + + public Vector(byte[] bytes, int start, int length) + { + this.bytes = bytes; + this.start = start; + this._length = length; + } + + public byte this[int i] + { + get + { + return bytes[start + i]; + } + set + { + bytes[start + i] = value; + } + } + + public int length() + { + return _length; + } + + public byte first() + { + return bytes[start]; + } + + public byte last() + { + return bytes[_length - 1]; + } + + public bool is_empty() + { + return _length == 0; + } + + public Vector SubVector(int from, int to) + { + return new Vector(this.bytes, start + from, to - from); + } + } + + internal static class StringToDouble + { + [ThreadStatic] + static byte[] copyBuffer; + + static byte[] GetCopyBuffer() + { + if (copyBuffer == null) + { + copyBuffer = new byte[kMaxSignificantDecimalDigits]; + } + return copyBuffer; + } + + // 2^53 = 9007199254740992. + // Any integer with at most 15 decimal digits will hence fit into a double + // (which has a 53bit significand) without loss of precision. + const int kMaxExactDoubleIntegerDecimalDigits = 15; + // 2^64 = 18446744073709551616 > 10^19 + const int kMaxUint64DecimalDigits = 19; + + // Max double: 1.7976931348623157 x 10^308 + // Min non-zero double: 4.9406564584124654 x 10^-324 + // Any x >= 10^309 is interpreted as +infinity. + // Any x <= 10^-324 is interpreted as 0. + // Note that 2.5e-324 (despite being smaller than the min double) will be read + // as non-zero (equal to the min non-zero double). + const int kMaxDecimalPower = 309; + const int kMinDecimalPower = -324; + + // 2^64 = 18446744073709551616 + const uint64_t kMaxUint64 = 0xFFFFFFFFFFFFFFFF; + + static readonly double[] exact_powers_of_ten = new double[]{ + 1.0, // 10^0 + 10.0, + 100.0, + 1000.0, + 10000.0, + 100000.0, + 1000000.0, + 10000000.0, + 100000000.0, + 1000000000.0, + 10000000000.0, // 10^10 + 100000000000.0, + 1000000000000.0, + 10000000000000.0, + 100000000000000.0, + 1000000000000000.0, + 10000000000000000.0, + 100000000000000000.0, + 1000000000000000000.0, + 10000000000000000000.0, + 100000000000000000000.0, // 10^20 + 1000000000000000000000.0, + // 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22 + 10000000000000000000000.0 + }; + static readonly int kExactPowersOfTenSize = exact_powers_of_ten.Length; + + // Maximum number of significant digits in the decimal representation. + // In fact the value is 772 (see conversions.cc), but to give us some margin + // we round up to 780. + const int kMaxSignificantDecimalDigits = 780; + + static Vector TrimLeadingZeros(Vector buffer) + { + for (int i = 0; i < buffer.length(); i++) + { + if (buffer[i] != '0') + { + return buffer.SubVector(i, buffer.length()); + } + } + return new Vector(buffer.bytes, buffer.start, 0); + } + + static Vector TrimTrailingZeros(Vector buffer) + { + for (int i = buffer.length() - 1; i >= 0; --i) + { + if (buffer[i] != '0') + { + return buffer.SubVector(0, i + 1); + } + } + return new Vector(buffer.bytes, buffer.start, 0); + } + + + static void CutToMaxSignificantDigits(Vector buffer, + int exponent, + byte[] significant_buffer, + out int significant_exponent) + { + for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) + { + significant_buffer[i] = buffer[i]; + } + // The input buffer has been trimmed. Therefore the last digit must be + // different from '0'. + // ASSERT(buffer[buffer.length() - 1] != '0'); + // Set the last digit to be non-zero. This is sufficient to guarantee + // correct rounding. + significant_buffer[kMaxSignificantDecimalDigits - 1] = (byte)'1'; + significant_exponent = exponent + (buffer.length() - kMaxSignificantDecimalDigits); + } + + // Trims the buffer and cuts it to at most kMaxSignificantDecimalDigits. + // If possible the input-buffer is reused, but if the buffer needs to be + // modified (due to cutting), then the input needs to be copied into the + // buffer_copy_space. + static void TrimAndCut(Vector buffer, int exponent, + byte[] buffer_copy_space, int space_size, + out Vector trimmed, out int updated_exponent) + { + Vector left_trimmed = TrimLeadingZeros(buffer); + Vector right_trimmed = TrimTrailingZeros(left_trimmed); + exponent += left_trimmed.length() - right_trimmed.length(); + if (right_trimmed.length() > kMaxSignificantDecimalDigits) + { + // (void)space_size; // Mark variable as used. + CutToMaxSignificantDigits(right_trimmed, exponent, + buffer_copy_space, out updated_exponent); + trimmed = new Vector(buffer_copy_space, 0, kMaxSignificantDecimalDigits); + } + else + { + trimmed = right_trimmed; + updated_exponent = exponent; + } + } + + + // Reads digits from the buffer and converts them to a uint64. + // Reads in as many digits as fit into a uint64. + // When the string starts with "1844674407370955161" no further digit is read. + // Since 2^64 = 18446744073709551616 it would still be possible read another + // digit if it was less or equal than 6, but this would complicate the code. + static uint64_t ReadUint64(Vector buffer, + out int number_of_read_digits) + { + uint64_t result = 0; + int i = 0; + while (i < buffer.length() && result <= (kMaxUint64 / 10 - 1)) + { + int digit = buffer[i++] - '0'; + result = 10 * result + (ulong)digit; + } + number_of_read_digits = i; + return result; + } + + // Reads a DiyFp from the buffer. + // The returned DiyFp is not necessarily normalized. + // If remaining_decimals is zero then the returned DiyFp is accurate. + // Otherwise it has been rounded and has error of at most 1/2 ulp. + static void ReadDiyFp(Vector buffer, + out DiyFp result, + out int remaining_decimals) + { + int read_digits; + uint64_t significand = ReadUint64(buffer, out read_digits); + if (buffer.length() == read_digits) + { + result = new DiyFp(significand, 0); + remaining_decimals = 0; + } + else + { + // Round the significand. + if (buffer[read_digits] >= '5') + { + significand++; + } + // Compute the binary exponent. + int exponent = 0; + result = new DiyFp(significand, exponent); + remaining_decimals = buffer.length() - read_digits; + } + } + + + static bool DoubleStrtod(Vector trimmed, + int exponent, + out double result) + { + if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) + { + int read_digits; + // The trimmed input fits into a double. + // If the 10^exponent (resp. 10^-exponent) fits into a double too then we + // can compute the result-double simply by multiplying (resp. dividing) the + // two numbers. + // This is possible because IEEE guarantees that floating-point operations + // return the best possible approximation. + if (exponent < 0 && -exponent < kExactPowersOfTenSize) + { + // 10^-exponent fits into a double. + result = unchecked((double)(ReadUint64(trimmed, out read_digits))); + result /= exact_powers_of_ten[-exponent]; + return true; + } + if (0 <= exponent && exponent < kExactPowersOfTenSize) + { + // 10^exponent fits into a double. + result = unchecked((double)(ReadUint64(trimmed, out read_digits))); + result *= exact_powers_of_ten[exponent]; + return true; + } + int remaining_digits = + kMaxExactDoubleIntegerDecimalDigits - trimmed.length(); + if ((0 <= exponent) && + (exponent - remaining_digits < kExactPowersOfTenSize)) + { + // The trimmed string was short and we can multiply it with + // 10^remaining_digits. As a result the remaining exponent now fits + // into a double too. + result = unchecked((double)(ReadUint64(trimmed, out read_digits))); + result *= exact_powers_of_ten[remaining_digits]; + result *= exact_powers_of_ten[exponent - remaining_digits]; + return true; + } + } + result = 0; + return false; + } + + + // Returns 10^exponent as an exact DiyFp. + // The given exponent must be in the range [1; kDecimalExponentDistance[. + static DiyFp AdjustmentPowerOfTen(int exponent) + { + // Simply hardcode the remaining powers for the given decimal exponent + // distance. + switch (exponent) + { + case 1: return new DiyFp(0xa000000000000000, -60); + case 2: return new DiyFp(0xc800000000000000, -57); + case 3: return new DiyFp(0xfa00000000000000, -54); + case 4: return new DiyFp(0x9c40000000000000, -50); + case 5: return new DiyFp(0xc350000000000000, -47); + case 6: return new DiyFp(0xf424000000000000, -44); + case 7: return new DiyFp(0x9896800000000000, -40); + default: + throw new Exception("unreached code."); + } + } + + // If the function returns true then the result is the correct double. + // Otherwise it is either the correct double or the double that is just below + // the correct double. + static bool DiyFpStrtod(Vector buffer, + int exponent, + out double result) + { + DiyFp input; + int remaining_decimals; + ReadDiyFp(buffer, out input, out remaining_decimals); + // Since we may have dropped some digits the input is not accurate. + // If remaining_decimals is different than 0 than the error is at most + // .5 ulp (unit in the last place). + // We don't want to deal with fractions and therefore keep a common + // denominator. + const int kDenominatorLog = 3; + const int kDenominator = 1 << kDenominatorLog; + // Move the remaining decimals into the exponent. + exponent += remaining_decimals; + uint64_t error = (ulong)(remaining_decimals == 0 ? 0 : kDenominator / 2); + + int old_e = input.e; + input.Normalize(); + error <<= old_e - input.e; + + if (exponent < PowersOfTenCache.kMinDecimalExponent) + { + result = 0.0; + return true; + } + DiyFp cached_power; + int cached_decimal_exponent; + PowersOfTenCache.GetCachedPowerForDecimalExponent(exponent, + out cached_power, + out cached_decimal_exponent); + + if (cached_decimal_exponent != exponent) + { + int adjustment_exponent = exponent - cached_decimal_exponent; + DiyFp adjustment_power = AdjustmentPowerOfTen(adjustment_exponent); + input.Multiply(ref adjustment_power); + if (kMaxUint64DecimalDigits - buffer.length() >= adjustment_exponent) + { + // The product of input with the adjustment power fits into a 64 bit + // integer. + } + else + { + // The adjustment power is exact. There is hence only an error of 0.5. + error += kDenominator / 2; + } + } + + input.Multiply(ref cached_power); + // The error introduced by a multiplication of a*b equals + // error_a + error_b + error_a*error_b/2^64 + 0.5 + // Substituting a with 'input' and b with 'cached_power' we have + // error_b = 0.5 (all cached powers have an error of less than 0.5 ulp), + // error_ab = 0 or 1 / kDenominator > error_a*error_b/ 2^64 + int error_b = kDenominator / 2; + int error_ab = (error == 0 ? 0 : 1); // We round up to 1. + int fixed_error = kDenominator / 2; + error += (ulong)(error_b + error_ab + fixed_error); + + old_e = input.e; + input.Normalize(); + error <<= old_e - input.e; + + // See if the double's significand changes if we add/subtract the error. + int order_of_magnitude = DiyFp.kSignificandSize + input.e; + int effective_significand_size = Double.SignificandSizeForOrderOfMagnitude(order_of_magnitude); + int precision_digits_count = DiyFp.kSignificandSize - effective_significand_size; + if (precision_digits_count + kDenominatorLog >= DiyFp.kSignificandSize) + { + // This can only happen for very small denormals. In this case the + // half-way multiplied by the denominator exceeds the range of an uint64. + // Simply shift everything to the right. + int shift_amount = (precision_digits_count + kDenominatorLog) - + DiyFp.kSignificandSize + 1; + input.f = (input.f >> shift_amount); + input.e = (input.e + shift_amount); + // We add 1 for the lost precision of error, and kDenominator for + // the lost precision of input.f(). + error = (error >> shift_amount) + 1 + kDenominator; + precision_digits_count -= shift_amount; + } + // We use uint64_ts now. This only works if the DiyFp uses uint64_ts too. + uint64_t one64 = 1; + uint64_t precision_bits_mask = (one64 << precision_digits_count) - 1; + uint64_t precision_bits = input.f & precision_bits_mask; + uint64_t half_way = one64 << (precision_digits_count - 1); + precision_bits *= kDenominator; + half_way *= kDenominator; + DiyFp rounded_input = new DiyFp(input.f >> precision_digits_count, input.e + precision_digits_count); + if (precision_bits >= half_way + error) + { + rounded_input.f = (rounded_input.f + 1); + } + // If the last_bits are too close to the half-way case than we are too + // inaccurate and round down. In this case we return false so that we can + // fall back to a more precise algorithm. + + result = new Double(rounded_input).value(); + if (half_way - error < precision_bits && precision_bits < half_way + error) + { + // Too imprecise. The caller will have to fall back to a slower version. + // However the returned number is guaranteed to be either the correct + // double, or the next-lower double. + return false; + } + else + { + return true; + } + } + + // Returns true if the guess is the correct double. + // Returns false, when guess is either correct or the next-lower double. + static bool ComputeGuess(Vector trimmed, int exponent, + out double guess) + { + if (trimmed.length() == 0) + { + guess = 0.0; + return true; + } + if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) + { + guess = Double.Infinity(); + return true; + } + if (exponent + trimmed.length() <= kMinDecimalPower) + { + guess = 0.0; + return true; + } + + if (DoubleStrtod(trimmed, exponent, out guess) || + DiyFpStrtod(trimmed, exponent, out guess)) + { + return true; + } + if (guess == Double.Infinity()) + { + return true; + } + return false; + } + + public static double? Strtod(Vector buffer, int exponent) + { + byte[] copy_buffer = GetCopyBuffer(); + Vector trimmed; + int updated_exponent; + TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits, + out trimmed, out updated_exponent); + exponent = updated_exponent; + + double guess; + var is_correct = ComputeGuess(trimmed, exponent, out guess); + if (is_correct) return guess; + return null; + } + + public static float? Strtof(Vector buffer, int exponent) + { + byte[] copy_buffer = GetCopyBuffer(); + Vector trimmed; + int updated_exponent; + TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits, + out trimmed, out updated_exponent); + exponent = updated_exponent; + + double double_guess; + var is_correct = ComputeGuess(trimmed, exponent, out double_guess); + + float float_guess = (float)(double_guess); + if (float_guess == double_guess) + { + // This shortcut triggers for integer values. + return float_guess; + } + + // We must catch double-rounding. Say the double has been rounded up, and is + // now a boundary of a float, and rounds up again. This is why we have to + // look at previous too. + // Example (in decimal numbers): + // input: 12349 + // high-precision (4 digits): 1235 + // low-precision (3 digits): + // when read from input: 123 + // when rounded from high precision: 124. + // To do this we simply look at the neigbors of the correct result and see + // if they would round to the same float. If the guess is not correct we have + // to look at four values (since two different doubles could be the correct + // double). + + double double_next = new Double(double_guess).NextDouble(); + double double_previous = new Double(double_guess).PreviousDouble(); + + float f1 = (float)(double_previous); + // float f2 = float_guess; + float f3 = (float)(double_next); + float f4; + if (is_correct) + { + f4 = f3; + } + else + { + double double_next2 = new Double(double_next).NextDouble(); + f4 = (float)(double_next2); + } + // (void)f2; // Mark variable as used. + + // If the guess doesn't lie near a single-precision boundary we can simply + // return its float-value. + if (f1 == f4) + { + return float_guess; + } + + return null; + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/StringToDoubleConverter.cs b/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/StringToDoubleConverter.cs new file mode 100644 index 0000000..8227393 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/DoubleConversion/StringToDoubleConverter.cs @@ -0,0 +1,622 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Utf8Json.Internal.DoubleConversion +{ +#pragma warning disable 660 +#pragma warning disable 661 + + internal struct Iterator + { + byte[] buffer; + int offset; + + public Iterator(byte[] buffer, int offset) + { + this.buffer = buffer; + this.offset = offset; + } + + public byte Value + { + get + { + return buffer[offset]; + } + } + + public static Iterator operator ++(Iterator self) + { + self.offset++; + return self; + } + + public static Iterator operator +(Iterator self, int length) + { + return new Iterator { buffer = self.buffer, offset = self.offset + length }; + } + + public static int operator -(Iterator lhs, Iterator rhs) + { + return lhs.offset - rhs.offset; + } + + public static bool operator ==(Iterator lhs, Iterator rhs) + { + return lhs.offset == rhs.offset; + } + + public static bool operator !=(Iterator lhs, Iterator rhs) + { + return lhs.offset != rhs.offset; + } + + public static bool operator ==(Iterator lhs, char rhs) + { + return lhs.buffer[lhs.offset] == (byte)rhs; + } + + public static bool operator !=(Iterator lhs, char rhs) + { + return lhs.buffer[lhs.offset] != (byte)rhs; + } + + public static bool operator ==(Iterator lhs, byte rhs) + { + return lhs.buffer[lhs.offset] == (byte)rhs; + } + + public static bool operator !=(Iterator lhs, byte rhs) + { + return lhs.buffer[lhs.offset] != (byte)rhs; + } + + public static bool operator >=(Iterator lhs, char rhs) + { + return lhs.buffer[lhs.offset] >= (byte)rhs; + } + + public static bool operator <=(Iterator lhs, char rhs) + { + return lhs.buffer[lhs.offset] <= (byte)rhs; + } + + public static bool operator >(Iterator lhs, char rhs) + { + return lhs.buffer[lhs.offset] > (byte)rhs; + } + + public static bool operator <(Iterator lhs, char rhs) + { + return lhs.buffer[lhs.offset] < (byte)rhs; + } + } + +#pragma warning restore 661 +#pragma warning restore 660 + + // C# API + internal static partial class StringToDoubleConverter + { + [ThreadStatic] + static byte[] kBuffer; + + static byte[] GetBuffer() + { + if (kBuffer == null) + { + kBuffer = new byte[kBufferSize]; + } + return kBuffer; + } + + [ThreadStatic] + static byte[] fallbackBuffer; + + static byte[] GetFallbackBuffer() + { + if (fallbackBuffer == null) + { + fallbackBuffer = new byte[99]; + } + return fallbackBuffer; + } + + public static double ToDouble(byte[] buffer, int offset, out int readCount) + { + return StringToIeee(new Iterator(buffer, offset), buffer.Length - offset, true, out readCount); + } + + public static float ToSingle(byte[] buffer, int offset, out int readCount) + { + return unchecked((float)StringToIeee(new Iterator(buffer, offset), buffer.Length - offset, false, out readCount)); + } + } + + // port + internal static partial class StringToDoubleConverter + { + enum Flags + { + NO_FLAGS = 0, + ALLOW_HEX = 1, // defined but always disallow + ALLOW_OCTALS = 2, + ALLOW_TRAILING_JUNK = 4, + ALLOW_LEADING_SPACES = 8, + ALLOW_TRAILING_SPACES = 16, + ALLOW_SPACES_AFTER_SIGN = 32, + ALLOW_CASE_INSENSIBILITY = 64, // not supported + }; + + const Flags flags_ = Flags.ALLOW_TRAILING_JUNK | Flags.ALLOW_TRAILING_SPACES | Flags.ALLOW_SPACES_AFTER_SIGN; + const double empty_string_value_ = 0.0; + const double junk_string_value_ = double.NaN; + const int kMaxSignificantDigits = 772; + const int kBufferSize = kMaxSignificantDigits + 10; + static readonly byte[] infinity_symbol_ = StringEncoding.UTF8.GetBytes(double.PositiveInfinity.ToString()); + static readonly byte[] nan_symbol_ = StringEncoding.UTF8.GetBytes(double.NaN.ToString()); + + static readonly byte[] kWhitespaceTable7 = new byte[] { 32, 13, 10, 9, 11, 12 }; + static readonly int kWhitespaceTable7Length = kWhitespaceTable7.Length; + + static readonly UInt16[] kWhitespaceTable16 = new UInt16[]{ + 160, 8232, 8233, 5760, 6158, 8192, 8193, 8194, 8195, + 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8239, 8287, 12288, 65279 + }; + static readonly int kWhitespaceTable16Length = kWhitespaceTable16.Length; + + static bool isWhitespace(int x) + { + if (x < 128) + { + for (int i = 0; i < kWhitespaceTable7Length; i++) + { + if (kWhitespaceTable7[i] == x) return true; + } + } + else + { + for (int i = 0; i < kWhitespaceTable16Length; i++) + { + if (kWhitespaceTable16[i] == x) return true; + } + } + return false; + } + + static bool AdvanceToNonspace(ref Iterator current, Iterator end) + { + while (current != end) + { + if (!isWhitespace(current.Value)) return true; + current++; + } + return false; + } + + static bool ConsumeSubString(ref Iterator current, + Iterator end, + byte[] substring) + { + for (int i = 1; i < substring.Length; i++) + { + ++current; + if (current == end || current != substring[i]) + { + return false; + } + } + ++current; + return true; + } + + + // Consumes first character of the str is equal to ch + static bool ConsumeFirstCharacter(ref Iterator iter, + byte[] str, + int offset) + { + return iter.Value == str[offset]; + } + + static double SignedZero(bool sign) + { + return sign ? -0.0 : 0.0; + } + + static double StringToIeee( + Iterator input, + int length, + bool read_as_double, + out int processed_characters_count) + { + Iterator current = input; + Iterator end = input + length; + + processed_characters_count = 0; + + bool allow_trailing_junk = (flags_ & Flags.ALLOW_TRAILING_JUNK) != 0; + bool allow_leading_spaces = (flags_ & Flags.ALLOW_LEADING_SPACES) != 0; + bool allow_trailing_spaces = (flags_ & Flags.ALLOW_TRAILING_SPACES) != 0; + bool allow_spaces_after_sign = (flags_ & Flags.ALLOW_SPACES_AFTER_SIGN) != 0; + // bool allow_case_insensibility = (flags_ & Flags.ALLOW_CASE_INSENSIBILITY) != 0; + + // To make sure that iterator dereferencing is valid the following + // convention is used: + // 1. Each '++current' statement is followed by check for equality to 'end'. + // 2. If AdvanceToNonspace returned false then current == end. + // 3. If 'current' becomes equal to 'end' the function returns or goes to + // 'parsing_done'. + // 4. 'current' is not dereferenced after the 'parsing_done' label. + // 5. Code before 'parsing_done' may rely on 'current != end'. + if (length == 0) return empty_string_value_; + + if (allow_leading_spaces || allow_trailing_spaces) + { + if (!AdvanceToNonspace(ref current, end)) + { + processed_characters_count = (int)(current - input); + return empty_string_value_; + } + if (!allow_leading_spaces && (input != current)) + { + // No leading spaces allowed, but AdvanceToNonspace moved forward. + return junk_string_value_; + } + } + + // The longest form of simplified number is: "-.1eXXX\0". + byte[] buffer = GetBuffer(); // NOLINT: size is known at compile time. + int buffer_pos = 0; + + // Exponent will be adjusted if insignificant digits of the integer part + // or insignificant leading zeros of the fractional part are dropped. + int exponent = 0; + int significant_digits = 0; + int insignificant_digits = 0; + bool nonzero_digit_dropped = false; + + bool sign = false; + + if (current == '+' || current == '-') + { + sign = (current == '-'); + current++; + Iterator next_non_space = current; + // Skip following spaces (if allowed). + if (!AdvanceToNonspace(ref next_non_space, end)) return junk_string_value_; + if (!allow_spaces_after_sign && (current != next_non_space)) + { + return junk_string_value_; + } + current = next_non_space; + } + + if (infinity_symbol_ != null) + { + if (ConsumeFirstCharacter(ref current, infinity_symbol_, 0)) + { + if (!ConsumeSubString(ref current, end, infinity_symbol_)) + { + return junk_string_value_; + } + + if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) + { + return junk_string_value_; + } + if (!allow_trailing_junk && AdvanceToNonspace(ref current, end)) + { + return junk_string_value_; + } + + processed_characters_count = (current - input); + return sign ? double.NegativeInfinity : double.PositiveInfinity; + } + } + + if (nan_symbol_ != null) + { + if (ConsumeFirstCharacter(ref current, nan_symbol_, 0)) + { + if (!ConsumeSubString(ref current, end, nan_symbol_)) + { + return junk_string_value_; + } + + if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) + { + return junk_string_value_; + } + if (!allow_trailing_junk && AdvanceToNonspace(ref current, end)) + { + return junk_string_value_; + } + + processed_characters_count = (current - input); + return sign ? -double.NaN : double.NaN; + } + } + + bool leading_zero = false; + if (current == '0') + { + current++; + if (current == end) + { + processed_characters_count = (current - input); + return SignedZero(sign); + } + + leading_zero = true; + + // It could be hexadecimal value. + //if ((flags_ & ALLOW_HEX) && (*current == 'x' || *current == 'X')) + //{ + // ++current; + // if (current == end || !isDigit(*current, 16)) + // { + // return junk_string_value_; // "0x". + // } + + // bool result_is_junk; + // double result = RadixStringToIeee < 4 > (¤t, + // end, + // sign, + // allow_trailing_junk, + // junk_string_value_, + // read_as_double, + // &result_is_junk); + // if (!result_is_junk) + // { + // if (allow_trailing_spaces) AdvanceToNonspace(¤t, end); + // *processed_characters_count = static_cast(current - input); + // } + // return result; + //} + + // Ignore leading zeros in the integer part. + while (current == '0') + { + current++; + if (current == end) + { + processed_characters_count = (current - input); + return SignedZero(sign); + } + } + } + + bool octal = leading_zero && (flags_ & Flags.ALLOW_OCTALS) != 0; + + // Copy significant digits of the integer part (if any) to the buffer. + while (current >= '0' && current <= '9') + { + if (significant_digits < kMaxSignificantDigits) + { + buffer[buffer_pos++] = (current.Value); + significant_digits++; + // Will later check if it's an octal in the buffer. + } + else + { + insignificant_digits++; // Move the digit into the exponential part. + nonzero_digit_dropped = nonzero_digit_dropped || current != '0'; + } + // octal = octal && *current < '8'; + current++; + if (current == end) goto parsing_done; + } + + if (significant_digits == 0) + { + octal = false; + } + + if (current == '.') + { + if (octal && !allow_trailing_junk) return junk_string_value_; + if (octal) goto parsing_done; + + current++; + if (current == end) + { + if (significant_digits == 0 && !leading_zero) + { + return junk_string_value_; + } + else + { + goto parsing_done; + } + } + + if (significant_digits == 0) + { + // octal = false; + // Integer part consists of 0 or is absent. Significant digits start after + // leading zeros (if any). + while (current == '0') + { + ++current; + if (current == end) + { + processed_characters_count = (current - input); + return SignedZero(sign); + } + exponent--; // Move this 0 into the exponent. + } + } + + // There is a fractional part. + // We don't emit a '.', but adjust the exponent instead. + while (current >= '0' && current <= '9') + { + if (significant_digits < kMaxSignificantDigits) + { + buffer[buffer_pos++] = current.Value; + significant_digits++; + exponent--; + } + else + { + // Ignore insignificant digits in the fractional part. + nonzero_digit_dropped = nonzero_digit_dropped || current != '0'; + } + ++current; + if (current == end) goto parsing_done; + } + } + + if (!leading_zero && exponent == 0 && significant_digits == 0) + { + // If leading_zeros is true then the string contains zeros. + // If exponent < 0 then string was [+-]\.0*... + // If significant_digits != 0 the string is not equal to 0. + // Otherwise there are no digits in the string. + return junk_string_value_; + } + + // Parse exponential part. + if (current == 'e' || current == 'E') + { + if (octal && !allow_trailing_junk) return junk_string_value_; + if (octal) goto parsing_done; + ++current; + if (current == end) + { + if (allow_trailing_junk) + { + goto parsing_done; + } + else + { + return junk_string_value_; + } + } + byte exponen_sign = (byte)'+'; + if (current == '+' || current == '-') + { + exponen_sign = current.Value; + ++current; + if (current == end) + { + if (allow_trailing_junk) + { + goto parsing_done; + } + else + { + return junk_string_value_; + } + } + } + + if (current == end || current < '0' || current > '9') + { + if (allow_trailing_junk) + { + goto parsing_done; + } + else + { + return junk_string_value_; + } + } + + const int max_exponent = int.MaxValue / 2; + + int num = 0; + do + { + // Check overflow. + int digit = current.Value - (byte)'0'; + if (num >= max_exponent / 10 + && !(num == max_exponent / 10 && digit <= max_exponent % 10)) + { + num = max_exponent; + } + else + { + num = num * 10 + digit; + } + ++current; + } while (current != end && current >= '0' && current <= '9'); + + exponent += (exponen_sign == '-' ? -num : num); + } + + if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) + { + return junk_string_value_; + } + if (!allow_trailing_junk && AdvanceToNonspace(ref current, end)) + { + return junk_string_value_; + } + if (allow_trailing_spaces) + { + AdvanceToNonspace(ref current, end); + } + + parsing_done: + exponent += insignificant_digits; + + //if (octal) + //{ + // double result; + // bool result_is_junk; + // char* start = buffer; + // result = RadixStringToIeee < 3 > (&start, + // buffer + buffer_pos, + // sign, + // allow_trailing_junk, + // junk_string_value_, + // read_as_double, + // &result_is_junk); + // ASSERT(!result_is_junk); + // *processed_characters_count = static_cast(current - input); + // return result; + //} + + if (nonzero_digit_dropped) + { + buffer[buffer_pos++] = (byte)'1'; + exponent--; + } + + buffer[buffer_pos] = (byte)'\0'; + + double? converted; + if (read_as_double) + { + converted = StringToDouble.Strtod(new Vector(buffer, 0, buffer_pos), exponent); + } + else + { + converted = StringToDouble.Strtof(new Vector(buffer, 0, buffer_pos), exponent); + } + + if (converted == null) + { + // read-again + processed_characters_count = (current - input); + + var fallbackbuffer = GetFallbackBuffer(); + BinaryUtil.EnsureCapacity(ref fallbackBuffer, 0, processed_characters_count); + var fallbackI = 0; + while (input != current) + { + fallbackbuffer[fallbackI++] = input.Value; + input++; + } + var laststr = Encoding.UTF8.GetString(fallbackbuffer, 0, fallbackI); + return double.Parse(laststr); + } + + processed_characters_count = (current - input); + return sign ? -converted.Value : converted.Value; + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Internal/Emit/DynamicAssembly.cs b/Unity3D/3rdLib/Utf8Json/Internal/Emit/DynamicAssembly.cs new file mode 100644 index 0000000..544d2a3 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/Emit/DynamicAssembly.cs @@ -0,0 +1,73 @@ +using System; +using System.Reflection; +using System.Reflection.Emit; + +namespace Utf8Json.Internal.Emit +{ + internal class DynamicAssembly + { +#if NET45 || NET47 + readonly string moduleName; +#endif + readonly AssemblyBuilder assemblyBuilder; + readonly ModuleBuilder moduleBuilder; + + // don't expose ModuleBuilder + // public ModuleBuilder ModuleBuilder { get { return moduleBuilder; } } + + readonly object gate = new object(); + + // requires lock on mono environment. see: https://github.com/neuecc/MessagePack-CSharp/issues/161 + + public TypeBuilder DefineType(string name, TypeAttributes attr) + { + lock (gate) + { + return moduleBuilder.DefineType(name, attr); + } + } + + public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent) + { + lock (gate) + { + return moduleBuilder.DefineType(name, attr, parent); + } + } + + public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, Type[] interfaces) + { + lock (gate) + { + return moduleBuilder.DefineType(name, attr, parent, interfaces); + } + } + + public DynamicAssembly(string moduleName) + { +#if NET45 || NET47 + this.moduleName = moduleName; + this.assemblyBuilder = System.AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(moduleName), AssemblyBuilderAccess.RunAndSave); + this.moduleBuilder = assemblyBuilder.DefineDynamicModule(moduleName, moduleName + ".dll"); +#else +#if NETSTANDARD + this.assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(moduleName), AssemblyBuilderAccess.Run); +#else + this.assemblyBuilder = System.AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(moduleName), AssemblyBuilderAccess.Run); +#endif + + this.moduleBuilder = assemblyBuilder.DefineDynamicModule(moduleName); +#endif + } + +#if NET45 || NET47 + + public AssemblyBuilder Save() + { + assemblyBuilder.Save(moduleName + ".dll"); + return assemblyBuilder; + } + +#endif + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/Emit/DynamicAssembly.cs.meta b/Unity3D/3rdLib/Utf8Json/Internal/Emit/DynamicAssembly.cs.meta new file mode 100644 index 0000000..d140c04 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/Emit/DynamicAssembly.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ceeb852ee9ab4b0987d35cdb843fc82c +timeCreated: 1668660996 \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/Emit/ExpressionUtility.cs b/Unity3D/3rdLib/Utf8Json/Internal/Emit/ExpressionUtility.cs new file mode 100644 index 0000000..791b597 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/Emit/ExpressionUtility.cs @@ -0,0 +1,96 @@ +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace Utf8Json.Internal.Emit +{ + internal static class ExpressionUtility + { + // Method + + static MethodInfo GetMethodInfoCore(LambdaExpression expression) + { + if (expression == null) + { + throw new ArgumentNullException("expression"); + } + + return (expression.Body as MethodCallExpression).Method; + } + + /// + /// Get MethodInfo from Expression for Static(with result) method. + /// + public static MethodInfo GetMethodInfo(Expression> expression) + { + return GetMethodInfoCore(expression); + } + + /// + /// Get MethodInfo from Expression for Static(void) method. + /// + public static MethodInfo GetMethodInfo(Expression expression) + { + return GetMethodInfoCore(expression); + } + + /// + /// Get MethodInfo from Expression for Instance(with result) method. + /// + public static MethodInfo GetMethodInfo(Expression> expression) + { + return GetMethodInfoCore(expression); + } + + /// + /// Get MethodInfo from Expression for Instance(void) method. + /// + public static MethodInfo GetMethodInfo(Expression> expression) + { + return GetMethodInfoCore(expression); + } + + // WithArgument(for ref, out) helper + + /// + /// Get MethodInfo from Expression for Instance(void) method. + /// + public static MethodInfo GetMethodInfo(Expression> expression) + { + return GetMethodInfoCore(expression); + } + + /// + /// Get MethodInfo from Expression for Instance(with result) method. + /// + public static MethodInfo GetMethodInfo(Expression> expression) + { + return GetMethodInfoCore(expression); + } + + // Property + + static MemberInfo GetMemberInfoCore(Expression source) + { + if (source == null) + { + throw new ArgumentNullException("source"); + } + + var memberExpression = source.Body as MemberExpression; + return memberExpression.Member; + } + + public static PropertyInfo GetPropertyInfo(Expression> expression) + { + return GetMemberInfoCore(expression) as PropertyInfo; + } + + // Field + + public static FieldInfo GetFieldInfo(Expression> expression) + { + return GetMemberInfoCore(expression) as FieldInfo; + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Internal/Emit/ExpressionUtility.cs.meta b/Unity3D/3rdLib/Utf8Json/Internal/Emit/ExpressionUtility.cs.meta new file mode 100644 index 0000000..1f364a4 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/Emit/ExpressionUtility.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: deffd288f8df41ce97256a7240acd693 +timeCreated: 1668660996 \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/Emit/ILGeneratorExtensions.cs b/Unity3D/3rdLib/Utf8Json/Internal/Emit/ILGeneratorExtensions.cs new file mode 100644 index 0000000..a4b1379 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/Emit/ILGeneratorExtensions.cs @@ -0,0 +1,378 @@ +using System; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; + +namespace Utf8Json.Internal.Emit +{ + internal struct ArgumentField + { + readonly int i; + readonly bool @ref; + readonly ILGenerator il; + + public ArgumentField(ILGenerator il, int i, bool @ref = false) + { + this.il = il; + this.i = i; + this.@ref = @ref; + } + + public ArgumentField(ILGenerator il, int i, Type type) + { + this.il = il; + this.i = i; + this.@ref = (type.IsClass || type.IsInterface || type.IsAbstract) ? false : true; + } + + public void EmitLoad() + { + if (@ref) + { + il.EmitLdarga(i); + } + else + { + il.EmitLdarg(i); + } + } + + public void EmitStore() + { + il.EmitStarg(i); + } + } + + /// + /// Provides optimized generation code and helpers. + /// + internal static class ILGeneratorExtensions + { + /// + /// Loads the local variable at a specific index onto the evaluation stack. + /// + public static void EmitLdloc(this ILGenerator il, int index) + { + switch (index) + { + case 0: + il.Emit(OpCodes.Ldloc_0); + break; + case 1: + il.Emit(OpCodes.Ldloc_1); + break; + case 2: + il.Emit(OpCodes.Ldloc_2); + break; + case 3: + il.Emit(OpCodes.Ldloc_3); + break; + default: + if (index <= 255) + { + il.Emit(OpCodes.Ldloc_S, (byte)index); + } + else + { + il.Emit(OpCodes.Ldloc, (short)index); + } + break; + } + } + + public static void EmitLdloc(this ILGenerator il, LocalBuilder local) + { + EmitLdloc(il, local.LocalIndex); + } + + /// + /// Pops the current value from the top of the evaluation stack and stores it in a the local variable list at a specified index. + /// + public static void EmitStloc(this ILGenerator il, int index) + { + switch (index) + { + case 0: + il.Emit(OpCodes.Stloc_0); + break; + case 1: + il.Emit(OpCodes.Stloc_1); + break; + case 2: + il.Emit(OpCodes.Stloc_2); + break; + case 3: + il.Emit(OpCodes.Stloc_3); + break; + default: + if (index <= 255) + { + il.Emit(OpCodes.Stloc_S, (byte)index); + } + else + { + il.Emit(OpCodes.Stloc, (short)index); + } + break; + } + } + + public static void EmitStloc(this ILGenerator il, LocalBuilder local) + { + EmitStloc(il, local.LocalIndex); + } + + /// + /// Loads the address of the local variable at a specific index onto the evaluation statck. + /// + public static void EmitLdloca(this ILGenerator il, int index) + { + if (index <= 255) + { + il.Emit(OpCodes.Ldloca_S, (byte)index); + } + else + { + il.Emit(OpCodes.Ldloca, (short)index); + } + } + + public static void EmitLdloca(this ILGenerator il, LocalBuilder local) + { + EmitLdloca(il, local.LocalIndex); + } + + public static void EmitTrue(this ILGenerator il) + { + EmitBoolean(il, true); + } + + public static void EmitFalse(this ILGenerator il) + { + EmitBoolean(il, false); + } + + public static void EmitBoolean(this ILGenerator il, bool value) + { + EmitLdc_I4(il, value ? 1 : 0); + } + + /// + /// Pushes a supplied value of type int32 onto the evaluation stack as an int32. + /// + public static void EmitLdc_I4(this ILGenerator il, int value) + { + switch (value) + { + case -1: + il.Emit(OpCodes.Ldc_I4_M1); + break; + case 0: + il.Emit(OpCodes.Ldc_I4_0); + break; + case 1: + il.Emit(OpCodes.Ldc_I4_1); + break; + case 2: + il.Emit(OpCodes.Ldc_I4_2); + break; + case 3: + il.Emit(OpCodes.Ldc_I4_3); + break; + case 4: + il.Emit(OpCodes.Ldc_I4_4); + break; + case 5: + il.Emit(OpCodes.Ldc_I4_5); + break; + case 6: + il.Emit(OpCodes.Ldc_I4_6); + break; + case 7: + il.Emit(OpCodes.Ldc_I4_7); + break; + case 8: + il.Emit(OpCodes.Ldc_I4_8); + break; + default: + if (value >= -128 && value <= 127) + { + il.Emit(OpCodes.Ldc_I4_S, (sbyte)value); + } + else + { + il.Emit(OpCodes.Ldc_I4, value); + } + break; + } + } + + public static void EmitUnboxOrCast(this ILGenerator il, Type type) + { + if (type.IsValueType) + { + il.Emit(OpCodes.Unbox_Any, type); + } + else + { + il.Emit(OpCodes.Castclass, type); + } + } + + public static void EmitBoxOrDoNothing(this ILGenerator il, Type type) + { + if (type.IsValueType) + { + il.Emit(OpCodes.Box, type); + } + } + + public static void EmitLdarg(this ILGenerator il, int index) + { + switch (index) + { + case 0: + il.Emit(OpCodes.Ldarg_0); + break; + case 1: + il.Emit(OpCodes.Ldarg_1); + break; + case 2: + il.Emit(OpCodes.Ldarg_2); + break; + case 3: + il.Emit(OpCodes.Ldarg_3); + break; + default: + if (index <= 255) + { + il.Emit(OpCodes.Ldarg_S, (byte)index); + } + else + { + il.Emit(OpCodes.Ldarg, index); + } + break; + } + } + + public static void EmitLoadThis(this ILGenerator il) + { + EmitLdarg(il, 0); + } + + public static void EmitLdarga(this ILGenerator il, int index) + { + if (index <= 255) + { + il.Emit(OpCodes.Ldarga_S, (byte)index); + } + else + { + il.Emit(OpCodes.Ldarga, index); + } + } + + public static void EmitStarg(this ILGenerator il, int index) + { + if (index <= 255) + { + il.Emit(OpCodes.Starg_S, (byte)index); + } + else + { + il.Emit(OpCodes.Starg, index); + } + } + + /// + /// Helper for Pop op. + /// + public static void EmitPop(this ILGenerator il, int count) + { + for (int i = 0; i < count; i++) + { + il.Emit(OpCodes.Pop); + } + } + + public static void EmitCall(this ILGenerator il, MethodInfo methodInfo) + { + if (methodInfo.IsFinal || !methodInfo.IsVirtual) + { + il.Emit(OpCodes.Call, methodInfo); + } + else + { + il.Emit(OpCodes.Callvirt, methodInfo); + } + } + + public static void EmitLdfld(this ILGenerator il, FieldInfo fieldInfo) + { + il.Emit(OpCodes.Ldfld, fieldInfo); + } + + public static void EmitLdsfld(this ILGenerator il, FieldInfo fieldInfo) + { + il.Emit(OpCodes.Ldsfld, fieldInfo); + } + + public static void EmitRet(this ILGenerator il) + { + il.Emit(OpCodes.Ret); + } + + public static void EmitIntZeroReturn(this ILGenerator il) + { + il.EmitLdc_I4(0); + il.Emit(OpCodes.Ret); + } + + public static void EmitNullReturn(this ILGenerator il) + { + il.Emit(OpCodes.Ldnull); + il.Emit(OpCodes.Ret); + } + + public static void EmitULong(this ILGenerator il, ulong value) + { + il.Emit(OpCodes.Ldc_I8, unchecked((long)value)); + } + + public static void EmitThrowNotimplemented(this ILGenerator il) + { + il.Emit(OpCodes.Newobj, typeof(System.NotImplementedException).GetTypeInfo().DeclaredConstructors.First(x => x.GetParameters().Length == 0)); + il.Emit(OpCodes.Throw); + } + + /// for var i = 0, i ..., i++ + public static void EmitIncrementFor(this ILGenerator il, LocalBuilder conditionGreater, Action emitBody) + { + var loopBegin = il.DefineLabel(); + var condtionLabel = il.DefineLabel(); + + // var i = 0 + var forI = il.DeclareLocal(typeof(int)); + il.EmitLdc_I4(0); + il.EmitStloc(forI); + il.Emit(OpCodes.Br, condtionLabel); + + il.MarkLabel(loopBegin); + emitBody(forI); + + // i++ + il.EmitLdloc(forI); + il.EmitLdc_I4(1); + il.Emit(OpCodes.Add); + il.EmitStloc(forI); + + //// i < *** + il.MarkLabel(condtionLabel); + il.EmitLdloc(forI); + il.EmitLdloc(conditionGreater); + il.Emit(OpCodes.Blt, loopBegin); + } + } +} + diff --git a/Unity3D/3rdLib/Utf8Json/Internal/Emit/ILGeneratorExtensions.cs.meta b/Unity3D/3rdLib/Utf8Json/Internal/Emit/ILGeneratorExtensions.cs.meta new file mode 100644 index 0000000..92bca8b --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/Emit/ILGeneratorExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4ac272307d2b439e9ddb5b65f702eeac +timeCreated: 1668660996 \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/Emit/ILViewer.cs b/Unity3D/3rdLib/Utf8Json/Internal/Emit/ILViewer.cs new file mode 100644 index 0000000..9a95ac5 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/Emit/ILViewer.cs @@ -0,0 +1,270 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Reflection.Emit; +using System.Text; +using System.Text.RegularExpressions; + +namespace Utf8Json.Internal +{ + internal class ILStreamReader : BinaryReader + { + static readonly OpCode[] oneByteOpCodes = new OpCode[0x100]; + static readonly OpCode[] twoByteOpCodes = new OpCode[0x100]; + + int endPosition; + + public int CurrentPosition { get { return (int)BaseStream.Position; } } + + public bool EndOfStream { get { return !((int)BaseStream.Position < endPosition); } } + + static ILStreamReader() + { + foreach (var fi in typeof(OpCodes).GetFields(BindingFlags.Public | BindingFlags.Static)) + { + var opCode = (OpCode)fi.GetValue(null); + var value = unchecked((ushort)opCode.Value); + + if (value < 0x100) + { + oneByteOpCodes[value] = opCode; + } + else if ((value & 0xff00) == 0xfe00) + { + twoByteOpCodes[value & 0xff] = opCode; + } + } + } + + public ILStreamReader(byte[] ilByteArray) + : base(new MemoryStream(ilByteArray)) + { + this.endPosition = ilByteArray.Length; + } + + public OpCode ReadOpCode() + { + var code = ReadByte(); + if (code != 0xFE) + { + return oneByteOpCodes[code]; + } + else + { + code = ReadByte(); + return twoByteOpCodes[code]; + } + } + + public int ReadMetadataToken() + { + return ReadInt32(); + } + } + +#if DEBUG && NETSTANDARD + + // not yet completed so only for debug. + public static class ILViewer + { + public static string ToPrettyPrintInstruction(MethodBase method) + { + var sb = new StringBuilder(); + + foreach (var item in ToOpCodes(method)) + { + sb.AppendLine(item.ToString()); + } + + return sb.ToString(); + } + + public static IEnumerable ToOpCodes(MethodBase method) + { + var body = method.GetMethodBody(); + if (body == null) yield break; + + var il = body.GetILAsByteArray(); + + using (var reader = new ILStreamReader(il)) + { + while (!reader.EndOfStream) + { + + object data = null; + var position = reader.CurrentPosition; + + var opCode = reader.ReadOpCode(); + switch (opCode.OperandType) + { + case OperandType.ShortInlineI: + data = reader.ReadByte(); + break; + case OperandType.ShortInlineBrTarget: + case OperandType.ShortInlineVar: + // data = + reader.ReadByte(); + break; + case OperandType.InlineVar: + reader.ReadUInt16(); + break; + case OperandType.InlineSig: + case OperandType.InlineType: + reader.ReadUInt32(); + break; + case OperandType.InlineNone: + break; + case OperandType.InlineBrTarget: + // data = + reader.ReadUInt32(); + break; + case OperandType.InlineSwitch: + { + var count = reader.ReadUInt32(); + for (int i = 0; i < count; i++) + { + // data =... + reader.ReadInt32(); + } + } + break; + case OperandType.InlineTok: + case OperandType.InlineI: + case OperandType.InlineString: + case OperandType.InlineMethod: + case OperandType.InlineField: + var metaDataToken = reader.ReadMetadataToken(); + Type[] genericMethodArguments = null; + if (method.IsGenericMethod) + { + genericMethodArguments = method.GetGenericArguments(); + } + + if (opCode.OperandType == OperandType.InlineMethod) + { + data = method.Module.ResolveMethod(metaDataToken, method.DeclaringType.GetGenericArguments(), genericMethodArguments); + } + else if (opCode.OperandType == OperandType.InlineField) + { + data = method.Module.ResolveField(metaDataToken, method.DeclaringType.GetGenericArguments(), genericMethodArguments); + } + else if (opCode.OperandType == OperandType.InlineString) + { + data = method.Module.ResolveString(metaDataToken); + } + else if (opCode.OperandType == OperandType.InlineI) + { + data = metaDataToken; + } + else if (opCode.OperandType == OperandType.InlineTok) + { + data = method.Module.ResolveType(metaDataToken); + } + break; + case OperandType.ShortInlineR: + data = reader.ReadSingle(); + break; + case OperandType.InlineI8: // more dump? + case OperandType.InlineR: + if (opCode.OperandType == OperandType.InlineI8) + { + data = reader.ReadInt64(); + } + else + { + data = reader.ReadDouble(); + } + break; + default: + throw new NotImplementedException(); + } + + yield return new Instruction(position, opCode, data); + } + } + } + public struct Instruction + { + public readonly int Offset; + public readonly OpCode OpCode; + public readonly object Data; + + static readonly Regex TrimVersion = new Regex(", Version=.+, Culture=.+, PublicKeyToken=[0-9a-z]+", RegexOptions.Compiled); + + public Instruction(int offset, OpCode opCode, object data) + { + Offset = offset; + OpCode = opCode; + Data = data; + } + + public override string ToString() + { + // format like LINQPad IL + var addition = ""; + if (Data is int && OpCode == OpCodes.Switch) // switch + { + // var offset = Offset; + // addition = "(" + string.Join(", ", Enumerable.Range(0, (int)Data).Select(x => "IL_" + (offset + x * 4).ToString("X4")).ToArray()) + ")"; + } + else if ((OpCode.OperandType == OperandType.InlineBrTarget) && (Data is int)) + { + // note:jump position + // addition = "IL_" + (Offset + (int)Data).ToString("X4"); + } + else if ((OpCode.OperandType == OperandType.ShortInlineBrTarget) && (Data is byte)) + { + // addition = "IL_" + (Offset + (byte)Data).ToString("X4"); + } + else if (Data is byte) + { + addition = ((byte)Data).ToString(); // I don't like hex format:) + } + else if (Data is int) + { + addition = ((int)Data).ToString(); + } + else if (Data is long) + { + addition = ((long)Data).ToString(); + } + else if (Data is double) + { + addition = ((double)Data).ToString(); + } + else if (Data is float) + { + addition = ((float)Data).ToString(); + } + else if (Data is MethodInfo) + { + var info = Data as MethodInfo; + addition = TrimVersion.Replace(info.DeclaringType.FullName, "") + "." + info.Name; + } + else if (Data is ConstructorInfo) + { + var info = Data as ConstructorInfo; + addition = TrimVersion.Replace(info.DeclaringType.FullName, "") + ".ctor"; + } + else if (Data is FieldInfo) + { + var info = Data as FieldInfo; + addition = TrimVersion.Replace(info.DeclaringType.FullName, "") + "." + info.Name; + } + else if (Data is String) + { + addition = (string)Data; + } + else if (Data is Type) + { + addition = TrimVersion.Replace(((Type)Data).FullName, ""); + } + + return string.Format("IL_{0,4:X4}: {1, -11} {2}", Offset, OpCode, addition); + } + } + } + +#endif +} diff --git a/Unity3D/3rdLib/Utf8Json/Internal/Emit/ILViewer.cs.meta b/Unity3D/3rdLib/Utf8Json/Internal/Emit/ILViewer.cs.meta new file mode 100644 index 0000000..99dcd6d --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/Emit/ILViewer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 886ed9cb12e14b7cb6b3c33e5eb30489 +timeCreated: 1668660996 \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/Emit/MetaMember.cs b/Unity3D/3rdLib/Utf8Json/Internal/Emit/MetaMember.cs new file mode 100644 index 0000000..4ad3a9b --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/Emit/MetaMember.cs @@ -0,0 +1,172 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using System.Text; +using System.Runtime.Serialization; + +namespace Utf8Json.Internal.Emit +{ + internal class MetaMember + { + public string Name { get; private set; } + public string MemberName { get; private set; } + + public bool IsProperty { get { return PropertyInfo != null; } } + public bool IsField { get { return FieldInfo != null; } } + public bool IsWritable { get; private set; } + public bool IsReadable { get; private set; } + public Type Type { get; private set; } + public FieldInfo FieldInfo { get; private set; } + public PropertyInfo PropertyInfo { get; private set; } + public MethodInfo ShouldSerializeMethodInfo { get; private set; } + + MethodInfo getMethod; + MethodInfo setMethod; + + protected MetaMember(Type type, string name, string memberName, bool isWritable, bool isReadable) + { + this.Name = name; + this.MemberName = memberName; + this.Type = type; + this.IsWritable = isWritable; + this.IsReadable = isReadable; + } + + public MetaMember(FieldInfo info, string name, bool allowPrivate) + { + this.Name = name; + this.MemberName = info.Name; + this.FieldInfo = info; + this.Type = info.FieldType; + this.IsReadable = allowPrivate || info.IsPublic; + this.IsWritable = allowPrivate || (info.IsPublic && !info.IsInitOnly); + this.ShouldSerializeMethodInfo = GetShouldSerialize(info); + } + + public MetaMember(PropertyInfo info, string name, bool allowPrivate) + { + this.getMethod = info.GetGetMethod(true); + this.setMethod = info.GetSetMethod(true); + + this.Name = name; + this.MemberName = info.Name; + this.PropertyInfo = info; + this.Type = info.PropertyType; + this.IsReadable = (getMethod != null) && (allowPrivate || getMethod.IsPublic) && !getMethod.IsStatic; + this.IsWritable = (setMethod != null) && (allowPrivate || setMethod.IsPublic) && !setMethod.IsStatic; + this.ShouldSerializeMethodInfo = GetShouldSerialize(info); + } + + static MethodInfo GetShouldSerialize(MemberInfo info) + { + var shouldSerialize = "ShouldSerialize" + info.Name; + + // public only + return info.DeclaringType.GetMethods(BindingFlags.Instance | BindingFlags.Public) + .Where(x => x.Name == shouldSerialize && x.ReturnType == typeof(bool) && x.GetParameters().Length == 0) + .FirstOrDefault(); + } + + public T GetCustomAttribute(bool inherit) where T : Attribute + { + if (IsProperty) + { + return PropertyInfo.GetCustomAttribute(inherit); + } + else if (FieldInfo != null) + { + return FieldInfo.GetCustomAttribute(inherit); + } + else + { + return null; + } + } + + public virtual void EmitLoadValue(ILGenerator il) + { + if (IsProperty) + { + il.EmitCall(getMethod); + } + else + { + il.Emit(OpCodes.Ldfld, FieldInfo); + } + } + + public virtual void EmitStoreValue(ILGenerator il) + { + if (IsProperty) + { + il.EmitCall(setMethod); + } + else + { + il.Emit(OpCodes.Stfld, FieldInfo); + } + } + } + + // used for serialize exception... + internal class StringConstantValueMetaMember : MetaMember + { + readonly string constant; + + public StringConstantValueMetaMember(string name, string constant) + : base(typeof(String), name, name, false, true) + { + this.constant = constant; + } + + public override void EmitLoadValue(ILGenerator il) + { + il.Emit(OpCodes.Pop); // pop load instance + il.Emit(OpCodes.Ldstr, constant); + } + + public override void EmitStoreValue(ILGenerator il) + { + throw new NotSupportedException(); + } + } + + // used for serialize exception... + internal class InnerExceptionMetaMember : MetaMember + { + static readonly MethodInfo getInnerException = ExpressionUtility.GetPropertyInfo((Exception ex) => ex.InnerException).GetGetMethod(); + static readonly MethodInfo nongenericSerialize = ExpressionUtility.GetMethodInfo(writer => JsonSerializer.NonGeneric.Serialize(ref writer, default(object), default(IJsonFormatterResolver))); + + // set after... + internal ArgumentField argWriter; + internal ArgumentField argValue; + internal ArgumentField argResolver; + + public InnerExceptionMetaMember(string name) + : base(typeof(Exception), name, name, false, true) + { + } + + public override void EmitLoadValue(ILGenerator il) + { + il.Emit(OpCodes.Callvirt, getInnerException); + } + + public override void EmitStoreValue(ILGenerator il) + { + throw new NotSupportedException(); + } + + public void EmitSerializeDirectly(ILGenerator il) + { + // JsonSerializer.NonGeneric.Serialize(ref writer, value.InnerException, formatterResolver); + argWriter.EmitLoad(); + argValue.EmitLoad(); + il.Emit(OpCodes.Callvirt, getInnerException); + argResolver.EmitLoad(); + il.EmitCall(nongenericSerialize); + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/Emit/MetaMember.cs.meta b/Unity3D/3rdLib/Utf8Json/Internal/Emit/MetaMember.cs.meta new file mode 100644 index 0000000..8eff3d2 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/Emit/MetaMember.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3473cd019eb046948ffb228010396b51 +timeCreated: 1668660996 \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/Emit/MetaType.cs b/Unity3D/3rdLib/Utf8Json/Internal/Emit/MetaType.cs new file mode 100644 index 0000000..c7d4e40 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/Emit/MetaType.cs @@ -0,0 +1,159 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.Serialization; + +namespace Utf8Json.Internal.Emit +{ + internal class MetaType + { + public Type Type { get; private set; } + public bool IsClass { get; private set; } + public bool IsStruct { get { return !IsClass; } } + public bool IsConcreteClass { get; private set; } + + public ConstructorInfo BestmatchConstructor { get; internal set; } + public MetaMember[] ConstructorParameters { get; internal set; } + public MetaMember[] Members { get; internal set; } + + public MetaType(Type type, Func nameMutetor, bool allowPrivate) + { + var ti = type.GetTypeInfo(); + var isClass = ti.IsClass || ti.IsInterface || ti.IsAbstract; + + this.Type = type; + var stringMembers = new Dictionary(); + + { + foreach (var item in type.GetAllProperties()) + { + if (item.GetIndexParameters().Length > 0) continue; // skip indexer + if (item.GetCustomAttribute(true) != null) continue; + + var dm = item.GetCustomAttribute(true); + var name = (dm != null && dm.Name != null) ? dm.Name : nameMutetor(item.Name); + + var member = new MetaMember(item, name, allowPrivate); + if (!member.IsReadable && !member.IsWritable) continue; + + if (stringMembers.ContainsKey(member.Name)) + { + throw new InvalidOperationException("same (custom)name is in type. Type:" + type.Name + " Name:" + member.Name); + } + stringMembers.Add(member.Name, member); + } + foreach (var item in type.GetAllFields()) + { + if (item.GetCustomAttribute(true) != null) continue; + if (item.GetCustomAttribute(true) != null) continue; + if (item.IsStatic) continue; + if (item.Name.StartsWith("<")) continue; // compiler generated field(anonymous type, etc...) + + var dm = item.GetCustomAttribute(true); + var name = (dm != null && dm.Name != null) ? dm.Name : nameMutetor(item.Name); + + var member = new MetaMember(item, name, allowPrivate); + if (!member.IsReadable && !member.IsWritable) continue; + + if (stringMembers.ContainsKey(member.Name)) + { + throw new InvalidOperationException("same (custom)name is in type. Type:" + type.Name + " Name:" + member.Name); + } + stringMembers.Add(member.Name, member); + } + } + + // GetConstructor + var ctor = ti.DeclaredConstructors.Where(x => x.IsPublic) + .SingleOrDefault(x => x.GetCustomAttribute(false) != null); + var constructorParameters = new List(); + { + IEnumerator ctorEnumerator = null; + if (ctor == null) + { + // descending. + ctorEnumerator = ti.DeclaredConstructors.Where(x => x.IsPublic).OrderByDescending(x => x.GetParameters().Length).GetEnumerator(); + if (ctorEnumerator.MoveNext()) + { + ctor = ctorEnumerator.Current; + } + } + + if (ctor != null) + { + var constructorLookupDictionary = stringMembers.ToLookup(x => x.Key, x => x, StringComparer.OrdinalIgnoreCase); + do + { + constructorParameters.Clear(); + var ctorParamIndex = 0; + foreach (var item in ctor.GetParameters()) + { + MetaMember paramMember; + + var hasKey = constructorLookupDictionary[item.Name]; + var len = hasKey.Count(); + if (len != 0) + { + if (len != 1) + { + if (ctorEnumerator != null) + { + ctor = null; + continue; + } + else + { + throw new InvalidOperationException("duplicate matched constructor parameter name:" + type.FullName + " parameterName:" + item.Name + " paramterType:" + item.ParameterType.Name); + } + } + + paramMember = hasKey.First().Value; + if (item.ParameterType == paramMember.Type && paramMember.IsReadable) + { + constructorParameters.Add(paramMember); + } + else + { + ctor = null; + continue; + } + } + else + { + ctor = null; + continue; + } + ctorParamIndex++; + } + } while (TryGetNextConstructor(ctorEnumerator, ref ctor)); + } + } + + this.IsClass = isClass; + this.IsConcreteClass = isClass && !(ti.IsAbstract || ti.IsInterface); + this.BestmatchConstructor = ctor; + this.ConstructorParameters = constructorParameters.ToArray(); + this.Members = stringMembers.Values.ToArray(); + } + + static bool TryGetNextConstructor(IEnumerator ctorEnumerator, ref ConstructorInfo ctor) + { + if (ctorEnumerator == null || ctor != null) + { + return false; + } + + if (ctorEnumerator.MoveNext()) + { + ctor = ctorEnumerator.Current; + return true; + } + else + { + ctor = null; + return false; + } + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Internal/Emit/MetaType.cs.meta b/Unity3D/3rdLib/Utf8Json/Internal/Emit/MetaType.cs.meta new file mode 100644 index 0000000..d17d580 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/Emit/MetaType.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ef67a98b73404d8995b3bb5f73daf9c3 +timeCreated: 1668660996 \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/FarmHash.cs b/Unity3D/3rdLib/Utf8Json/Internal/FarmHash.cs new file mode 100644 index 0000000..96ea8f2 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/FarmHash.cs @@ -0,0 +1,604 @@ +#if NETSTANDARD + +using System.Runtime.CompilerServices; + +namespace Utf8Json.Internal +{ + internal static class FarmHash + { + // entry point of 32bit + + #region Hash32 + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe uint Hash32(byte[] bytes, int offset, int count) + { + if (count <= 4) + { + return Hash32Len0to4(bytes, offset, (uint)count); + } + + fixed (byte* p = &bytes[offset]) + { + return Hash32(p, (uint)count); + } + } + + // port of farmhash.cc, 32bit only + + // Magic numbers for 32-bit hashing. Copied from Murmur3. + const uint c1 = 0xcc9e2d51; + const uint c2 = 0x1b873593; + + static unsafe uint Fetch32(byte* p) + { + return *(uint*)p; + } + + static uint Rotate32(uint val, int shift) + { + return shift == 0 ? val : ((val >> shift) | (val << (32 - shift))); + } + + // A 32-bit to 32-bit integer hash copied from Murmur3. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static uint fmix(uint h) + { + unchecked + { + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + return h; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static uint Mur(uint a, uint h) + { + unchecked + { + // Helper from Murmur3 for combining two 32-bit values. + a *= c1; + a = Rotate32(a, 17); + a *= c2; + h ^= a; + h = Rotate32(h, 19); + return h * 5 + 0xe6546b64; + } + } + + // 0-4 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static unsafe uint Hash32Len0to4(byte[] s, int offset, uint len) + { + unchecked + { + uint b = 0; + uint c = 9; + var max = offset + len; + for (int i = offset; i < max; i++) + { + b = b * c1 + s[i]; + c ^= b; + } + return fmix(Mur(b, Mur(len, c))); + } + } + + // 5-12 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static unsafe uint Hash32Len5to12(byte* s, uint len) + { + unchecked + { + uint a = len, b = len * 5, c = 9, d = b; + a += Fetch32(s); + b += Fetch32(s + len - 4); + c += Fetch32(s + ((len >> 1) & 4)); + return fmix(Mur(c, Mur(b, Mur(a, d)))); + } + } + + // 13-24 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static unsafe uint Hash32Len13to24(byte* s, uint len) + { + unchecked + { + uint a = Fetch32(s - 4 + (len >> 1)); + uint b = Fetch32(s + 4); + uint c = Fetch32(s + len - 8); + uint d = Fetch32(s + (len >> 1)); + uint e = Fetch32(s); + uint f = Fetch32(s + len - 4); + uint h = d * c1 + len; + a = Rotate32(a, 12) + f; + h = Mur(c, h) + a; + a = Rotate32(a, 3) + c; + h = Mur(e, h) + a; + a = Rotate32(a + f, 12) + d; + h = Mur(b, h) + a; + return fmix(h); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static unsafe uint Hash32(byte* s, uint len) + { + if (len <= 24) + { + return len <= 12 ? Hash32Len5to12(s, len) : Hash32Len13to24(s, len); + } + + unchecked + { + // len > 24 + uint h = len, g = c1 * len, f = g; + uint a0 = Rotate32(Fetch32(s + len - 4) * c1, 17) * c2; + uint a1 = Rotate32(Fetch32(s + len - 8) * c1, 17) * c2; + uint a2 = Rotate32(Fetch32(s + len - 16) * c1, 17) * c2; + uint a3 = Rotate32(Fetch32(s + len - 12) * c1, 17) * c2; + uint a4 = Rotate32(Fetch32(s + len - 20) * c1, 17) * c2; + h ^= a0; + h = Rotate32(h, 19); + h = h * 5 + 0xe6546b64; + h ^= a2; + h = Rotate32(h, 19); + h = h * 5 + 0xe6546b64; + g ^= a1; + g = Rotate32(g, 19); + g = g * 5 + 0xe6546b64; + g ^= a3; + g = Rotate32(g, 19); + g = g * 5 + 0xe6546b64; + f += a4; + f = Rotate32(f, 19) + 113; + uint iters = (len - 1) / 20; + do + { + uint a = Fetch32(s); + uint b = Fetch32(s + 4); + uint c = Fetch32(s + 8); + uint d = Fetch32(s + 12); + uint e = Fetch32(s + 16); + h += a; + g += b; + f += c; + h = Mur(d, h) + e; + g = Mur(c, g) + a; + f = Mur(b + e * c1, f) + d; + f += g; + g += f; + s += 20; + } while (--iters != 0); + g = Rotate32(g, 11) * c1; + g = Rotate32(g, 17) * c1; + f = Rotate32(f, 11) * c1; + f = Rotate32(f, 17) * c1; + h = Rotate32(h + g, 19); + h = h * 5 + 0xe6546b64; + h = Rotate32(h, 17) * c1; + h = Rotate32(h + f, 19); + h = h * 5 + 0xe6546b64; + h = Rotate32(h, 17) * c1; + return h; + } + } + + #endregion + + #region hash64 + + // entry point + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe ulong Hash64(byte[] bytes, int offset, int count) + { + fixed (byte* p = &bytes[offset]) + { + return Hash64(p, (uint)count); + } + } + + // port from farmhash.cc + + struct pair + { + public ulong first; + public ulong second; + + public pair(ulong first, ulong second) + { + this.first = first; + this.second = second; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static pair make_pair(ulong first, ulong second) + { + return new pair(first, second); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static void swap(ref ulong x, ref ulong z) + { + var temp = z; + z = x; + x = temp; + } + + // Some primes between 2^63 and 2^64 for various uses. + const ulong k0 = 0xc3a5c85c97cb3127UL; + const ulong k1 = 0xb492b66fbe98f273UL; + const ulong k2 = 0x9ae16a3b2f90404fUL; + + static unsafe ulong Fetch64(byte* p) + { + return *(ulong*)p; + } + + static ulong Rotate64(ulong val, int shift) + { + return shift == 0 ? val : (val >> shift) | (val << (64 - shift)); + } + + // farmhashna.cc + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static ulong ShiftMix(ulong val) + { + return val ^ (val >> 47); + } + + // farmhashna.cc + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static ulong HashLen16(ulong u, ulong v, ulong mul) + { + unchecked + { + // Murmur-inspired hashing. + ulong a = (u ^ v) * mul; + a ^= a >> 47; + ulong b = (v ^ a) * mul; + b ^= b >> 47; + b *= mul; + return b; + } + } + + // farmhashxo.cc + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static unsafe ulong Hash64(byte* s, uint len) + { + if (len <= 16) + { + // farmhashna:: + return HashLen0to16(s, len); + } + + if (len <= 32) + { + // farmhashna:: + return HashLen17to32(s, len); + } + + if (len <= 64) + { + return HashLen33to64(s, len); + } + + if (len <= 96) + { + return HashLen65to96(s, len); + } + + if (len <= 256) + { + // farmhashna:: + return Hash64NA(s, len); + } + + // farmhashuo:: + return Hash64UO(s, len); + } + + // 0-16 farmhashna.cc + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static unsafe ulong HashLen0to16(byte* s, uint len) + { + unchecked + { + if (len >= 8) + { + ulong mul = k2 + len * 2; + ulong a = Fetch64(s) + k2; + ulong b = Fetch64(s + len - 8); + ulong c = Rotate64(b, 37) * mul + a; + ulong d = (Rotate64(a, 25) + b) * mul; + return HashLen16(c, d, mul); + } + if (len >= 4) + { + ulong mul = k2 + len * 2; + ulong a = Fetch32(s); + return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul); + } + if (len > 0) + { + ushort a = s[0]; + ushort b = s[len >> 1]; + ushort c = s[len - 1]; + uint y = a + ((uint)b << 8); + uint z = len + ((uint)c << 2); + return ShiftMix(y * k2 ^ z * k0) * k2; + } + return k2; + } + } + + // 17-32 farmhashna.cc + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static unsafe ulong HashLen17to32(byte* s, uint len) + { + unchecked + { + ulong mul = k2 + len * 2; + ulong a = Fetch64(s) * k1; + ulong b = Fetch64(s + 8); + ulong c = Fetch64(s + len - 8) * mul; + ulong d = Fetch64(s + len - 16) * k2; + return HashLen16(Rotate64(a + b, 43) + Rotate64(c, 30) + d, + a + Rotate64(b + k2, 18) + c, mul); + } + } + + // farmhashxo.cc + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static unsafe ulong H32(byte* s, uint len, ulong mul, ulong seed0 = 0, ulong seed1 = 0) + { + unchecked + { + ulong a = Fetch64(s) * k1; + ulong b = Fetch64(s + 8); + ulong c = Fetch64(s + len - 8) * mul; + ulong d = Fetch64(s + len - 16) * k2; + ulong u = Rotate64(a + b, 43) + Rotate64(c, 30) + d + seed0; + ulong v = a + Rotate64(b + k2, 18) + c + seed1; + a = ShiftMix((u ^ v) * mul); + b = ShiftMix((v ^ a) * mul); + return b; + } + } + + // 33-64 farmhashxo.cc + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static unsafe ulong HashLen33to64(byte* s, uint len) + { + const ulong mul0 = k2 - 30; + + unchecked + { + ulong mul1 = k2 - 30 + 2 * len; + ulong h0 = H32(s, 32, mul0); + ulong h1 = H32(s + len - 32, 32, mul1); + return (h1 * mul1 + h0) * mul1; + } + } + + // 65-96 farmhashxo.cc + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static unsafe ulong HashLen65to96(byte* s, uint len) + { + const ulong mul0 = k2 - 114; + + unchecked + { + ulong mul1 = k2 - 114 + 2 * len; + ulong h0 = H32(s, 32, mul0); + ulong h1 = H32(s + 32, 32, mul1); + ulong h2 = H32(s + len - 32, 32, mul1, h0, h1); + return (h2 * 9 + (h0 >> 17) + (h1 >> 21)) * mul1; + } + } + + // farmhashna.cc + // Return a 16-byte hash for 48 bytes. Quick and dirty. + // Callers do best to use "random-looking" values for a and b. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static unsafe pair WeakHashLen32WithSeeds(ulong w, ulong x, ulong y, ulong z, ulong a, ulong b) + { + unchecked + { + a += w; + b = Rotate64(b + a + z, 21); + ulong c = a; + a += x; + a += y; + b += Rotate64(a, 44); + return make_pair(a + z, b + c); + } + } + + // farmhashna.cc + // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static unsafe pair WeakHashLen32WithSeeds(byte* s, ulong a, ulong b) + { + return WeakHashLen32WithSeeds(Fetch64(s), + Fetch64(s + 8), + Fetch64(s + 16), + Fetch64(s + 24), + a, + b); + } + + // na(97-256) farmhashna.cc + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static unsafe ulong Hash64NA(byte* s, uint len) + { + const ulong seed = 81; + + unchecked + { + // For strings over 64 bytes we loop. Internal state consists of + // 56 bytes: v, w, x, y, and z. + ulong x = seed; + ulong y = seed * k1 + 113; + ulong z = ShiftMix(y * k2 + 113) * k2; + var v = make_pair(0, 0); + var w = make_pair(0, 0); + x = x * k2 + Fetch64(s); + + // Set end so that after the loop we have 1 to 64 bytes left to process. + byte* end = s + ((len - 1) / 64) * 64; + byte* last64 = end + ((len - 1) & 63) - 63; + + do + { + x = Rotate64(x + y + v.first + Fetch64(s + 8), 37) * k1; + y = Rotate64(y + v.second + Fetch64(s + 48), 42) * k1; + x ^= w.second; + y += v.first + Fetch64(s + 40); + z = Rotate64(z + w.first, 33) * k1; + v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); + w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16)); + swap(ref z, ref x); + s += 64; + } while (s != end); + ulong mul = k1 + ((z & 0xff) << 1); + // Make s point to the last 64 bytes of input. + s = last64; + w.first += ((len - 1) & 63); + v.first += w.first; + w.first += v.first; + x = Rotate64(x + y + v.first + Fetch64(s + 8), 37) * mul; + y = Rotate64(y + v.second + Fetch64(s + 48), 42) * mul; + x ^= w.second * 9; + y += v.first * 9 + Fetch64(s + 40); + z = Rotate64(z + w.first, 33) * mul; + v = WeakHashLen32WithSeeds(s, v.second * mul, x + w.first); + w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16)); + swap(ref z, ref x); + return HashLen16(HashLen16(v.first, w.first, mul) + ShiftMix(y) * k0 + z, + HashLen16(v.second, w.second, mul) + x, + mul); + } + } + + // farmhashuo.cc + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static ulong H(ulong x, ulong y, ulong mul, int r) + { + unchecked + { + ulong a = (x ^ y) * mul; + a ^= (a >> 47); + ulong b = (y ^ a) * mul; + return Rotate64(b, r) * mul; + } + } + + // uo(257-) farmhashuo.cc, Hash64WithSeeds + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static unsafe ulong Hash64UO(byte* s, uint len) + { + const ulong seed0 = 81; + const ulong seed1 = 0; + + unchecked + { + // For strings over 64 bytes we loop. Internal state consists of + // 64 bytes: u, v, w, x, y, and z. + ulong x = seed0; + ulong y = seed1 * k2 + 113; + ulong z = ShiftMix(y * k2) * k2; + var v = make_pair(seed0, seed1); + var w = make_pair(0, 0); + ulong u = x - z; + x *= k2; + ulong mul = k2 + (u & 0x82); + + // Set end so that after the loop we have 1 to 64 bytes left to process. + byte* end = s + ((len - 1) / 64) * 64; + byte* last64 = end + ((len - 1) & 63) - 63; + + do + { + ulong a0 = Fetch64(s); + ulong a1 = Fetch64(s + 8); + ulong a2 = Fetch64(s + 16); + ulong a3 = Fetch64(s + 24); + ulong a4 = Fetch64(s + 32); + ulong a5 = Fetch64(s + 40); + ulong a6 = Fetch64(s + 48); + ulong a7 = Fetch64(s + 56); + x += a0 + a1; + y += a2; + z += a3; + v.first += a4; + v.second += a5 + a1; + w.first += a6; + w.second += a7; + + x = Rotate64(x, 26); + x *= 9; + y = Rotate64(y, 29); + z *= mul; + v.first = Rotate64(v.first, 33); + v.second = Rotate64(v.second, 30); + w.first ^= x; + w.first *= 9; + z = Rotate64(z, 32); + z += w.second; + w.second += z; + z *= 9; + swap(ref u, ref y); + + z += a0 + a6; + v.first += a2; + v.second += a3; + w.first += a4; + w.second += a5 + a6; + x += a1; + y += a7; + + y += v.first; + v.first += x - y; + v.second += w.first; + w.first += v.second; + w.second += x - y; + x += w.second; + w.second = Rotate64(w.second, 34); + swap(ref u, ref z); + s += 64; + } while (s != end); + // Make s point to the last 64 bytes of input. + s = last64; + u *= 9; + v.second = Rotate64(v.second, 28); + v.first = Rotate64(v.first, 20); + w.first += ((len - 1) & 63); + u += y; + y += u; + x = Rotate64(y - x + v.first + Fetch64(s + 8), 37) * mul; + y = Rotate64(y ^ v.second ^ Fetch64(s + 48), 42) * mul; + x ^= w.second * 9; + y += v.first + Fetch64(s + 40); + z = Rotate64(z + w.first, 33) * mul; + v = WeakHashLen32WithSeeds(s, v.second * mul, x + w.first); + w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16)); + return H(HashLen16(v.first + x, w.first ^ y, mul) + z - u, + H(v.second + y, w.second + z, k2, 30) ^ x, + k2, + 31); + } + } + + #endregion + } +} + +#endif \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/FuncExtensions.cs b/Unity3D/3rdLib/Utf8Json/Internal/FuncExtensions.cs new file mode 100644 index 0000000..9298123 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/FuncExtensions.cs @@ -0,0 +1,35 @@ +#if NETSTANDARD + +using System; + +namespace Utf8Json.Internal +{ + // Unity compiler can't understand this. + + internal static class FuncExtensions + { + // hack of avoid closure allocation(() => value). + public static Func AsFunc(this T value) + { + return new Func(value.ReturnBox); + } + + public static Func AsFuncFast(this T value) where T : class + { + return new Func(value.Return); + } + + static T Return(this T value) + { + return value; + } + + static T ReturnBox(this object value) + { + return (T)value; + } + } +} + + +#endif \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/GuidBits.cs b/Unity3D/3rdLib/Utf8Json/Internal/GuidBits.cs new file mode 100644 index 0000000..0211371 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/GuidBits.cs @@ -0,0 +1,372 @@ +using System; +using System.Runtime.InteropServices; + +namespace Utf8Json.Internal +{ + [StructLayout(LayoutKind.Explicit, Pack = 1)] + internal struct GuidBits + { + [FieldOffset(0)] + public readonly Guid Value; + + [FieldOffset(0)] + public readonly byte Byte0; + [FieldOffset(1)] + public readonly byte Byte1; + [FieldOffset(2)] + public readonly byte Byte2; + [FieldOffset(3)] + public readonly byte Byte3; + [FieldOffset(4)] + public readonly byte Byte4; + [FieldOffset(5)] + public readonly byte Byte5; + [FieldOffset(6)] + public readonly byte Byte6; + [FieldOffset(7)] + public readonly byte Byte7; + [FieldOffset(8)] + public readonly byte Byte8; + [FieldOffset(9)] + public readonly byte Byte9; + [FieldOffset(10)] + public readonly byte Byte10; + [FieldOffset(11)] + public readonly byte Byte11; + [FieldOffset(12)] + public readonly byte Byte12; + [FieldOffset(13)] + public readonly byte Byte13; + [FieldOffset(14)] + public readonly byte Byte14; + [FieldOffset(15)] + public readonly byte Byte15; + + // string.Join(", ", Enumerable.Range(0, 256).Select(x => (int)BitConverter.ToString(new byte[] { (byte)x }).ToLower()[0])) + static byte[] byteToHexStringHigh = new byte[256] { 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102 }; + + // string.Join(", ", Enumerable.Range(0, 256).Select(x => (int)BitConverter.ToString(new byte[] { (byte)x }).ToLower()[1])) + static byte[] byteToHexStringLow = new byte[256] { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102 }; + + public GuidBits(ref Guid value) + { + this = default(GuidBits); + this.Value = value; + } + + // 4-pattern, lower/upper and '-' or no + public GuidBits(ref ArraySegment utf8string) + { + this = default(GuidBits); + + var array = utf8string.Array; + var offset = utf8string.Offset; + + // 32 + if (utf8string.Count == 32) + { + if (BitConverter.IsLittleEndian) + { + this.Byte0 = Parse(array, offset + 6); + this.Byte1 = Parse(array, offset + 4); + this.Byte2 = Parse(array, offset + 2); + this.Byte3 = Parse(array, offset + 0); + + this.Byte4 = Parse(array, offset + 10); + this.Byte5 = Parse(array, offset + 8); + + this.Byte6 = Parse(array, offset + 14); + this.Byte7 = Parse(array, offset + 12); + } + else + { + this.Byte0 = Parse(array, offset + 0); + this.Byte1 = Parse(array, offset + 2); + this.Byte2 = Parse(array, offset + 4); + this.Byte3 = Parse(array, offset + 6); + + this.Byte4 = Parse(array, offset + 8); + this.Byte5 = Parse(array, offset + 10); + + this.Byte6 = Parse(array, offset + 12); + this.Byte7 = Parse(array, offset + 14); + } + this.Byte8 = Parse(array, offset + 16); + this.Byte9 = Parse(array, offset + 18); + + this.Byte10 = Parse(array, offset + 20); + this.Byte11 = Parse(array, offset + 22); + this.Byte12 = Parse(array, offset + 24); + this.Byte13 = Parse(array, offset + 26); + this.Byte14 = Parse(array, offset + 28); + this.Byte15 = Parse(array, offset + 30); + return; + } + else if (utf8string.Count == 36) + { + // '-' => 45 + if (BitConverter.IsLittleEndian) + { + this.Byte0 = Parse(array, offset + 6); + this.Byte1 = Parse(array, offset + 4); + this.Byte2 = Parse(array, offset + 2); + this.Byte3 = Parse(array, offset + 0); + + if (array[offset + 8] != '-') goto ERROR; + + this.Byte4 = Parse(array, offset + 11); + this.Byte5 = Parse(array, offset + 9); + + if (array[offset + 13] != '-') goto ERROR; + + this.Byte6 = Parse(array, offset + 16); + this.Byte7 = Parse(array, offset + 14); + } + else + { + this.Byte0 = Parse(array, offset + 0); + this.Byte1 = Parse(array, offset + 2); + this.Byte2 = Parse(array, offset + 4); + this.Byte3 = Parse(array, offset + 6); + + if (array[offset + 8] != '-') goto ERROR; + + this.Byte4 = Parse(array, offset + 9); + this.Byte5 = Parse(array, offset + 11); + + if (array[offset + 13] != '-') goto ERROR; + + this.Byte6 = Parse(array, offset + 14); + this.Byte7 = Parse(array, offset + 16); + } + + if (array[offset + 18] != '-') goto ERROR; + + this.Byte8 = Parse(array, offset + 19); + this.Byte9 = Parse(array, offset + 21); + + if (array[offset + 23] != '-') goto ERROR; + + this.Byte10 = Parse(array, offset + 24); + this.Byte11 = Parse(array, offset + 26); + this.Byte12 = Parse(array, offset + 28); + this.Byte13 = Parse(array, offset + 30); + this.Byte14 = Parse(array, offset + 32); + this.Byte15 = Parse(array, offset + 34); + return; + } + + ERROR: + throw new ArgumentException("Invalid Guid Pattern."); + } + +#if NETSTANDARD + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] +#endif + static byte Parse(byte[] bytes, int highOffset) + { + return unchecked((byte)(SwitchParse(bytes[highOffset]) * 16 + SwitchParse(bytes[highOffset + 1]))); + } + +#if NETSTANDARD + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] +#endif + static byte SwitchParse(byte b) + { + // '0'(48) ~ '9'(57) => -48 + // 'A'(65) ~ 'F'(70) => -55 + // 'a'(97) ~ 'f'(102) => -87 + switch (b) + { + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + return unchecked((byte)((b - 48))); + case 65: + case 66: + case 67: + case 68: + case 69: + case 70: + return unchecked((byte)((b - 55))); + case 97: + case 98: + case 99: + case 100: + case 101: + case 102: + return unchecked((byte)((b - 87))); + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + case 58: + case 59: + case 60: + case 61: + case 62: + case 63: + case 64: + case 71: + case 72: + case 73: + case 74: + case 75: + case 76: + case 77: + case 78: + case 79: + case 80: + case 81: + case 82: + case 83: + case 84: + case 85: + case 86: + case 87: + case 88: + case 89: + case 90: + case 91: + case 92: + case 93: + case 94: + case 95: + case 96: + default: + throw new ArgumentException("Invalid Guid Pattern."); + } + } + + // 4(x2) - 2(x2) - 2(x2) - 2(x2) - 6(x2) + public void Write(byte[] buffer, int offset) + { + if (BitConverter.IsLittleEndian) + { + // int(_a) + buffer[offset + 6] = byteToHexStringHigh[Byte0]; + buffer[offset + 7] = byteToHexStringLow[Byte0]; + buffer[offset + 4] = byteToHexStringHigh[Byte1]; + buffer[offset + 5] = byteToHexStringLow[Byte1]; + buffer[offset + 2] = byteToHexStringHigh[Byte2]; + buffer[offset + 3] = byteToHexStringLow[Byte2]; + buffer[offset + 0] = byteToHexStringHigh[Byte3]; + buffer[offset + 1] = byteToHexStringLow[Byte3]; + + buffer[offset + 8] = (byte)'-'; + + // short(_b) + buffer[offset + 11] = byteToHexStringHigh[Byte4]; + buffer[offset + 12] = byteToHexStringLow[Byte4]; + buffer[offset + 9] = byteToHexStringHigh[Byte5]; + buffer[offset + 10] = byteToHexStringLow[Byte5]; + + buffer[offset + 13] = (byte)'-'; + + // short(_c) + buffer[offset + 16] = byteToHexStringHigh[Byte6]; + buffer[offset + 17] = byteToHexStringLow[Byte6]; + buffer[offset + 14] = byteToHexStringHigh[Byte7]; + buffer[offset + 15] = byteToHexStringLow[Byte7]; + } + else + { + buffer[offset + 0] = byteToHexStringHigh[Byte0]; + buffer[offset + 1] = byteToHexStringLow[Byte0]; + buffer[offset + 2] = byteToHexStringHigh[Byte1]; + buffer[offset + 3] = byteToHexStringLow[Byte1]; + buffer[offset + 4] = byteToHexStringHigh[Byte2]; + buffer[offset + 5] = byteToHexStringLow[Byte2]; + buffer[offset + 6] = byteToHexStringHigh[Byte3]; + buffer[offset + 7] = byteToHexStringLow[Byte3]; + + buffer[offset + 8] = (byte)'-'; + + buffer[offset + 9] = byteToHexStringHigh[Byte4]; + buffer[offset + 10] = byteToHexStringLow[Byte4]; + buffer[offset + 11] = byteToHexStringHigh[Byte5]; + buffer[offset + 12] = byteToHexStringLow[Byte5]; + + buffer[offset + 13] = (byte)'-'; + + buffer[offset + 14] = byteToHexStringHigh[Byte6]; + buffer[offset + 15] = byteToHexStringLow[Byte6]; + buffer[offset + 16] = byteToHexStringHigh[Byte7]; + buffer[offset + 17] = byteToHexStringLow[Byte7]; + } + + buffer[offset + 18] = (byte)'-'; + + buffer[offset + 19] = byteToHexStringHigh[Byte8]; + buffer[offset + 20] = byteToHexStringLow[Byte8]; + buffer[offset + 21] = byteToHexStringHigh[Byte9]; + buffer[offset + 22] = byteToHexStringLow[Byte9]; + + buffer[offset + 23] = (byte)'-'; + + buffer[offset + 24] = byteToHexStringHigh[Byte10]; + buffer[offset + 25] = byteToHexStringLow[Byte10]; + buffer[offset + 26] = byteToHexStringHigh[Byte11]; + buffer[offset + 27] = byteToHexStringLow[Byte11]; + buffer[offset + 28] = byteToHexStringHigh[Byte12]; + buffer[offset + 29] = byteToHexStringLow[Byte12]; + buffer[offset + 30] = byteToHexStringHigh[Byte13]; + buffer[offset + 31] = byteToHexStringLow[Byte13]; + buffer[offset + 32] = byteToHexStringHigh[Byte14]; + buffer[offset + 33] = byteToHexStringLow[Byte14]; + buffer[offset + 34] = byteToHexStringHigh[Byte15]; + buffer[offset + 35] = byteToHexStringLow[Byte15]; + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/NumberConverter.cs b/Unity3D/3rdLib/Utf8Json/Internal/NumberConverter.cs new file mode 100644 index 0000000..9ecd32a --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/NumberConverter.cs @@ -0,0 +1,537 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Utf8Json.Internal.DoubleConversion; + +#if NETSTANDARD +using System.Runtime.CompilerServices; +#endif + +namespace Utf8Json.Internal +{ + /// + /// zero-allocate itoa, dtoa, atoi, atod converters. + /// + public static class NumberConverter + { + /// + /// 0 ~ 9 + /// +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static bool IsNumber(byte c) + { + return (byte)'0' <= c && c <= (byte)'9'; + } + + /// + /// Is 0 ~ 9, '.', '+', '-'? + /// +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static bool IsNumberRepresentation(byte c) + { + switch (c) + { + case 43: // + + case 45: // - + case 46: // . + case 48: // 0 + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: // 9 + return true; + case 44: + case 47: + default: + return false; + } + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static sbyte ReadSByte(byte[] bytes, int offset, out int readCount) + { + return checked((sbyte)ReadInt64(bytes, offset, out readCount)); + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static short ReadInt16(byte[] bytes, int offset, out int readCount) + { + return checked((short)ReadInt64(bytes, offset, out readCount)); + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static int ReadInt32(byte[] bytes, int offset, out int readCount) + { + return checked((int)ReadInt64(bytes, offset, out readCount)); + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static long ReadInt64(byte[] bytes, int offset, out int readCount) + { + var value = 0L; + var sign = 1; + + if (bytes[offset] == '-') + { + sign = -1; + } + + for (int i = ((sign == -1) ? offset + 1 : offset); i < bytes.Length; i++) + { + if (!IsNumber(bytes[i])) + { + readCount = i - offset; + goto END; + } + + // long.MinValue causes overflow so use unchecked. + value = unchecked(value * 10 + (bytes[i] - '0')); + } + readCount = bytes.Length - offset; + + END: + return unchecked(value * sign); + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static byte ReadByte(byte[] bytes, int offset, out int readCount) + { + return checked((byte)ReadUInt64(bytes, offset, out readCount)); + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static ushort ReadUInt16(byte[] bytes, int offset, out int readCount) + { + return checked((ushort)ReadUInt64(bytes, offset, out readCount)); + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static uint ReadUInt32(byte[] bytes, int offset, out int readCount) + { + return checked((uint)ReadUInt64(bytes, offset, out readCount)); + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static ulong ReadUInt64(byte[] bytes, int offset, out int readCount) + { + var value = 0UL; + + for (int i = offset; i < bytes.Length; i++) + { + if (!IsNumber(bytes[i])) + { + readCount = i - offset; + goto END; + } + + value = checked(value * 10 + (ulong)(bytes[i] - '0')); + } + readCount = bytes.Length - offset; + + END: + return value; + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static float ReadSingle(byte[] bytes, int offset, out int readCount) + { + return StringToDoubleConverter.ToSingle(bytes, offset, out readCount); + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static double ReadDouble(byte[] bytes, int offset, out int readCount) + { + return StringToDoubleConverter.ToDouble(bytes, offset, out readCount); + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static int WriteByte(ref byte[] buffer, int offset, byte value) + { + return WriteUInt64(ref buffer, offset, (ulong)value); + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static int WriteUInt16(ref byte[] buffer, int offset, ushort value) + { + return WriteUInt64(ref buffer, offset, (ulong)value); + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static int WriteUInt32(ref byte[] buffer, int offset, uint value) + { + return WriteUInt64(ref buffer, offset, (ulong)value); + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static int WriteUInt64(ref byte[] buffer, int offset, ulong value) + { + var startOffset = offset; + + ulong num1 = value, num2, num3, num4, num5, div; + + if (num1 < 10000) + { + if (num1 < 10) { BinaryUtil.EnsureCapacity(ref buffer, offset, 1); goto L1; } + if (num1 < 100) { BinaryUtil.EnsureCapacity(ref buffer, offset, 2); goto L2; } + if (num1 < 1000) { BinaryUtil.EnsureCapacity(ref buffer, offset, 3); goto L3; } + BinaryUtil.EnsureCapacity(ref buffer, offset, 4); goto L4; + } + else + { + num2 = num1 / 10000; + num1 -= num2 * 10000; + if (num2 < 10000) + { + if (num2 < 10) { BinaryUtil.EnsureCapacity(ref buffer, offset, 5); goto L5; } + if (num2 < 100) { BinaryUtil.EnsureCapacity(ref buffer, offset, 6); goto L6; } + if (num2 < 1000) { BinaryUtil.EnsureCapacity(ref buffer, offset, 7); goto L7; } + BinaryUtil.EnsureCapacity(ref buffer, offset, 8); goto L8; + } + else + { + num3 = num2 / 10000; + num2 -= num3 * 10000; + if (num3 < 10000) + { + if (num3 < 10) { BinaryUtil.EnsureCapacity(ref buffer, offset, 9); goto L9; } + if (num3 < 100) { BinaryUtil.EnsureCapacity(ref buffer, offset, 10); goto L10; } + if (num3 < 1000) { BinaryUtil.EnsureCapacity(ref buffer, offset, 11); goto L11; } + BinaryUtil.EnsureCapacity(ref buffer, offset, 12); goto L12; + } + else + { + num4 = num3 / 10000; + num3 -= num4 * 10000; + if (num4 < 10000) + { + if (num4 < 10) { BinaryUtil.EnsureCapacity(ref buffer, offset, 13); goto L13; } + if (num4 < 100) { BinaryUtil.EnsureCapacity(ref buffer, offset, 14); goto L14; } + if (num4 < 1000) { BinaryUtil.EnsureCapacity(ref buffer, offset, 15); goto L15; } + BinaryUtil.EnsureCapacity(ref buffer, offset, 16); goto L16; + } + else + { + num5 = num4 / 10000; + num4 -= num5 * 10000; + if (num5 < 10000) + { + if (num5 < 10) { BinaryUtil.EnsureCapacity(ref buffer, offset, 17); goto L17; } + if (num5 < 100) { BinaryUtil.EnsureCapacity(ref buffer, offset, 18); goto L18; } + if (num5 < 1000) { BinaryUtil.EnsureCapacity(ref buffer, offset, 19); goto L19; } + BinaryUtil.EnsureCapacity(ref buffer, offset, 20); goto L20; + } + L20: + buffer[offset++] = (byte)('0' + (div = (num5 * 8389UL) >> 23)); + num5 -= div * 1000; + L19: + buffer[offset++] = (byte)('0' + (div = (num5 * 5243UL) >> 19)); + num5 -= div * 100; + L18: + buffer[offset++] = (byte)('0' + (div = (num5 * 6554UL) >> 16)); + num5 -= div * 10; + L17: + buffer[offset++] = (byte)('0' + (num5)); + } + L16: + buffer[offset++] = (byte)('0' + (div = (num4 * 8389UL) >> 23)); + num4 -= div * 1000; + L15: + buffer[offset++] = (byte)('0' + (div = (num4 * 5243UL) >> 19)); + num4 -= div * 100; + L14: + buffer[offset++] = (byte)('0' + (div = (num4 * 6554UL) >> 16)); + num4 -= div * 10; + L13: + buffer[offset++] = (byte)('0' + (num4)); + } + L12: + buffer[offset++] = (byte)('0' + (div = (num3 * 8389UL) >> 23)); + num3 -= div * 1000; + L11: + buffer[offset++] = (byte)('0' + (div = (num3 * 5243UL) >> 19)); + num3 -= div * 100; + L10: + buffer[offset++] = (byte)('0' + (div = (num3 * 6554UL) >> 16)); + num3 -= div * 10; + L9: + buffer[offset++] = (byte)('0' + (num3)); + } + L8: + buffer[offset++] = (byte)('0' + (div = (num2 * 8389UL) >> 23)); + num2 -= div * 1000; + L7: + buffer[offset++] = (byte)('0' + (div = (num2 * 5243UL) >> 19)); + num2 -= div * 100; + L6: + buffer[offset++] = (byte)('0' + (div = (num2 * 6554UL) >> 16)); + num2 -= div * 10; + L5: + buffer[offset++] = (byte)('0' + (num2)); + } + L4: + buffer[offset++] = (byte)('0' + (div = (num1 * 8389UL) >> 23)); + num1 -= div * 1000; + L3: + buffer[offset++] = (byte)('0' + (div = (num1 * 5243UL) >> 19)); + num1 -= div * 100; + L2: + buffer[offset++] = (byte)('0' + (div = (num1 * 6554UL) >> 16)); + num1 -= div * 10; + L1: + buffer[offset++] = (byte)('0' + (num1)); + + return offset - startOffset; + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static int WriteSByte(ref byte[] buffer, int offset, sbyte value) + { + return WriteInt64(ref buffer, offset, (long)value); + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static int WriteInt16(ref byte[] buffer, int offset, short value) + { + return WriteInt64(ref buffer, offset, (long)value); + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static int WriteInt32(ref byte[] buffer, int offset, int value) + { + return WriteInt64(ref buffer, offset, (long)value); + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static int WriteInt64(ref byte[] buffer, int offset, long value) + { + var startOffset = offset; + + long num1 = value, num2, num3, num4, num5, div; + + if (value < 0) + { + if (value == long.MinValue) // -9223372036854775808 + { + BinaryUtil.EnsureCapacity(ref buffer, offset, 20); + buffer[offset++] = (byte)'-'; + buffer[offset++] = (byte)'9'; + buffer[offset++] = (byte)'2'; + buffer[offset++] = (byte)'2'; + buffer[offset++] = (byte)'3'; + buffer[offset++] = (byte)'3'; + buffer[offset++] = (byte)'7'; + buffer[offset++] = (byte)'2'; + buffer[offset++] = (byte)'0'; + buffer[offset++] = (byte)'3'; + buffer[offset++] = (byte)'6'; + buffer[offset++] = (byte)'8'; + buffer[offset++] = (byte)'5'; + buffer[offset++] = (byte)'4'; + buffer[offset++] = (byte)'7'; + buffer[offset++] = (byte)'7'; + buffer[offset++] = (byte)'5'; + buffer[offset++] = (byte)'8'; + buffer[offset++] = (byte)'0'; + buffer[offset++] = (byte)'8'; + return offset - startOffset; + } + + BinaryUtil.EnsureCapacity(ref buffer, offset, 1); + buffer[offset++] = (byte)'-'; + num1 = unchecked(-value); + } + + // WriteUInt64(inlined) + + if (num1 < 10000) + { + if (num1 < 10) { BinaryUtil.EnsureCapacity(ref buffer, offset, 1); goto L1; } + if (num1 < 100) { BinaryUtil.EnsureCapacity(ref buffer, offset, 2); goto L2; } + if (num1 < 1000) { BinaryUtil.EnsureCapacity(ref buffer, offset, 3); goto L3; } + BinaryUtil.EnsureCapacity(ref buffer, offset, 4); goto L4; + } + else + { + num2 = num1 / 10000; + num1 -= num2 * 10000; + if (num2 < 10000) + { + if (num2 < 10) { BinaryUtil.EnsureCapacity(ref buffer, offset, 5); goto L5; } + if (num2 < 100) { BinaryUtil.EnsureCapacity(ref buffer, offset, 6); goto L6; } + if (num2 < 1000) { BinaryUtil.EnsureCapacity(ref buffer, offset, 7); goto L7; } + BinaryUtil.EnsureCapacity(ref buffer, offset, 8); goto L8; + } + else + { + num3 = num2 / 10000; + num2 -= num3 * 10000; + if (num3 < 10000) + { + if (num3 < 10) { BinaryUtil.EnsureCapacity(ref buffer, offset, 9); goto L9; } + if (num3 < 100) { BinaryUtil.EnsureCapacity(ref buffer, offset, 10); goto L10; } + if (num3 < 1000) { BinaryUtil.EnsureCapacity(ref buffer, offset, 11); goto L11; } + BinaryUtil.EnsureCapacity(ref buffer, offset, 12); goto L12; + } + else + { + num4 = num3 / 10000; + num3 -= num4 * 10000; + if (num4 < 10000) + { + if (num4 < 10) { BinaryUtil.EnsureCapacity(ref buffer, offset, 13); goto L13; } + if (num4 < 100) { BinaryUtil.EnsureCapacity(ref buffer, offset, 14); goto L14; } + if (num4 < 1000) { BinaryUtil.EnsureCapacity(ref buffer, offset, 15); goto L15; } + BinaryUtil.EnsureCapacity(ref buffer, offset, 16); goto L16; + } + else + { + num5 = num4 / 10000; + num4 -= num5 * 10000; + if (num5 < 10000) + { + if (num5 < 10) { BinaryUtil.EnsureCapacity(ref buffer, offset, 17); goto L17; } + if (num5 < 100) { BinaryUtil.EnsureCapacity(ref buffer, offset, 18); goto L18; } + if (num5 < 1000) { BinaryUtil.EnsureCapacity(ref buffer, offset, 19); goto L19; } + BinaryUtil.EnsureCapacity(ref buffer, offset, 20); goto L20; + } + L20: + buffer[offset++] = (byte)('0' + (div = (num5 * 8389L) >> 23)); + num5 -= div * 1000; + L19: + buffer[offset++] = (byte)('0' + (div = (num5 * 5243L) >> 19)); + num5 -= div * 100; + L18: + buffer[offset++] = (byte)('0' + (div = (num5 * 6554L) >> 16)); + num5 -= div * 10; + L17: + buffer[offset++] = (byte)('0' + (num5)); + } + L16: + buffer[offset++] = (byte)('0' + (div = (num4 * 8389L) >> 23)); + num4 -= div * 1000; + L15: + buffer[offset++] = (byte)('0' + (div = (num4 * 5243L) >> 19)); + num4 -= div * 100; + L14: + buffer[offset++] = (byte)('0' + (div = (num4 * 6554L) >> 16)); + num4 -= div * 10; + L13: + buffer[offset++] = (byte)('0' + (num4)); + } + L12: + buffer[offset++] = (byte)('0' + (div = (num3 * 8389L) >> 23)); + num3 -= div * 1000; + L11: + buffer[offset++] = (byte)('0' + (div = (num3 * 5243L) >> 19)); + num3 -= div * 100; + L10: + buffer[offset++] = (byte)('0' + (div = (num3 * 6554L) >> 16)); + num3 -= div * 10; + L9: + buffer[offset++] = (byte)('0' + (num3)); + } + L8: + buffer[offset++] = (byte)('0' + (div = (num2 * 8389L) >> 23)); + num2 -= div * 1000; + L7: + buffer[offset++] = (byte)('0' + (div = (num2 * 5243L) >> 19)); + num2 -= div * 100; + L6: + buffer[offset++] = (byte)('0' + (div = (num2 * 6554L) >> 16)); + num2 -= div * 10; + L5: + buffer[offset++] = (byte)('0' + (num2)); + } + L4: + buffer[offset++] = (byte)('0' + (div = (num1 * 8389L) >> 23)); + num1 -= div * 1000; + L3: + buffer[offset++] = (byte)('0' + (div = (num1 * 5243L) >> 19)); + num1 -= div * 100; + L2: + buffer[offset++] = (byte)('0' + (div = (num1 * 6554L) >> 16)); + num1 -= div * 10; + L1: + buffer[offset++] = (byte)('0' + (num1)); + + return offset - startOffset; + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static int WriteSingle(ref byte[] bytes, int offset, float value) + { + return DoubleToStringConverter.GetBytes(ref bytes, offset, value); + } +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static int WriteDouble(ref byte[] bytes, int offset, double value) + { + return DoubleToStringConverter.GetBytes(ref bytes, offset, value); + } + + // boolean is not number:) + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static bool ReadBoolean(byte[] bytes, int offset, out int readCount) + { + if (bytes[offset] == 't') + { + if (bytes[offset + 1] != 'r') goto ERROR_TRUE; + if (bytes[offset + 2] != 'u') goto ERROR_TRUE; + if (bytes[offset + 3] != 'e') goto ERROR_TRUE; + readCount = 4; + return true; + } + else if (bytes[offset] == 'f') + { + if (bytes[offset + 1] != 'a') goto ERROR_FALSE; + if (bytes[offset + 2] != 'l') goto ERROR_FALSE; + if (bytes[offset + 3] != 's') goto ERROR_FALSE; + if (bytes[offset + 4] != 'e') goto ERROR_FALSE; + readCount = 5; + return false; + } + else + { + throw new InvalidOperationException("value is not boolean."); + } + + ERROR_TRUE: + throw new InvalidOperationException("value is not boolean(true)."); + ERROR_FALSE: + throw new InvalidOperationException("value is not boolean(false)."); + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Internal/ReflectionExtensions.cs b/Unity3D/3rdLib/Utf8Json/Internal/ReflectionExtensions.cs new file mode 100644 index 0000000..93e1692 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/ReflectionExtensions.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Utf8Json.Internal +{ + internal static class ReflectionExtensions + { + public static bool IsNullable(this System.Reflection.TypeInfo type) + { + return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(System.Nullable<>); + } + + public static bool IsPublic(this System.Reflection.TypeInfo type) + { + return type.IsPublic; + } + + public static bool IsAnonymous(this System.Reflection.TypeInfo type) + { + return type.GetCustomAttribute() != null + && type.Name.Contains("AnonymousType") + && (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$")) + && (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic; + } + + public static IEnumerable GetAllProperties(this Type type) + { + return GetAllPropertiesCore(type, new HashSet()); + } + + static IEnumerable GetAllPropertiesCore(Type type, HashSet nameCheck) + { + foreach (var item in type.GetRuntimeProperties()) + { + if (nameCheck.Add(item.Name)) + { + yield return item; + } + } + if (type.BaseType != null) + { + foreach (var item in GetAllPropertiesCore(type.BaseType, nameCheck)) + { + yield return item; + } + } + } + + public static IEnumerable GetAllFields(this Type type) + { + return GetAllFieldsCore(type, new HashSet()); + } + + static IEnumerable GetAllFieldsCore(Type type, HashSet nameCheck) + { + foreach (var item in type.GetRuntimeFields()) + { + if (nameCheck.Add(item.Name)) + { + yield return item; + } + } + if (type.BaseType != null) + { + foreach (var item in GetAllFieldsCore(type.BaseType, nameCheck)) + { + yield return item; + } + } + } + +#if NETSTANDARD + + public static bool IsConstructedGenericType(this System.Reflection.TypeInfo type) + { + return type.AsType().IsConstructedGenericType; + } + + public static MethodInfo GetGetMethod(this PropertyInfo propInfo) + { + return propInfo.GetMethod; + } + + public static MethodInfo GetSetMethod(this PropertyInfo propInfo) + { + return propInfo.SetMethod; + } + +#endif + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/StringEncoding.cs b/Unity3D/3rdLib/Utf8Json/Internal/StringEncoding.cs new file mode 100644 index 0000000..182f8bb --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/StringEncoding.cs @@ -0,0 +1,9 @@ +using System.Text; + +namespace Utf8Json.Internal +{ + internal static class StringEncoding + { + public static readonly Encoding UTF8 = new UTF8Encoding(false); + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/StringMutator.cs b/Unity3D/3rdLib/Utf8Json/Internal/StringMutator.cs new file mode 100644 index 0000000..3ff3d52 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/StringMutator.cs @@ -0,0 +1,69 @@ +using System; +using System.Text; + +namespace Utf8Json.Internal +{ + internal static class StringMutator + { + /// + /// MyProperty -> MyProperty + /// + public static string Original(string s) + { + return s; + } + + /// + /// MyProperty -> myProperty + /// + public static string ToCamelCase(string s) + { + if (string.IsNullOrEmpty(s) || char.IsLower(s, 0)) + { + return s; + } + + var array = s.ToCharArray(); + array[0] = char.ToLowerInvariant(array[0]); + return new string(array); + } + + /// + /// MyProperty -> my_property + /// + public static string ToSnakeCase(string s) + { + if (string.IsNullOrEmpty(s)) return s; + + var sb = new StringBuilder(); + for (int i = 0; i < s.Length; i++) + { + var c = s[i]; + + if (Char.IsUpper(c)) + { + // first + if (i == 0) + { + sb.Append(char.ToLowerInvariant(c)); + } + else if (char.IsUpper(s[i - 1])) // WriteIO => write_io + { + sb.Append(char.ToLowerInvariant(c)); + } + else + { + sb.Append("_"); + sb.Append(char.ToLowerInvariant(c)); + } + } + else + { + sb.Append(c); + } + } + + return sb.ToString(); + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Internal/ThreadsafeTypeKeyHashTable.cs b/Unity3D/3rdLib/Utf8Json/Internal/ThreadsafeTypeKeyHashTable.cs new file mode 100644 index 0000000..d54477d --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/ThreadsafeTypeKeyHashTable.cs @@ -0,0 +1,232 @@ +using System; + +namespace Utf8Json.Internal +{ + // Safe for multiple-read, single-write. + internal class ThreadsafeTypeKeyHashTable + { + Entry[] buckets; + int size; // only use in writer lock + + readonly object writerLock = new object(); + readonly float loadFactor; + + // IEqualityComparer.Equals is overhead if key only Type, don't use it. + // readonly IEqualityComparer comparer; + + public ThreadsafeTypeKeyHashTable(int capacity = 4, float loadFactor = 0.75f) + { + var tableSize = CalculateCapacity(capacity, loadFactor); + this.buckets = new Entry[tableSize]; + this.loadFactor = loadFactor; + } + + public bool TryAdd(Type key, TValue value) + { + return TryAdd(key, _ => value); // create lambda capture + } + + public bool TryAdd(Type key, Func valueFactory) + { + TValue _; + return TryAddInternal(key, valueFactory, out _); + } + + bool TryAddInternal(Type key, Func valueFactory, out TValue resultingValue) + { + lock (writerLock) + { + var nextCapacity = CalculateCapacity(size + 1, loadFactor); + + if (buckets.Length < nextCapacity) + { + // rehash + var nextBucket = new Entry[nextCapacity]; + for (int i = 0; i < buckets.Length; i++) + { + var e = buckets[i]; + while (e != null) + { + var newEntry = new Entry { Key = e.Key, Value = e.Value, Hash = e.Hash }; + AddToBuckets(nextBucket, key, newEntry, null, out resultingValue); + e = e.Next; + } + } + + // add entry(if failed to add, only do resize) + var successAdd = AddToBuckets(nextBucket, key, null, valueFactory, out resultingValue); + + // replace field(threadsafe for read) + VolatileWrite(ref buckets, nextBucket); + + if (successAdd) size++; + return successAdd; + } + else + { + // add entry(insert last is thread safe for read) + var successAdd = AddToBuckets(buckets, key, null, valueFactory, out resultingValue); + if (successAdd) size++; + return successAdd; + } + } + } + + bool AddToBuckets(Entry[] buckets, Type newKey, Entry newEntryOrNull, Func valueFactory, out TValue resultingValue) + { + var h = (newEntryOrNull != null) ? newEntryOrNull.Hash : newKey.GetHashCode(); + if (buckets[h & (buckets.Length - 1)] == null) + { + if (newEntryOrNull != null) + { + resultingValue = newEntryOrNull.Value; + VolatileWrite(ref buckets[h & (buckets.Length - 1)], newEntryOrNull); + } + else + { + resultingValue = valueFactory(newKey); + VolatileWrite(ref buckets[h & (buckets.Length - 1)], new Entry { Key = newKey, Value = resultingValue, Hash = h }); + } + } + else + { + var searchLastEntry = buckets[h & (buckets.Length - 1)]; + while (true) + { + if (searchLastEntry.Key == newKey) + { + resultingValue = searchLastEntry.Value; + return false; + } + + if (searchLastEntry.Next == null) + { + if (newEntryOrNull != null) + { + resultingValue = newEntryOrNull.Value; + VolatileWrite(ref searchLastEntry.Next, newEntryOrNull); + } + else + { + resultingValue = valueFactory(newKey); + VolatileWrite(ref searchLastEntry.Next, new Entry { Key = newKey, Value = resultingValue, Hash = h }); + } + break; + } + searchLastEntry = searchLastEntry.Next; + } + } + + return true; + } + + public bool TryGetValue(Type key, out TValue value) + { + var table = buckets; + var hash = key.GetHashCode(); + var entry = table[hash & table.Length - 1]; + + if (entry == null) goto NOT_FOUND; + + if (entry.Key == key) + { + value = entry.Value; + return true; + } + + var next = entry.Next; + while (next != null) + { + if (next.Key == key) + { + value = next.Value; + return true; + } + next = next.Next; + } + + NOT_FOUND: + value = default(TValue); + return false; + } + + public TValue GetOrAdd(Type key, Func valueFactory) + { + TValue v; + if (TryGetValue(key, out v)) + { + return v; + } + + TryAddInternal(key, valueFactory, out v); + return v; + } + + static int CalculateCapacity(int collectionSize, float loadFactor) + { + var initialCapacity = (int)(((float)collectionSize) / loadFactor); + var capacity = 1; + while (capacity < initialCapacity) + { + capacity <<= 1; + } + + if (capacity < 8) + { + return 8; + } + + return capacity; + } + + static void VolatileWrite(ref Entry location, Entry value) + { +#if NETSTANDARD + System.Threading.Volatile.Write(ref location, value); +#elif UNITY_METRO || UNITY_WSA + System.Threading.Volatile.Write(ref location, value); +#else + System.Threading.Thread.MemoryBarrier(); + location = value; +#endif + } + + static void VolatileWrite(ref Entry[] location, Entry[] value) + { +#if NETSTANDARD + System.Threading.Volatile.Write(ref location, value); +#elif UNITY_METRO || UNITY_WSA + System.Threading.Volatile.Write(ref location, value); +#else + System.Threading.Thread.MemoryBarrier(); + location = value; +#endif + } + + class Entry + { + public Type Key; + public TValue Value; + public int Hash; + public Entry Next; + + // debug only + public override string ToString() + { + return Key + "(" + Count() + ")"; + } + + int Count() + { + var count = 1; + var n = this; + while (n.Next != null) + { + count++; + n = n.Next; + } + return count; + } + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Internal/UnsafeMemory.Low.cs b/Unity3D/3rdLib/Utf8Json/Internal/UnsafeMemory.Low.cs new file mode 100644 index 0000000..46cad94 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/UnsafeMemory.Low.cs @@ -0,0 +1,224 @@ +#if NETSTANDARD + +using System; +using System.Runtime.CompilerServices; + +namespace Utf8Json.Internal +{ + // for string key property name write optimization. + + public static class UnsafeMemory + { + public static readonly bool Is32Bit = (IntPtr.Size == 4); + + public static void WriteRaw(ref JsonWriter writer, byte[] src) + { + switch (src.Length) + { + case 0: break; + case 1: if (Is32Bit) { UnsafeMemory32.WriteRaw1(ref writer, src); } else { UnsafeMemory64.WriteRaw1(ref writer, src); } break; + case 2: if (Is32Bit) { UnsafeMemory32.WriteRaw2(ref writer, src); } else { UnsafeMemory64.WriteRaw2(ref writer, src); } break; + case 3: if (Is32Bit) { UnsafeMemory32.WriteRaw3(ref writer, src); } else { UnsafeMemory64.WriteRaw3(ref writer, src); } break; + case 4: if (Is32Bit) { UnsafeMemory32.WriteRaw4(ref writer, src); } else { UnsafeMemory64.WriteRaw4(ref writer, src); } break; + case 5: if (Is32Bit) { UnsafeMemory32.WriteRaw5(ref writer, src); } else { UnsafeMemory64.WriteRaw5(ref writer, src); } break; + case 6: if (Is32Bit) { UnsafeMemory32.WriteRaw6(ref writer, src); } else { UnsafeMemory64.WriteRaw6(ref writer, src); } break; + case 7: if (Is32Bit) { UnsafeMemory32.WriteRaw7(ref writer, src); } else { UnsafeMemory64.WriteRaw7(ref writer, src); } break; + case 8: if (Is32Bit) { UnsafeMemory32.WriteRaw8(ref writer, src); } else { UnsafeMemory64.WriteRaw8(ref writer, src); } break; + case 9: if (Is32Bit) { UnsafeMemory32.WriteRaw9(ref writer, src); } else { UnsafeMemory64.WriteRaw9(ref writer, src); } break; + case 10: if (Is32Bit) { UnsafeMemory32.WriteRaw10(ref writer, src); } else { UnsafeMemory64.WriteRaw10(ref writer, src); } break; + case 11: if (Is32Bit) { UnsafeMemory32.WriteRaw11(ref writer, src); } else { UnsafeMemory64.WriteRaw11(ref writer, src); } break; + case 12: if (Is32Bit) { UnsafeMemory32.WriteRaw12(ref writer, src); } else { UnsafeMemory64.WriteRaw12(ref writer, src); } break; + case 13: if (Is32Bit) { UnsafeMemory32.WriteRaw13(ref writer, src); } else { UnsafeMemory64.WriteRaw13(ref writer, src); } break; + case 14: if (Is32Bit) { UnsafeMemory32.WriteRaw14(ref writer, src); } else { UnsafeMemory64.WriteRaw14(ref writer, src); } break; + case 15: if (Is32Bit) { UnsafeMemory32.WriteRaw15(ref writer, src); } else { UnsafeMemory64.WriteRaw15(ref writer, src); } break; + case 16: if (Is32Bit) { UnsafeMemory32.WriteRaw16(ref writer, src); } else { UnsafeMemory64.WriteRaw16(ref writer, src); } break; + case 17: if (Is32Bit) { UnsafeMemory32.WriteRaw17(ref writer, src); } else { UnsafeMemory64.WriteRaw17(ref writer, src); } break; + case 18: if (Is32Bit) { UnsafeMemory32.WriteRaw18(ref writer, src); } else { UnsafeMemory64.WriteRaw18(ref writer, src); } break; + case 19: if (Is32Bit) { UnsafeMemory32.WriteRaw19(ref writer, src); } else { UnsafeMemory64.WriteRaw19(ref writer, src); } break; + case 20: if (Is32Bit) { UnsafeMemory32.WriteRaw20(ref writer, src); } else { UnsafeMemory64.WriteRaw20(ref writer, src); } break; + case 21: if (Is32Bit) { UnsafeMemory32.WriteRaw21(ref writer, src); } else { UnsafeMemory64.WriteRaw21(ref writer, src); } break; + case 22: if (Is32Bit) { UnsafeMemory32.WriteRaw22(ref writer, src); } else { UnsafeMemory64.WriteRaw22(ref writer, src); } break; + case 23: if (Is32Bit) { UnsafeMemory32.WriteRaw23(ref writer, src); } else { UnsafeMemory64.WriteRaw23(ref writer, src); } break; + case 24: if (Is32Bit) { UnsafeMemory32.WriteRaw24(ref writer, src); } else { UnsafeMemory64.WriteRaw24(ref writer, src); } break; + case 25: if (Is32Bit) { UnsafeMemory32.WriteRaw25(ref writer, src); } else { UnsafeMemory64.WriteRaw25(ref writer, src); } break; + case 26: if (Is32Bit) { UnsafeMemory32.WriteRaw26(ref writer, src); } else { UnsafeMemory64.WriteRaw26(ref writer, src); } break; + case 27: if (Is32Bit) { UnsafeMemory32.WriteRaw27(ref writer, src); } else { UnsafeMemory64.WriteRaw27(ref writer, src); } break; + case 28: if (Is32Bit) { UnsafeMemory32.WriteRaw28(ref writer, src); } else { UnsafeMemory64.WriteRaw28(ref writer, src); } break; + case 29: if (Is32Bit) { UnsafeMemory32.WriteRaw29(ref writer, src); } else { UnsafeMemory64.WriteRaw29(ref writer, src); } break; + case 30: if (Is32Bit) { UnsafeMemory32.WriteRaw30(ref writer, src); } else { UnsafeMemory64.WriteRaw30(ref writer, src); } break; + case 31: if (Is32Bit) { UnsafeMemory32.WriteRaw31(ref writer, src); } else { UnsafeMemory64.WriteRaw31(ref writer, src); } break; + default: + MemoryCopy(ref writer, src); + break; + } + } + + public static unsafe void MemoryCopy(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); +#if !NET45 + fixed (void* dstP = &writer.buffer[writer.offset]) + fixed (void* srcP = &src[0]) + { + Buffer.MemoryCopy(srcP, dstP, writer.buffer.Length - writer.offset, src.Length); + } +#else + Buffer.BlockCopy(src, 0, writer.buffer, writer.offset, src.Length); +#endif + writer.offset += src.Length; + } + } + + public static partial class UnsafeMemory32 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw1(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(byte*)pDst = *(byte*)pSrc; + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw2(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(short*)pDst = *(short*)pSrc; + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw3(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(byte*)pDst = *(byte*)pSrc; + *(short*)(pDst + 1) = *(short*)(pSrc + 1); + } + + writer.offset += src.Length; + } + } + + public static partial class UnsafeMemory64 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw1(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(byte*)pDst = *(byte*)pSrc; + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw2(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(short*)pDst = *(short*)pSrc; + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw3(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(byte*)pDst = *(byte*)pSrc; + *(short*)(pDst + 1) = *(short*)(pSrc + 1); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw4(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw5(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 1) = *(int*)(pSrc + 1); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw6(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 2) = *(int*)(pSrc + 2); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw7(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 3) = *(int*)(pSrc + 3); + } + + writer.offset += src.Length; + } + } +} + +#endif \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Internal/UnsafeMemory.cs b/Unity3D/3rdLib/Utf8Json/Internal/UnsafeMemory.cs new file mode 100644 index 0000000..f4cba08 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Internal/UnsafeMemory.cs @@ -0,0 +1,894 @@ +#if NETSTANDARD + +using System.Runtime.CompilerServices; + +namespace Utf8Json.Internal +{ + public static partial class UnsafeMemory32 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw4(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw5(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 1) = *(int*)(pSrc + 1); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw6(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 2) = *(int*)(pSrc + 2); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw7(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 3) = *(int*)(pSrc + 3); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw8(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw9(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 5) = *(int*)(pSrc + 5); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw10(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 6) = *(int*)(pSrc + 6); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw11(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 7) = *(int*)(pSrc + 7); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw12(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw13(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 9) = *(int*)(pSrc + 9); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw14(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 10) = *(int*)(pSrc + 10); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw15(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 11) = *(int*)(pSrc + 11); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw16(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 12) = *(int*)(pSrc + 12); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw17(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 12) = *(int*)(pSrc + 12); + *(int*)(pDst + 13) = *(int*)(pSrc + 13); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw18(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 12) = *(int*)(pSrc + 12); + *(int*)(pDst + 14) = *(int*)(pSrc + 14); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw19(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 12) = *(int*)(pSrc + 12); + *(int*)(pDst + 15) = *(int*)(pSrc + 15); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw20(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 12) = *(int*)(pSrc + 12); + *(int*)(pDst + 16) = *(int*)(pSrc + 16); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw21(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 12) = *(int*)(pSrc + 12); + *(int*)(pDst + 16) = *(int*)(pSrc + 16); + *(int*)(pDst + 17) = *(int*)(pSrc + 17); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw22(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 12) = *(int*)(pSrc + 12); + *(int*)(pDst + 16) = *(int*)(pSrc + 16); + *(int*)(pDst + 18) = *(int*)(pSrc + 18); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw23(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 12) = *(int*)(pSrc + 12); + *(int*)(pDst + 16) = *(int*)(pSrc + 16); + *(int*)(pDst + 19) = *(int*)(pSrc + 19); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw24(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 12) = *(int*)(pSrc + 12); + *(int*)(pDst + 16) = *(int*)(pSrc + 16); + *(int*)(pDst + 20) = *(int*)(pSrc + 20); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw25(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 12) = *(int*)(pSrc + 12); + *(int*)(pDst + 16) = *(int*)(pSrc + 16); + *(int*)(pDst + 20) = *(int*)(pSrc + 20); + *(int*)(pDst + 21) = *(int*)(pSrc + 21); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw26(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 12) = *(int*)(pSrc + 12); + *(int*)(pDst + 16) = *(int*)(pSrc + 16); + *(int*)(pDst + 20) = *(int*)(pSrc + 20); + *(int*)(pDst + 22) = *(int*)(pSrc + 22); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw27(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 12) = *(int*)(pSrc + 12); + *(int*)(pDst + 16) = *(int*)(pSrc + 16); + *(int*)(pDst + 20) = *(int*)(pSrc + 20); + *(int*)(pDst + 23) = *(int*)(pSrc + 23); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw28(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 12) = *(int*)(pSrc + 12); + *(int*)(pDst + 16) = *(int*)(pSrc + 16); + *(int*)(pDst + 20) = *(int*)(pSrc + 20); + *(int*)(pDst + 24) = *(int*)(pSrc + 24); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw29(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 12) = *(int*)(pSrc + 12); + *(int*)(pDst + 16) = *(int*)(pSrc + 16); + *(int*)(pDst + 20) = *(int*)(pSrc + 20); + *(int*)(pDst + 24) = *(int*)(pSrc + 24); + *(int*)(pDst + 25) = *(int*)(pSrc + 25); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw30(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 12) = *(int*)(pSrc + 12); + *(int*)(pDst + 16) = *(int*)(pSrc + 16); + *(int*)(pDst + 20) = *(int*)(pSrc + 20); + *(int*)(pDst + 24) = *(int*)(pSrc + 24); + *(int*)(pDst + 26) = *(int*)(pSrc + 26); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw31(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(int*)(pDst + 0) = *(int*)(pSrc + 0); + *(int*)(pDst + 4) = *(int*)(pSrc + 4); + *(int*)(pDst + 8) = *(int*)(pSrc + 8); + *(int*)(pDst + 12) = *(int*)(pSrc + 12); + *(int*)(pDst + 16) = *(int*)(pSrc + 16); + *(int*)(pDst + 20) = *(int*)(pSrc + 20); + *(int*)(pDst + 24) = *(int*)(pSrc + 24); + *(int*)(pDst + 27) = *(int*)(pSrc + 27); + } + + writer.offset += src.Length; + } + + } + + public static partial class UnsafeMemory64 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw8(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw9(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 1) = *(long*)(pSrc + 1); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw10(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 2) = *(long*)(pSrc + 2); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw11(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 3) = *(long*)(pSrc + 3); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw12(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 4) = *(long*)(pSrc + 4); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw13(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 5) = *(long*)(pSrc + 5); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw14(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 6) = *(long*)(pSrc + 6); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw15(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 7) = *(long*)(pSrc + 7); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw16(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 8) = *(long*)(pSrc + 8); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw17(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 8) = *(long*)(pSrc + 8); + *(long*)(pDst + 9) = *(long*)(pSrc + 9); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw18(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 8) = *(long*)(pSrc + 8); + *(long*)(pDst + 10) = *(long*)(pSrc + 10); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw19(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 8) = *(long*)(pSrc + 8); + *(long*)(pDst + 11) = *(long*)(pSrc + 11); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw20(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 8) = *(long*)(pSrc + 8); + *(long*)(pDst + 12) = *(long*)(pSrc + 12); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw21(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 8) = *(long*)(pSrc + 8); + *(long*)(pDst + 13) = *(long*)(pSrc + 13); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw22(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 8) = *(long*)(pSrc + 8); + *(long*)(pDst + 14) = *(long*)(pSrc + 14); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw23(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 8) = *(long*)(pSrc + 8); + *(long*)(pDst + 15) = *(long*)(pSrc + 15); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw24(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 8) = *(long*)(pSrc + 8); + *(long*)(pDst + 16) = *(long*)(pSrc + 16); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw25(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 8) = *(long*)(pSrc + 8); + *(long*)(pDst + 16) = *(long*)(pSrc + 16); + *(long*)(pDst + 17) = *(long*)(pSrc + 17); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw26(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 8) = *(long*)(pSrc + 8); + *(long*)(pDst + 16) = *(long*)(pSrc + 16); + *(long*)(pDst + 18) = *(long*)(pSrc + 18); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw27(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 8) = *(long*)(pSrc + 8); + *(long*)(pDst + 16) = *(long*)(pSrc + 16); + *(long*)(pDst + 19) = *(long*)(pSrc + 19); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw28(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 8) = *(long*)(pSrc + 8); + *(long*)(pDst + 16) = *(long*)(pSrc + 16); + *(long*)(pDst + 20) = *(long*)(pSrc + 20); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw29(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 8) = *(long*)(pSrc + 8); + *(long*)(pDst + 16) = *(long*)(pSrc + 16); + *(long*)(pDst + 21) = *(long*)(pSrc + 21); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw30(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 8) = *(long*)(pSrc + 8); + *(long*)(pDst + 16) = *(long*)(pSrc + 16); + *(long*)(pDst + 22) = *(long*)(pSrc + 22); + } + + writer.offset += src.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteRaw31(ref JsonWriter writer, byte[] src) + { + BinaryUtil.EnsureCapacity(ref writer.buffer, writer.offset, src.Length); + + fixed (byte* pSrc = &src[0]) + fixed (byte* pDst = &writer.buffer[writer.offset]) + { + *(long*)(pDst + 0) = *(long*)(pSrc + 0); + *(long*)(pDst + 8) = *(long*)(pSrc + 8); + *(long*)(pDst + 16) = *(long*)(pSrc + 16); + *(long*)(pDst + 23) = *(long*)(pSrc + 23); + } + + writer.offset += src.Length; + } + + } +} + +#endif \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/JsonReader.cs b/Unity3D/3rdLib/Utf8Json/JsonReader.cs new file mode 100644 index 0000000..e0117ff --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/JsonReader.cs @@ -0,0 +1,1294 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Utf8Json.Internal; + +#if NETSTANDARD +using System.Runtime.CompilerServices; +#endif + +namespace Utf8Json +{ + // JSON RFC: https://www.ietf.org/rfc/rfc4627.txt + + public struct JsonReader + { + static readonly ArraySegment nullTokenSegment = new ArraySegment(new byte[] { 110, 117, 108, 108 }, 0, 4); + static readonly byte[] bom = Encoding.UTF8.GetPreamble(); + + + readonly byte[] bytes; + int offset; + + public JsonReader(byte[] bytes) + : this(bytes, 0) + { + + } + + public JsonReader(byte[] bytes, int offset) + { + this.bytes = bytes; + this.offset = offset; + + // skip bom + if (bytes.Length >= 3) + { + if (bytes[offset] == bom[0] && bytes[offset + 1] == bom[1] && bytes[offset + 2] == bom[2]) + { + this.offset = offset += 3; + } + } + } + + JsonParsingException CreateParsingException(string expected) + { + var actual = ((char)bytes[offset]).ToString(); + var pos = offset; + + try + { + var token = GetCurrentJsonToken(); + switch (token) + { + case JsonToken.Number: + var ns = ReadNumberSegment(); + actual = StringEncoding.UTF8.GetString(ns.Array, ns.Offset, ns.Count); + break; + case JsonToken.String: + actual = "\"" + ReadString() + "\""; + break; + case JsonToken.True: + actual = "true"; + break; + case JsonToken.False: + actual = "false"; + break; + case JsonToken.Null: + actual = "null"; + break; + default: + break; + } + } + catch { } + + return new JsonParsingException("expected:'" + expected + "', actual:'" + actual + "', at offset:" + pos, bytes, pos, offset, actual); + } + + JsonParsingException CreateParsingExceptionMessage(string message) + { + var actual = ((char)bytes[offset]).ToString(); + var pos = offset; + + return new JsonParsingException(message, bytes, pos, pos, actual); + } + + bool IsInRange + { + get + { + return offset < bytes.Length; + } + } + + public void AdvanceOffset(int offset) + { + this.offset += offset; + } + + public byte[] GetBufferUnsafe() + { + return bytes; + } + + public int GetCurrentOffsetUnsafe() + { + return offset; + } + + public JsonToken GetCurrentJsonToken() + { + SkipWhiteSpace(); + if (offset < bytes.Length) + { + var c = bytes[offset]; + switch (c) + { + case (byte)'{': return JsonToken.BeginObject; + case (byte)'}': return JsonToken.EndObject; + case (byte)'[': return JsonToken.BeginArray; + case (byte)']': return JsonToken.EndArray; + case (byte)'t': return JsonToken.True; + case (byte)'f': return JsonToken.False; + case (byte)'n': return JsonToken.Null; + case (byte)',': return JsonToken.ValueSeparator; + case (byte)':': return JsonToken.NameSeparator; + case (byte)'-': return JsonToken.Number; + case (byte)'0': return JsonToken.Number; + case (byte)'1': return JsonToken.Number; + case (byte)'2': return JsonToken.Number; + case (byte)'3': return JsonToken.Number; + case (byte)'4': return JsonToken.Number; + case (byte)'5': return JsonToken.Number; + case (byte)'6': return JsonToken.Number; + case (byte)'7': return JsonToken.Number; + case (byte)'8': return JsonToken.Number; + case (byte)'9': return JsonToken.Number; + case (byte)'\"': return JsonToken.String; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + case 32: + case 33: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 46: + case 47: + case 59: + case 60: + case 61: + case 62: + case 63: + case 64: + case 65: + case 66: + case 67: + case 68: + case 69: + case 70: + case 71: + case 72: + case 73: + case 74: + case 75: + case 76: + case 77: + case 78: + case 79: + case 80: + case 81: + case 82: + case 83: + case 84: + case 85: + case 86: + case 87: + case 88: + case 89: + case 90: + case 92: + case 94: + case 95: + case 96: + case 97: + case 98: + case 99: + case 100: + case 101: + case 103: + case 104: + case 105: + case 106: + case 107: + case 108: + case 109: + case 111: + case 112: + case 113: + case 114: + case 115: + case 117: + case 118: + case 119: + case 120: + case 121: + case 122: + default: + return JsonToken.None; + } + } + else + { + return JsonToken.None; + } + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void SkipWhiteSpace() + { + // eliminate array bound check + for (int i = offset; i < bytes.Length; i++) + { + switch (bytes[i]) + { + case 0x20: // Space + case 0x09: // Horizontal tab + case 0x0A: // Line feed or New line + case 0x0D: // Carriage return + continue; + case (byte)'/': // BeginComment + i = ReadComment(bytes, i); + continue; + // optimize skip jumptable + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 11: + case 12: + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + default: + offset = i; + return; // end + } + } + + offset = bytes.Length; + } + + public bool ReadIsNull() + { + SkipWhiteSpace(); + if (IsInRange && bytes[offset] == 'n') + { + if (bytes[offset + 1] != 'u') goto ERROR; + if (bytes[offset + 2] != 'l') goto ERROR; + if (bytes[offset + 3] != 'l') goto ERROR; + offset += 4; + return true; + } + else + { + return false; + } + + ERROR: + throw CreateParsingException("null"); + } + + public bool ReadIsBeginArray() + { + SkipWhiteSpace(); + if (IsInRange && bytes[offset] == '[') + { + offset += 1; + return true; + } + else + { + return false; + } + } + + public void ReadIsBeginArrayWithVerify() + { + if (!ReadIsBeginArray()) throw CreateParsingException("["); + } + + public bool ReadIsEndArray() + { + SkipWhiteSpace(); + if (IsInRange && bytes[offset] == ']') + { + offset += 1; + return true; + } + else + { + return false; + } + } + + public void ReadIsEndArrayWithVerify() + { + if (!ReadIsEndArray()) throw CreateParsingException("]"); + } + + public bool ReadIsEndArrayWithSkipValueSeparator(ref int count) + { + SkipWhiteSpace(); + if (IsInRange && bytes[offset] == ']') + { + offset += 1; + return true; + } + else + { + if (count++ != 0) + { + ReadIsValueSeparatorWithVerify(); + } + return false; + } + } + + /// + /// Convinient pattern of ReadIsBeginArrayWithVerify + while(!ReadIsEndArrayWithSkipValueSeparator) + /// + public bool ReadIsInArray(ref int count) + { + if (count == 0) + { + ReadIsBeginArrayWithVerify(); + if (ReadIsEndArray()) + { + return false; + } + } + else + { + if (ReadIsEndArray()) + { + return false; + } + else + { + ReadIsValueSeparatorWithVerify(); + } + } + + count++; + return true; + } + + public bool ReadIsBeginObject() + { + SkipWhiteSpace(); + if (IsInRange && bytes[offset] == '{') + { + offset += 1; + return true; + } + else + { + return false; + } + } + + public void ReadIsBeginObjectWithVerify() + { + if (!ReadIsBeginObject()) throw CreateParsingException("{"); + } + + public bool ReadIsEndObject() + { + SkipWhiteSpace(); + if (IsInRange && bytes[offset] == '}') + { + offset += 1; + return true; + } + else + { + return false; + } + } + public void ReadIsEndObjectWithVerify() + { + if (!ReadIsEndObject()) throw CreateParsingException("}"); + } + + public bool ReadIsEndObjectWithSkipValueSeparator(ref int count) + { + SkipWhiteSpace(); + if (IsInRange && bytes[offset] == '}') + { + offset += 1; + return true; + } + else + { + if (count++ != 0) + { + ReadIsValueSeparatorWithVerify(); + } + return false; + } + } + + /// + /// Convinient pattern of ReadIsBeginObjectWithVerify + while(!ReadIsEndObjectWithSkipValueSeparator) + /// + public bool ReadIsInObject(ref int count) + { + if (count == 0) + { + ReadIsBeginObjectWithVerify(); + if (ReadIsEndObject()) + { + return false; + } + } + else + { + if (ReadIsEndObject()) + { + return false; + } + else + { + ReadIsValueSeparatorWithVerify(); + } + } + + count++; + return true; + } + + public bool ReadIsValueSeparator() + { + SkipWhiteSpace(); + if (IsInRange && bytes[offset] == ',') + { + offset += 1; + return true; + } + else + { + return false; + } + } + + public void ReadIsValueSeparatorWithVerify() + { + if (!ReadIsValueSeparator()) throw CreateParsingException(","); + } + + public bool ReadIsNameSeparator() + { + SkipWhiteSpace(); + if (IsInRange && bytes[offset] == ':') + { + offset += 1; + return true; + } + else + { + return false; + } + } + + public void ReadIsNameSeparatorWithVerify() + { + if (!ReadIsNameSeparator()) throw CreateParsingException(":"); + } + + void ReadStringSegmentCore(out byte[] resultBytes, out int resultOffset, out int resultLength) + { + // SkipWhiteSpace is already called from IsNull + + byte[] builder = null; + var builderOffset = 0; + char[] codePointStringBuffer = null; + var codePointStringOffet = 0; + + if (bytes[offset] != '\"') throw CreateParsingException("String Begin Token"); + offset++; + + var from = offset; + + // eliminate array-bound check + for (int i = offset; i < bytes.Length; i++) + { + byte escapeCharacter = 0; + switch (bytes[i]) + { + case (byte)'\\': // escape character + switch ((char)bytes[i + 1]) + { + case '"': + case '\\': + case '/': + escapeCharacter = bytes[i + 1]; + goto COPY; + case 'b': + escapeCharacter = (byte)'\b'; + goto COPY; + case 'f': + escapeCharacter = (byte)'\f'; + goto COPY; + case 'n': + escapeCharacter = (byte)'\n'; + goto COPY; + case 'r': + escapeCharacter = (byte)'\r'; + goto COPY; + case 't': + escapeCharacter = (byte)'\t'; + goto COPY; + case 'u': + if (codePointStringBuffer == null) codePointStringBuffer = StringBuilderCache.GetCodePointStringBuffer(); + + if (codePointStringOffet == 0) + { + if (builder == null) builder = StringBuilderCache.GetBuffer(); + + var copyCount = i - from; + BinaryUtil.EnsureCapacity(ref builder, builderOffset, copyCount + 1); // require + 1 + Buffer.BlockCopy(bytes, from, builder, builderOffset, copyCount); + builderOffset += copyCount; + } + + if (codePointStringBuffer.Length == codePointStringOffet) + { + Array.Resize(ref codePointStringBuffer, codePointStringBuffer.Length * 2); + } + + var a = (char)bytes[i + 2]; + var b = (char)bytes[i + 3]; + var c = (char)bytes[i + 4]; + var d = (char)bytes[i + 5]; + var codepoint = GetCodePoint(a, b, c, d); + codePointStringBuffer[codePointStringOffet++] = (char)codepoint; + i += 5; + offset += 6; + from = offset; + continue; + default: + throw CreateParsingExceptionMessage("Bad JSON escape."); + } + case (byte)'"': // endtoken + offset++; + goto END; + default: // string + if (codePointStringOffet != 0) + { + if (builder == null) builder = StringBuilderCache.GetBuffer(); + BinaryUtil.EnsureCapacity(ref builder, builderOffset, StringEncoding.UTF8.GetMaxByteCount(codePointStringOffet)); + builderOffset += StringEncoding.UTF8.GetBytes(codePointStringBuffer, 0, codePointStringOffet, builder, builderOffset); + codePointStringOffet = 0; + } + offset++; + continue; + } + + COPY: + { + if (builder == null) builder = StringBuilderCache.GetBuffer(); + if (codePointStringOffet != 0) + { + BinaryUtil.EnsureCapacity(ref builder, builderOffset, StringEncoding.UTF8.GetMaxByteCount(codePointStringOffet)); + builderOffset += StringEncoding.UTF8.GetBytes(codePointStringBuffer, 0, codePointStringOffet, builder, builderOffset); + codePointStringOffet = 0; + } + + var copyCount = i - from; + BinaryUtil.EnsureCapacity(ref builder, builderOffset, copyCount + 1); // require + 1! + Buffer.BlockCopy(bytes, from, builder, builderOffset, copyCount); + builderOffset += copyCount; + builder[builderOffset++] = escapeCharacter; + i += 1; + offset += 2; + from = offset; + } + } + + resultLength = 0; + resultBytes = null; + resultOffset = 0; + throw CreateParsingException("String End Token"); + + END: + if (builderOffset == 0 && codePointStringOffet == 0) // no escape + { + resultBytes = bytes; + resultOffset = from; + resultLength = offset - 1 - from; // skip last quote + } + else + { + if (builder == null) builder = StringBuilderCache.GetBuffer(); + if (codePointStringOffet != 0) + { + BinaryUtil.EnsureCapacity(ref builder, builderOffset, StringEncoding.UTF8.GetMaxByteCount(codePointStringOffet)); + builderOffset += StringEncoding.UTF8.GetBytes(codePointStringBuffer, 0, codePointStringOffet, builder, builderOffset); + codePointStringOffet = 0; + } + + var copyCount = offset - from - 1; + BinaryUtil.EnsureCapacity(ref builder, builderOffset, copyCount); + Buffer.BlockCopy(bytes, from, builder, builderOffset, copyCount); + builderOffset += copyCount; + + resultBytes = builder; + resultOffset = 0; + resultLength = builderOffset; + } + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + static int GetCodePoint(char a, char b, char c, char d) + { + return (((((ToNumber(a) * 16) + ToNumber(b)) * 16) + ToNumber(c)) * 16) + ToNumber(d); + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + static int ToNumber(char x) + { + if ('0' <= x && x <= '9') + { + return x - '0'; + } + else if ('a' <= x && x <= 'f') + { + return x - 'a' + 10; + } + else if ('A' <= x && x <= 'F') + { + return x - 'A' + 10; + } + throw new JsonParsingException("Invalid Character" + x); + } + + public ArraySegment ReadStringSegmentUnsafe() + { + if (ReadIsNull()) return nullTokenSegment; + + byte[] bytes; + int offset; + int length; + ReadStringSegmentCore(out bytes, out offset, out length); + return new ArraySegment(bytes, offset, length); + } + + public string ReadString() + { + if (ReadIsNull()) return null; + + byte[] bytes; + int offset; + int length; + ReadStringSegmentCore(out bytes, out offset, out length); + + return Encoding.UTF8.GetString(bytes, offset, length); + } + + /// ReadString + ReadIsNameSeparatorWithVerify + public string ReadPropertyName() + { + var key = ReadString(); + ReadIsNameSeparatorWithVerify(); + return key; + } + + /// Get raw string-span(do not unescape) + public ArraySegment ReadStringSegmentRaw() + { + ArraySegment key = default(ArraySegment); + if (ReadIsNull()) + { + key = nullTokenSegment; + } + else + { + // SkipWhiteSpace is already called from IsNull + if (bytes[offset++] != '\"') throw CreateParsingException("\""); + + var from = offset; + + for (int i = offset; i < bytes.Length; i++) + { + if (bytes[i] == (char)'\"') + { + // is escape? + if (bytes[i - 1] == (char)'\\') + { + continue; + } + else + { + offset = i + 1; + goto OK; + } + } + } + throw CreateParsingExceptionMessage("not found end string."); + + OK: + key = new ArraySegment(bytes, from, offset - from - 1); // remove \" + } + + return key; + } + + /// Get raw string-span(do not unescape) + ReadIsNameSeparatorWithVerify + public ArraySegment ReadPropertyNameSegmentRaw() + { + var key = ReadStringSegmentRaw(); + ReadIsNameSeparatorWithVerify(); + return key; + } + + public bool ReadBoolean() + { + SkipWhiteSpace(); + if (bytes[offset] == 't') + { + if (bytes[offset + 1] != 'r') goto ERROR_TRUE; + if (bytes[offset + 2] != 'u') goto ERROR_TRUE; + if (bytes[offset + 3] != 'e') goto ERROR_TRUE; + offset += 4; + return true; + } + else if (bytes[offset] == 'f') + { + if (bytes[offset + 1] != 'a') goto ERROR_FALSE; + if (bytes[offset + 2] != 'l') goto ERROR_FALSE; + if (bytes[offset + 3] != 's') goto ERROR_FALSE; + if (bytes[offset + 4] != 'e') goto ERROR_FALSE; + offset += 5; + return false; + } + else + { + throw CreateParsingException("true | false"); + } + + ERROR_TRUE: + throw CreateParsingException("true"); + ERROR_FALSE: + throw CreateParsingException("false"); + } + + static bool IsWordBreak(byte c) + { + switch (c) + { + case (byte)' ': + case (byte)'{': + case (byte)'}': + case (byte)'[': + case (byte)']': + case (byte)',': + case (byte)':': + case (byte)'\"': + return true; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + case 33: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 45: + case 46: + case 47: + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + case 59: + case 60: + case 61: + case 62: + case 63: + case 64: + case 65: + case 66: + case 67: + case 68: + case 69: + case 70: + case 71: + case 72: + case 73: + case 74: + case 75: + case 76: + case 77: + case 78: + case 79: + case 80: + case 81: + case 82: + case 83: + case 84: + case 85: + case 86: + case 87: + case 88: + case 89: + case 90: + case 92: + case 94: + case 95: + case 96: + case 97: + case 98: + case 99: + case 100: + case 101: + case 102: + case 103: + case 104: + case 105: + case 106: + case 107: + case 108: + case 109: + case 110: + case 111: + case 112: + case 113: + case 114: + case 115: + case 116: + case 117: + case 118: + case 119: + case 120: + case 121: + case 122: + default: + return false; + } + } + + public void ReadNext() + { + var token = GetCurrentJsonToken(); + ReadNextCore(token); + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + void ReadNextCore(JsonToken token) + { + switch (token) + { + case JsonToken.BeginObject: + case JsonToken.BeginArray: + case JsonToken.ValueSeparator: + case JsonToken.NameSeparator: + case JsonToken.EndObject: + case JsonToken.EndArray: + offset += 1; + break; + case JsonToken.True: + case JsonToken.Null: + offset += 4; + break; + case JsonToken.False: + offset += 5; + break; + case JsonToken.String: + offset += 1; // position is "\""; + for (int i = offset; i < bytes.Length; i++) + { + if (bytes[i] == (char)'\"') + { + // is escape? + if (bytes[i - 1] == (char)'\\') + { + continue; + } + else + { + offset = i + 1; + return; // end + } + } + } + throw CreateParsingExceptionMessage("not found end string."); + case JsonToken.Number: + for (int i = offset; i < bytes.Length; i++) + { + if (IsWordBreak(bytes[i])) + { + offset = i; + return; + } + } + offset = bytes.Length; + break; + case JsonToken.None: + default: + break; + } + } + + public void ReadNextBlock() + { + ReadNextBlockCore(0); + } + + void ReadNextBlockCore(int stack) + { + var token = GetCurrentJsonToken(); + switch (token) + { + case JsonToken.BeginObject: + case JsonToken.BeginArray: + offset++; + ReadNextBlockCore(stack + 1); + break; + case JsonToken.EndObject: + case JsonToken.EndArray: + offset++; + if ((stack - 1) != 0) + { + ReadNextBlockCore(stack - 1); + } + break; + case JsonToken.True: + case JsonToken.False: + case JsonToken.Null: + case JsonToken.String: + case JsonToken.Number: + case JsonToken.NameSeparator: + case JsonToken.ValueSeparator: + do + { + ReadNextCore(token); + token = GetCurrentJsonToken(); + } while (stack != 0 && !((int)token < 5)); // !(None, Begin/EndObject, Begin/EndArray) + + if (stack != 0) + { + ReadNextBlockCore(stack); + } + break; + case JsonToken.None: + default: + break; + } + } + + public ArraySegment ReadNextBlockSegment() + { + var startOffset = offset; + ReadNextBlock(); + return new ArraySegment(bytes, startOffset, offset - startOffset); + } + + public sbyte ReadSByte() + { + return checked((sbyte)ReadInt64()); + } + + public short ReadInt16() + { + return checked((short)ReadInt64()); + } + + public int ReadInt32() + { + return checked((int)ReadInt64()); + } + + public long ReadInt64() + { + SkipWhiteSpace(); + + int readCount; + var v = NumberConverter.ReadInt64(bytes, offset, out readCount); + if (readCount == 0) + { + throw CreateParsingException("Number Token"); + } + + offset += readCount; + return v; + } + + public byte ReadByte() + { + return checked((byte)ReadUInt64()); + } + + public ushort ReadUInt16() + { + return checked((ushort)ReadUInt64()); + } + + public uint ReadUInt32() + { + return checked((uint)ReadUInt64()); + } + + public ulong ReadUInt64() + { + SkipWhiteSpace(); + + int readCount; + var v = NumberConverter.ReadUInt64(bytes, offset, out readCount); + if (readCount == 0) + { + throw CreateParsingException("Number Token"); + } + offset += readCount; + return v; + } + + public Single ReadSingle() + { + SkipWhiteSpace(); + int readCount; + var v = Utf8Json.Internal.DoubleConversion.StringToDoubleConverter.ToSingle(bytes, offset, out readCount); + if (readCount == 0) + { + throw CreateParsingException("Number Token"); + } + offset += readCount; + return v; + } + + public Double ReadDouble() + { + SkipWhiteSpace(); + int readCount; + var v = Utf8Json.Internal.DoubleConversion.StringToDoubleConverter.ToDouble(bytes, offset, out readCount); + if (readCount == 0) + { + throw CreateParsingException("Number Token"); + } + offset += readCount; + return v; + } + + public ArraySegment ReadNumberSegment() + { + SkipWhiteSpace(); + var initialOffset = offset; + for (int i = offset; i < bytes.Length; i++) + { + if (!NumberConverter.IsNumberRepresentation(bytes[i])) + { + offset = i; + goto END; + } + } + offset = bytes.Length; + + END: + return new ArraySegment(bytes, initialOffset, offset - initialOffset); + } + + // return last offset. + static int ReadComment(byte[] bytes, int offset) + { + // current token is '/' + if (bytes[offset + 1] == '/') + { + // single line + offset += 2; + for (int i = offset; i < bytes.Length; i++) + { + if (bytes[i] == '\r' || bytes[i] == '\n') + { + return i; + } + } + + throw new JsonParsingException("Can not find end token of single line comment(\r or \n)."); + } + else if (bytes[offset + 1] == '*') + { + + offset += 2; // '/' + '*'; + for (int i = offset; i < bytes.Length; i++) + { + if (bytes[i] == '*' && bytes[i + 1] == '/') + { + return i + 1; + } + } + throw new JsonParsingException("Can not find end token of multi line comment(*/)."); + } + + return offset; + } + + internal static class StringBuilderCache + { + [ThreadStatic] + static byte[] buffer; + + [ThreadStatic] + static char[] codePointStringBuffer; + + public static byte[] GetBuffer() + { + if (buffer == null) + { + buffer = new byte[65535]; + } + return buffer; + } + + public static char[] GetCodePointStringBuffer() + { + if (codePointStringBuffer == null) + { + codePointStringBuffer = new char[65535]; + } + return codePointStringBuffer; + } + } + } + + public class JsonParsingException : Exception + { + WeakReference underyingBytes; + int limit; + public int Offset { get; private set; } + public string ActualChar { get; set; } + + public JsonParsingException(string message) + : base(message) + { + + } + + public JsonParsingException(string message, byte[] underlyingBytes, int offset, int limit, string actualChar) + : base(message) + { + this.underyingBytes = new WeakReference(underlyingBytes); + this.Offset = offset; + this.ActualChar = actualChar; + this.limit = limit; + } + + /// + /// Underlying bytes is may be a pooling buffer, be careful to use it. If lost reference or can not handled byte[], return null. + /// + public byte[] GetUnderlyingByteArrayUnsafe() + { + return underyingBytes.Target as byte[]; + } + + /// + /// Underlying bytes is may be a pooling buffer, be careful to use it. If lost reference or can not handled byte[], return null. + /// + public string GetUnderlyingStringUnsafe() + { + var bytes = underyingBytes.Target as byte[]; + if (bytes != null) + { + return StringEncoding.UTF8.GetString(bytes, 0, limit) + "..."; + } + return null; + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/JsonSerializer.NonGeneric.cs b/Unity3D/3rdLib/Utf8Json/JsonSerializer.NonGeneric.cs new file mode 100644 index 0000000..b51dc32 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/JsonSerializer.NonGeneric.cs @@ -0,0 +1,491 @@ +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using Utf8Json.Internal; +using Utf8Json.Internal.Emit; + +namespace Utf8Json +{ + // NonGeneric API + public static partial class JsonSerializer + { + public static class NonGeneric + { + static readonly Func CreateCompiledMethods; + static readonly ThreadsafeTypeKeyHashTable serializes = new ThreadsafeTypeKeyHashTable(capacity: 64); + + delegate void SerializeJsonWriter(ref JsonWriter writer, object value, IJsonFormatterResolver resolver); + delegate object DeserializeJsonReader(ref JsonReader reader, IJsonFormatterResolver resolver); + + static NonGeneric() + { + CreateCompiledMethods = t => new CompiledMethods(t); + } + + static CompiledMethods GetOrAdd(Type type) + { + return serializes.GetOrAdd(type, CreateCompiledMethods); + } + + /// + /// Serialize to binary with default resolver. + /// + public static byte[] Serialize(object value) + { + if (value == null) return Serialize(value); + return Serialize(value.GetType(), value, defaultResolver); + } + + /// + /// Serialize to binary with default resolver. + /// + public static byte[] Serialize(Type type, object value) + { + return Serialize(type, value, defaultResolver); + } + + /// + /// Serialize to binary with specified resolver. + /// + public static byte[] Serialize(object value, IJsonFormatterResolver resolver) + { + if (value == null) return Serialize(value, resolver); + return Serialize(value.GetType(), value, resolver); + } + + /// + /// Serialize to binary with specified resolver. + /// + public static byte[] Serialize(Type type, object value, IJsonFormatterResolver resolver) + { + return GetOrAdd(type).serialize1.Invoke(value, resolver); + } + + /// + /// Serialize to stream. + /// + public static void Serialize(Stream stream, object value) + { + if (value == null) { Serialize(stream, value); return; } + Serialize(value.GetType(), stream, value, defaultResolver); + } + + /// + /// Serialize to stream. + /// + public static void Serialize(Type type, Stream stream, object value) + { + Serialize(type, stream, value, defaultResolver); + } + + /// + /// Serialize to stream with specified resolver. + /// + public static void Serialize(Stream stream, object value, IJsonFormatterResolver resolver) + { + if (value == null) { Serialize(stream, value, resolver); return; } + Serialize(value.GetType(), stream, value, resolver); + } + + /// + /// Serialize to stream with specified resolver. + /// + public static void Serialize(Type type, Stream stream, object value, IJsonFormatterResolver resolver) + { + GetOrAdd(type).serialize2.Invoke(stream, value, resolver); + } + +#if NETSTANDARD + + /// + /// Serialize to stream. + /// + public static System.Threading.Tasks.Task SerializeAsync(Stream stream, object value) + { + if (value == null) { return SerializeAsync(stream, value); } + return SerializeAsync(value.GetType(), stream, value, defaultResolver); + } + + /// + /// Serialize to stream. + /// + public static System.Threading.Tasks.Task SerializeAsync(Type type, Stream stream, object value) + { + return SerializeAsync(type, stream, value, defaultResolver); + } + + /// + /// Serialize to stream with specified resolver. + /// + public static System.Threading.Tasks.Task SerializeAsync(Stream stream, object value, IJsonFormatterResolver resolver) + { + if (value == null) { return SerializeAsync(stream, value, resolver); } + return SerializeAsync(value.GetType(), stream, value, resolver); + } + + /// + /// Serialize to stream with specified resolver. + /// + public static System.Threading.Tasks.Task SerializeAsync(Type type, Stream stream, object value, IJsonFormatterResolver resolver) + { + return GetOrAdd(type).serializeAsync.Invoke(stream, value, resolver); + } + +#endif + + public static void Serialize(ref JsonWriter writer, object value, IJsonFormatterResolver resolver) + { + if (value == null) + { + writer.WriteNull(); + return; + } + else + { + Serialize(value.GetType(), ref writer, value, resolver); + } + } + + public static void Serialize(Type type, ref JsonWriter writer, object value) + { + Serialize(type, ref writer, value, defaultResolver); + } + + public static void Serialize(Type type, ref JsonWriter writer, object value, IJsonFormatterResolver resolver) + { + GetOrAdd(type).serialize3.Invoke(ref writer, value, resolver); + } + + /// + /// Serialize to binary. Get the raw memory pool byte[]. The result can not share across thread and can not hold, so use quickly. + /// + public static ArraySegment SerializeUnsafe(object value) + { + if (value == null) return SerializeUnsafe(value); + return SerializeUnsafe(value.GetType(), value); + } + + /// + /// Serialize to binary. Get the raw memory pool byte[]. The result can not share across thread and can not hold, so use quickly. + /// + public static ArraySegment SerializeUnsafe(Type type, object value) + { + return SerializeUnsafe(type, value, defaultResolver); + } + + /// + /// Serialize to binary with specified resolver. Get the raw memory pool byte[]. The result can not share across thread and can not hold, so use quickly. + /// + public static ArraySegment SerializeUnsafe(object value, IJsonFormatterResolver resolver) + { + if (value == null) return SerializeUnsafe(value); + return SerializeUnsafe(value.GetType(), value, resolver); + } + + /// + /// Serialize to binary with specified resolver. Get the raw memory pool byte[]. The result can not share across thread and can not hold, so use quickly. + /// + public static ArraySegment SerializeUnsafe(Type type, object value, IJsonFormatterResolver resolver) + { + return GetOrAdd(type).serializeUnsafe.Invoke(value, resolver); + } + + /// + /// Serialize to JsonString. + /// + public static string ToJsonString(object value) + { + if (value == null) return "null"; + return ToJsonString(value.GetType(), value); + } + + /// + /// Serialize to JsonString. + /// + public static string ToJsonString(Type type, object value) + { + return ToJsonString(type, value, defaultResolver); + } + + /// + /// Serialize to JsonString with specified resolver. + /// + public static string ToJsonString(object value, IJsonFormatterResolver resolver) + { + if (value == null) return "null"; + return ToJsonString(value.GetType(), value, resolver); + } + + /// + /// Serialize to JsonString with specified resolver. + /// + public static string ToJsonString(Type type, object value, IJsonFormatterResolver resolver) + { + return GetOrAdd(type).toJsonString.Invoke(value, resolver); + } + + public static object Deserialize(Type type, string json) + { + return Deserialize(type, json, defaultResolver); + } + + public static object Deserialize(Type type, string json, IJsonFormatterResolver resolver) + { + return GetOrAdd(type).deserialize1.Invoke(json, resolver); + } + + public static object Deserialize(Type type, byte[] bytes) + { + return Deserialize(type, bytes, defaultResolver); + } + + public static object Deserialize(Type type, byte[] bytes, IJsonFormatterResolver resolver) + { + return Deserialize(type, bytes, 0, defaultResolver); + } + + public static object Deserialize(Type type, byte[] bytes, int offset) + { + return Deserialize(type, bytes, offset, defaultResolver); + } + + public static object Deserialize(Type type, byte[] bytes, int offset, IJsonFormatterResolver resolver) + { + return GetOrAdd(type).deserialize2.Invoke(bytes, offset, resolver); + } + + public static object Deserialize(Type type, Stream stream) + { + return Deserialize(type, stream, defaultResolver); + } + + public static object Deserialize(Type type, Stream stream, IJsonFormatterResolver resolver) + { + return GetOrAdd(type).deserialize3.Invoke(stream, resolver); + } + + public static object Deserialize(Type type, ref JsonReader reader) + { + return Deserialize(type, ref reader, defaultResolver); + } + + public static object Deserialize(Type type, ref JsonReader reader, IJsonFormatterResolver resolver) + { + return GetOrAdd(type).deserialize4.Invoke(ref reader, resolver); + } + +#if NETSTANDARD + + public static System.Threading.Tasks.Task DeserializeAsync(Type type, Stream stream) + { + return DeserializeAsync(type, stream, defaultResolver); + } + + public static System.Threading.Tasks.Task DeserializeAsync(Type type, Stream stream, IJsonFormatterResolver resolver) + { + return GetOrAdd(type).deserializeAsync.Invoke(stream, resolver); + } + +#endif + + class CompiledMethods + { + public readonly Func serialize1; + public readonly Action serialize2; + public readonly SerializeJsonWriter serialize3; + public readonly Func> serializeUnsafe; + public readonly Func toJsonString; + public readonly Func deserialize1; + public readonly Func deserialize2; + public readonly Func deserialize3; + public readonly DeserializeJsonReader deserialize4; + +#if NETSTANDARD + public readonly Func serializeAsync; + public readonly Func> deserializeAsync; +#endif + + public CompiledMethods(Type type) + { + { + var dm = new DynamicMethod("serialize1", typeof(byte[]), new[] { typeof(object), typeof(IJsonFormatterResolver) }, type.Module, true); + var il = dm.GetILGenerator(); + + il.EmitLdarg(0); // obj + il.EmitUnboxOrCast(type); + il.EmitLdarg(1); + il.EmitCall(GetMethod(type, "Serialize", new[] { null, typeof(IJsonFormatterResolver) })); + il.Emit(OpCodes.Ret); + + serialize1 = CreateDelegate>(dm); + } + { + var dm = new DynamicMethod("serialize2", null, new[] { typeof(Stream), typeof(object), typeof(IJsonFormatterResolver) }, type.Module, true); + var il = dm.GetILGenerator(); + + il.EmitLdarg(0); // stream + il.EmitLdarg(1); + il.EmitUnboxOrCast(type); + il.EmitLdarg(2); + il.EmitCall(GetMethod(type, "Serialize", new[] { typeof(Stream), null, typeof(IJsonFormatterResolver) })); + il.Emit(OpCodes.Ret); + + serialize2 = CreateDelegate>(dm); + } + { + var dm = new DynamicMethod("serialize3", null, new[] { typeof(JsonWriter).MakeByRefType(), typeof(object), typeof(IJsonFormatterResolver) }, type.Module, true); + var il = dm.GetILGenerator(); + + il.EmitLdarg(0); // ref writer + il.EmitLdarg(1); + il.EmitUnboxOrCast(type); + il.EmitLdarg(2); + il.EmitCall(GetMethod(type, "Serialize", new[] { typeof(JsonWriter).MakeByRefType(), null, typeof(IJsonFormatterResolver) })); + il.Emit(OpCodes.Ret); + + serialize3 = CreateDelegate(dm); + } + { + var dm = new DynamicMethod("serializeUnsafe", typeof(ArraySegment), new[] { typeof(object), typeof(IJsonFormatterResolver) }, type.Module, true); + var il = dm.GetILGenerator(); + + il.EmitLdarg(0); // obj + il.EmitUnboxOrCast(type); + il.EmitLdarg(1); + il.EmitCall(GetMethod(type, "SerializeUnsafe", new[] { null, typeof(IJsonFormatterResolver) })); + il.Emit(OpCodes.Ret); + + serializeUnsafe = CreateDelegate>>(dm); + } + { + var dm = new DynamicMethod("toJsonString", typeof(string), new[] { typeof(object), typeof(IJsonFormatterResolver) }, type.Module, true); + var il = dm.GetILGenerator(); + + il.EmitLdarg(0); // obj + il.EmitUnboxOrCast(type); + il.EmitLdarg(1); + il.EmitCall(GetMethod(type, "ToJsonString", new[] { null, typeof(IJsonFormatterResolver) })); + il.Emit(OpCodes.Ret); + + toJsonString = CreateDelegate>(dm); + } + { + var dm = new DynamicMethod("Deserialize", typeof(object), new[] { typeof(string), typeof(IJsonFormatterResolver) }, type.Module, true); + var il = dm.GetILGenerator(); + + il.EmitLdarg(0); + il.EmitLdarg(1); + il.EmitCall(GetMethod(type, "Deserialize", new[] { typeof(string), typeof(IJsonFormatterResolver) })); + il.EmitBoxOrDoNothing(type); + il.Emit(OpCodes.Ret); + + deserialize1 = CreateDelegate>(dm); + } + { + var dm = new DynamicMethod("Deserialize", typeof(object), new[] { typeof(byte[]), typeof(int), typeof(IJsonFormatterResolver) }, type.Module, true); + var il = dm.GetILGenerator(); + + il.EmitLdarg(0); + il.EmitLdarg(1); + il.EmitLdarg(2); + il.EmitCall(GetMethod(type, "Deserialize", new[] { typeof(byte[]), typeof(int), typeof(IJsonFormatterResolver) })); + il.EmitBoxOrDoNothing(type); + il.Emit(OpCodes.Ret); + + deserialize2 = CreateDelegate>(dm); + } + { + var dm = new DynamicMethod("Deserialize", typeof(object), new[] { typeof(Stream), typeof(IJsonFormatterResolver) }, type.Module, true); + var il = dm.GetILGenerator(); + + il.EmitLdarg(0); + il.EmitLdarg(1); + il.EmitCall(GetMethod(type, "Deserialize", new[] { typeof(Stream), typeof(IJsonFormatterResolver) })); + il.EmitBoxOrDoNothing(type); + il.Emit(OpCodes.Ret); + + deserialize3 = CreateDelegate>(dm); + } + { + var dm = new DynamicMethod("Deserialize", typeof(object), new[] { typeof(JsonReader).MakeByRefType(), typeof(IJsonFormatterResolver) }, type.Module, true); + var il = dm.GetILGenerator(); + + il.EmitLdarg(0); // ref reader + il.EmitLdarg(1); + il.EmitCall(GetMethod(type, "Deserialize", new[] { typeof(JsonReader).MakeByRefType(), typeof(IJsonFormatterResolver) })); + il.EmitBoxOrDoNothing(type); + il.Emit(OpCodes.Ret); + + deserialize4 = CreateDelegate(dm); + } + +#if NETSTANDARD + + { + var dm = new DynamicMethod("SerializeAsync", typeof(System.Threading.Tasks.Task), new[] { typeof(Stream), typeof(object), typeof(IJsonFormatterResolver) }, type.Module, true); + var il = dm.GetILGenerator(); + + il.EmitLdarg(0); // stream + il.EmitLdarg(1); + il.EmitUnboxOrCast(type); + il.EmitLdarg(2); + il.EmitCall(GetMethod(type, "SerializeAsync", new[] { typeof(Stream), null, typeof(IJsonFormatterResolver) })); + il.Emit(OpCodes.Ret); + + serializeAsync = CreateDelegate>(dm); + } + + { + var dm = new DynamicMethod("DeserializeAsync", typeof(System.Threading.Tasks.Task), new[] { typeof(Stream), typeof(IJsonFormatterResolver) }, type.Module, true); + var il = dm.GetILGenerator(); + + il.EmitLdarg(0); + il.EmitLdarg(1); + il.EmitCall(GetMethod(type, "DeserializeAsync", new[] { typeof(Stream), typeof(IJsonFormatterResolver) })); + il.EmitCall(typeof(CompiledMethods).GetMethod("TaskCast", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(type)); + il.Emit(OpCodes.Ret); + + deserializeAsync = CreateDelegate>>(dm); + } +#endif + } + +#if NETSTANDARD + + static async System.Threading.Tasks.Task TaskCast(System.Threading.Tasks.Task task) + { + var t = await task.ConfigureAwait(false); + return (object)t; + } + +#endif + + static T CreateDelegate(DynamicMethod dm) + { + return (T)(object)dm.CreateDelegate(typeof(T)); + } + + static MethodInfo GetMethod(Type type, string name, Type[] arguments) + { + return typeof(JsonSerializer).GetMethods(BindingFlags.Static | BindingFlags.Public) + .Where(x => x.Name == name) + .Single(x => + { + var ps = x.GetParameters(); + if (ps.Length != arguments.Length) return false; + for (int i = 0; i < ps.Length; i++) + { + // null for . + if (arguments[i] == null && ps[i].ParameterType.IsGenericParameter) continue; + if (ps[i].ParameterType != arguments[i]) return false; + } + return true; + }) + .MakeGenericMethod(type); + } + } + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/JsonSerializer.cs b/Unity3D/3rdLib/Utf8Json/JsonSerializer.cs new file mode 100644 index 0000000..ac4ec26 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/JsonSerializer.cs @@ -0,0 +1,469 @@ +using System; +using System.IO; +using System.Linq; +using System.Text; +using Utf8Json.Internal; +using Utf8Json.Resolvers; + +namespace Utf8Json +{ + /// + /// High-Level API of Utf8Json. + /// + public static partial class JsonSerializer + { + static IJsonFormatterResolver defaultResolver; + + /// + /// FormatterResolver that used resolver less overloads. If does not set it, used StandardResolver.Default. + /// + public static IJsonFormatterResolver DefaultResolver + { + get + { + if (defaultResolver == null) + { + defaultResolver = StandardResolver.Default; + } + + return defaultResolver; + } + } + + /// + /// Is resolver decided? + /// + public static bool IsInitialized + { + get + { + return defaultResolver != null; + } + } + + /// + /// Set default resolver of Utf8Json APIs. + /// + /// + public static void SetDefaultResolver(IJsonFormatterResolver resolver) + { + defaultResolver = resolver; + } + + /// + /// Serialize to binary with default resolver. + /// + public static byte[] Serialize(T obj) + { + return Serialize(obj, defaultResolver); + } + + /// + /// Serialize to binary with specified resolver. + /// + public static byte[] Serialize(T value, IJsonFormatterResolver resolver) + { + if (resolver == null) resolver = DefaultResolver; + + var writer = new JsonWriter(MemoryPool.GetBuffer()); + var formatter = resolver.GetFormatterWithVerify(); + formatter.Serialize(ref writer, value, resolver); + return writer.ToUtf8ByteArray(); + } + + public static void Serialize(ref JsonWriter writer, T value) + { + Serialize(ref writer, value, defaultResolver); + } + + public static void Serialize(ref JsonWriter writer, T value, IJsonFormatterResolver resolver) + { + if (resolver == null) resolver = DefaultResolver; + + var formatter = resolver.GetFormatterWithVerify(); + formatter.Serialize(ref writer, value, resolver); + } + + /// + /// Serialize to stream. + /// + public static void Serialize(Stream stream, T value) + { + Serialize(stream, value, defaultResolver); + } + + /// + /// Serialize to stream with specified resolver. + /// + public static void Serialize(Stream stream, T value, IJsonFormatterResolver resolver) + { + if (resolver == null) resolver = DefaultResolver; + + var buffer = SerializeUnsafe(value, resolver); + stream.Write(buffer.Array, buffer.Offset, buffer.Count); + } + +#if NETSTANDARD + + /// + /// Serialize to stream(write async). + /// + public static System.Threading.Tasks.Task SerializeAsync(Stream stream, T value) + { + return SerializeAsync(stream, value, defaultResolver); + } + + /// + /// Serialize to stream(write async) with specified resolver. + /// + public static async System.Threading.Tasks.Task SerializeAsync(Stream stream, T value, IJsonFormatterResolver resolver) + { + if (resolver == null) resolver = DefaultResolver; + + var buf = BufferPool.Default.Rent(); + try + { + var writer = new JsonWriter(buf); + var formatter = resolver.GetFormatterWithVerify(); + formatter.Serialize(ref writer, value, resolver); + var buffer = writer.GetBuffer(); + await stream.WriteAsync(buffer.Array, buffer.Offset, buffer.Count).ConfigureAwait(false); + } + finally + { + BufferPool.Default.Return(buf); + } + } + +#endif + + /// + /// Serialize to binary. Get the raw memory pool byte[]. The result can not share across thread and can not hold, so use quickly. + /// + public static ArraySegment SerializeUnsafe(T obj) + { + return SerializeUnsafe(obj, defaultResolver); + } + + /// + /// Serialize to binary with specified resolver. Get the raw memory pool byte[]. The result can not share across thread and can not hold, so use quickly. + /// + public static ArraySegment SerializeUnsafe(T value, IJsonFormatterResolver resolver) + { + if (resolver == null) resolver = DefaultResolver; + + var writer = new JsonWriter(MemoryPool.GetBuffer()); + var formatter = resolver.GetFormatterWithVerify(); + formatter.Serialize(ref writer, value, resolver); + return writer.GetBuffer(); + } + + /// + /// Serialize to JsonString. + /// + public static string ToJsonString(T value) + { + return ToJsonString(value, defaultResolver); + } + + /// + /// Serialize to JsonString with specified resolver. + /// + public static string ToJsonString(T value, IJsonFormatterResolver resolver) + { + if (resolver == null) resolver = DefaultResolver; + + var writer = new JsonWriter(MemoryPool.GetBuffer()); + var formatter = resolver.GetFormatterWithVerify(); + formatter.Serialize(ref writer, value, resolver); + return writer.ToString(); + } + + public static T Deserialize(string json) + { + return Deserialize(json, defaultResolver); + } + + public static T Deserialize(string json, IJsonFormatterResolver resolver) + { + return Deserialize(StringEncoding.UTF8.GetBytes(json), resolver); + } + + public static T Deserialize(byte[] bytes) + { + return Deserialize(bytes, defaultResolver); + } + + public static T Deserialize(byte[] bytes, IJsonFormatterResolver resolver) + { + return Deserialize(bytes, 0, resolver); + } + + public static T Deserialize(byte[] bytes, int offset) + { + return Deserialize(bytes, offset, defaultResolver); + } + + public static T Deserialize(byte[] bytes, int offset, IJsonFormatterResolver resolver) + { + if (resolver == null) resolver = DefaultResolver; + + var reader = new JsonReader(bytes, offset); + var formatter = resolver.GetFormatterWithVerify(); + return formatter.Deserialize(ref reader, resolver); + } + + public static T Deserialize(ref JsonReader reader) + { + return Deserialize(ref reader, defaultResolver); + } + + public static T Deserialize(ref JsonReader reader, IJsonFormatterResolver resolver) + { + if (resolver == null) resolver = DefaultResolver; + + var formatter = resolver.GetFormatterWithVerify(); + return formatter.Deserialize(ref reader, resolver); + } + + public static T Deserialize(Stream stream) + { + return Deserialize(stream, defaultResolver); + } + + public static T Deserialize(Stream stream, IJsonFormatterResolver resolver) + { + if (resolver == null) resolver = DefaultResolver; + +#if NETSTANDARD && !NET45 + var ms = stream as MemoryStream; + if (ms != null) + { + ArraySegment buf2; + if (ms.TryGetBuffer(out buf2)) + { + // when token is number, can not use from pool(can not find end line). + var token = new JsonReader(buf2.Array, buf2.Offset).GetCurrentJsonToken(); + if (token == JsonToken.Number) + { + var buf3 = new byte[buf2.Count]; + Buffer.BlockCopy(buf2.Array, buf2.Offset, buf3, 0, buf3.Length); + return Deserialize(buf3, 0, resolver); + } + + return Deserialize(buf2.Array, buf2.Offset, resolver); + } + } +#endif + { + var buf = MemoryPool.GetBuffer(); + var len = FillFromStream(stream, ref buf); + + // when token is number, can not use from pool(can not find end line). + var token = new JsonReader(buf).GetCurrentJsonToken(); + if (token == JsonToken.Number) + { + buf = BinaryUtil.FastCloneWithResize(buf, len); + } + + return Deserialize(buf, resolver); + } + } + +#if NETSTANDARD + + public static System.Threading.Tasks.Task DeserializeAsync(Stream stream) + { + return DeserializeAsync(stream, defaultResolver); + } + + public static async System.Threading.Tasks.Task DeserializeAsync(Stream stream, IJsonFormatterResolver resolver) + { + if (resolver == null) resolver = DefaultResolver; + + var buffer = BufferPool.Default.Rent(); + var buf = buffer; + try + { + int length = 0; + int read; + while ((read = await stream.ReadAsync(buf, length, buf.Length - length).ConfigureAwait(false)) > 0) + { + length += read; + if (length == buf.Length) + { + BinaryUtil.FastResize(ref buf, length * 2); + } + } + + // when token is number, can not use from pool(can not find end line). + var token = new JsonReader(buf).GetCurrentJsonToken(); + if (token == JsonToken.Number) + { + buf = BinaryUtil.FastCloneWithResize(buf, length); + } + + return Deserialize(buf, resolver); + } + finally + { + BufferPool.Default.Return(buffer); + } + } + +#endif + + public static string PrettyPrint(byte[] json) + { + return PrettyPrint(json, 0); + } + + public static string PrettyPrint(byte[] json, int offset) + { + var reader = new JsonReader(json, offset); + var writer = new JsonWriter(MemoryPool.GetBuffer()); + WritePrittyPrint(ref reader, ref writer, 0); + return writer.ToString(); + } + + public static string PrettyPrint(string json) + { + var reader = new JsonReader(Encoding.UTF8.GetBytes(json)); + var writer = new JsonWriter(MemoryPool.GetBuffer()); + WritePrittyPrint(ref reader, ref writer, 0); + return writer.ToString(); + } + + public static byte[] PrettyPrintByteArray(byte[] json) + { + return PrettyPrintByteArray(json, 0); + } + + public static byte[] PrettyPrintByteArray(byte[] json, int offset) + { + var reader = new JsonReader(json, offset); + var writer = new JsonWriter(MemoryPool.GetBuffer()); + WritePrittyPrint(ref reader, ref writer, 0); + return writer.ToUtf8ByteArray(); + } + + public static byte[] PrettyPrintByteArray(string json) + { + var reader = new JsonReader(Encoding.UTF8.GetBytes(json)); + var writer = new JsonWriter(MemoryPool.GetBuffer()); + WritePrittyPrint(ref reader, ref writer, 0); + return writer.ToUtf8ByteArray(); + } + + static readonly byte[][] indent = Enumerable.Range(0, 100).Select(x => Encoding.UTF8.GetBytes(new string(' ', x * 2))).ToArray(); + static readonly byte[] newLine = Encoding.UTF8.GetBytes(Environment.NewLine); + + static void WritePrittyPrint(ref JsonReader reader, ref JsonWriter writer, int depth) + { + var token = reader.GetCurrentJsonToken(); + switch (token) + { + case JsonToken.BeginObject: + { + writer.WriteBeginObject(); + writer.WriteRaw(newLine); + var c = 0; + while (reader.ReadIsInObject(ref c)) + { + if (c != 1) + { + writer.WriteRaw((byte)','); + writer.WriteRaw(newLine); + } + writer.WriteRaw(indent[depth + 1]); + writer.WritePropertyName(reader.ReadPropertyName()); + writer.WriteRaw((byte)' '); + WritePrittyPrint(ref reader, ref writer, depth + 1); + } + writer.WriteRaw(newLine); + writer.WriteRaw(indent[depth]); + writer.WriteEndObject(); + } + break; + case JsonToken.BeginArray: + { + writer.WriteBeginArray(); + writer.WriteRaw(newLine); + var c = 0; + while (reader.ReadIsInArray(ref c)) + { + if (c != 1) + { + writer.WriteRaw((byte)','); + writer.WriteRaw(newLine); + } + writer.WriteRaw(indent[depth + 1]); + WritePrittyPrint(ref reader, ref writer, depth + 1); + } + writer.WriteRaw(newLine); + writer.WriteRaw(indent[depth]); + writer.WriteEndArray(); + } + break; + case JsonToken.Number: + { + var v = reader.ReadDouble(); + writer.WriteDouble(v); + } + break; + case JsonToken.String: + { + var v = reader.ReadString(); + writer.WriteString(v); + } + break; + case JsonToken.True: + case JsonToken.False: + { + var v = reader.ReadBoolean(); + writer.WriteBoolean(v); + } + break; + case JsonToken.Null: + { + reader.ReadIsNull(); + writer.WriteNull(); + } + break; + default: + break; + } + } + + static int FillFromStream(Stream input, ref byte[] buffer) + { + int length = 0; + int read; + while ((read = input.Read(buffer, length, buffer.Length - length)) > 0) + { + length += read; + if (length == buffer.Length) + { + BinaryUtil.FastResize(ref buffer, length * 2); + } + } + + return length; + } + + static class MemoryPool + { + [ThreadStatic] + static byte[] buffer = null; + + public static byte[] GetBuffer() + { + if (buffer == null) + { + buffer = new byte[65536]; + } + return buffer; + } + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/JsonToken.cs b/Unity3D/3rdLib/Utf8Json/JsonToken.cs new file mode 100644 index 0000000..cb48ddf --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/JsonToken.cs @@ -0,0 +1,32 @@ +namespace Utf8Json +{ + // 0 = None, 1 ~ 4 is block token, 5 ~ 9 = value token, 10 ~ 11 = delimiter token + // you can use range-check if optimization needed. + + public enum JsonToken : byte + { + None = 0, + /// { + BeginObject = 1, + /// } + EndObject = 2, + /// [ + BeginArray = 3, + /// ] + EndArray = 4, + /// 0~9, - + Number = 5, + /// " + String = 6, + /// t + True = 7, + /// f + False = 8, + /// n + Null = 9, + /// , + ValueSeparator = 10, + /// : + NameSeparator = 11 + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/JsonWriter.cs b/Unity3D/3rdLib/Utf8Json/JsonWriter.cs new file mode 100644 index 0000000..c901dcd --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/JsonWriter.cs @@ -0,0 +1,505 @@ +using System; +using System.Text; +using Utf8Json.Internal; + +#if NETSTANDARD +using System.Runtime.CompilerServices; +#endif + +namespace Utf8Json +{ + // JSON RFC: https://www.ietf.org/rfc/rfc4627.txt + + public struct JsonWriter + { + static readonly byte[] emptyBytes = new byte[0]; + + // write direct from UnsafeMemory +#if NETSTANDARD + internal +#endif + byte[] buffer; +#if NETSTANDARD + internal +#endif + int offset; + + public int CurrentOffset + { + get + { + return offset; + } + } + + public void AdvanceOffset(int offset) + { + this.offset += offset; + } + + public static byte[] GetEncodedPropertyName(string propertyName) + { + var writer = new JsonWriter(); + writer.WritePropertyName(propertyName); + return writer.ToUtf8ByteArray(); + } + + public static byte[] GetEncodedPropertyNameWithPrefixValueSeparator(string propertyName) + { + var writer = new JsonWriter(); + writer.WriteValueSeparator(); + writer.WritePropertyName(propertyName); + return writer.ToUtf8ByteArray(); + } + + public static byte[] GetEncodedPropertyNameWithBeginObject(string propertyName) + { + var writer = new JsonWriter(); + writer.WriteBeginObject(); + writer.WritePropertyName(propertyName); + return writer.ToUtf8ByteArray(); + } + + public static byte[] GetEncodedPropertyNameWithoutQuotation(string propertyName) + { + var writer = new JsonWriter(); + writer.WriteString(propertyName); // "propname" + var buf = writer.GetBuffer(); + var result = new byte[buf.Count - 2]; + Buffer.BlockCopy(buf.Array, buf.Offset + 1, result, 0, result.Length); // without quotation + return result; + } + + public JsonWriter(byte[] initialBuffer) + { + this.buffer = initialBuffer; + this.offset = 0; + } + + public ArraySegment GetBuffer() + { + if (buffer == null) return new ArraySegment(emptyBytes, 0, 0); + return new ArraySegment(buffer, 0, offset); + } + + public byte[] ToUtf8ByteArray() + { + if (buffer == null) return emptyBytes; + return BinaryUtil.FastCloneWithResize(buffer, offset); + } + + public override string ToString() + { + if (buffer == null) return null; + return Encoding.UTF8.GetString(buffer, 0, offset); + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void EnsureCapacity(int appendLength) + { + BinaryUtil.EnsureCapacity(ref buffer, offset, appendLength); + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteRaw(byte rawValue) + { + BinaryUtil.EnsureCapacity(ref buffer, offset, 1); + buffer[offset++] = rawValue; + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteRaw(byte[] rawValue) + { +#if NETSTANDARD + UnsafeMemory.WriteRaw(ref this, rawValue); +#else + BinaryUtil.EnsureCapacity(ref buffer, offset, rawValue.Length); + Buffer.BlockCopy(rawValue, 0, buffer, offset, rawValue.Length); + offset += rawValue.Length; +#endif + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteRawUnsafe(byte rawValue) + { + buffer[offset++] = rawValue; + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteBeginArray() + { + BinaryUtil.EnsureCapacity(ref buffer, offset, 1); + buffer[offset++] = (byte)'['; + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteEndArray() + { + BinaryUtil.EnsureCapacity(ref buffer, offset, 1); + buffer[offset++] = (byte)']'; + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteBeginObject() + { + BinaryUtil.EnsureCapacity(ref buffer, offset, 1); + buffer[offset++] = (byte)'{'; + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteEndObject() + { + BinaryUtil.EnsureCapacity(ref buffer, offset, 1); + buffer[offset++] = (byte)'}'; + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteValueSeparator() + { + BinaryUtil.EnsureCapacity(ref buffer, offset, 1); + buffer[offset++] = (byte)','; + } + + /// : +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteNameSeparator() + { + BinaryUtil.EnsureCapacity(ref buffer, offset, 1); + buffer[offset++] = (byte)':'; + } + + /// WriteString + WriteNameSeparator +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WritePropertyName(string propertyName) + { + WriteString(propertyName); + WriteNameSeparator(); + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteQuotation() + { + BinaryUtil.EnsureCapacity(ref buffer, offset, 1); + buffer[offset++] = (byte)'\"'; + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteNull() + { + BinaryUtil.EnsureCapacity(ref buffer, offset, 4); + buffer[offset + 0] = (byte)'n'; + buffer[offset + 1] = (byte)'u'; + buffer[offset + 2] = (byte)'l'; + buffer[offset + 3] = (byte)'l'; + offset += 4; + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteBoolean(bool value) + { + if (value) + { + BinaryUtil.EnsureCapacity(ref buffer, offset, 4); + buffer[offset + 0] = (byte)'t'; + buffer[offset + 1] = (byte)'r'; + buffer[offset + 2] = (byte)'u'; + buffer[offset + 3] = (byte)'e'; + offset += 4; + } + else + { + BinaryUtil.EnsureCapacity(ref buffer, offset, 5); + buffer[offset + 0] = (byte)'f'; + buffer[offset + 1] = (byte)'a'; + buffer[offset + 2] = (byte)'l'; + buffer[offset + 3] = (byte)'s'; + buffer[offset + 4] = (byte)'e'; + offset += 5; + } + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteTrue() + { + BinaryUtil.EnsureCapacity(ref buffer, offset, 4); + buffer[offset + 0] = (byte)'t'; + buffer[offset + 1] = (byte)'r'; + buffer[offset + 2] = (byte)'u'; + buffer[offset + 3] = (byte)'e'; + offset += 4; + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteFalse() + { + BinaryUtil.EnsureCapacity(ref buffer, offset, 5); + buffer[offset + 0] = (byte)'f'; + buffer[offset + 1] = (byte)'a'; + buffer[offset + 2] = (byte)'l'; + buffer[offset + 3] = (byte)'s'; + buffer[offset + 4] = (byte)'e'; + offset += 5; + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteSingle(Single value) + { + offset += Utf8Json.Internal.DoubleConversion.DoubleToStringConverter.GetBytes(ref buffer, offset, value); + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteDouble(double value) + { + offset += Utf8Json.Internal.DoubleConversion.DoubleToStringConverter.GetBytes(ref buffer, offset, value); + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteByte(byte value) + { + WriteUInt64((ulong)value); + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteUInt16(ushort value) + { + WriteUInt64((ulong)value); + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteUInt32(uint value) + { + WriteUInt64((ulong)value); + } + + public void WriteUInt64(ulong value) + { + offset += NumberConverter.WriteUInt64(ref buffer, offset, value); + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteSByte(sbyte value) + { + WriteInt64((long)value); + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteInt16(short value) + { + WriteInt64((long)value); + } + +#if NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void WriteInt32(int value) + { + WriteInt64((long)value); + } + + public void WriteInt64(long value) + { + offset += NumberConverter.WriteInt64(ref buffer, offset, value); + } + + public void WriteString(string value) + { + if (value == null) + { + WriteNull(); + return; + } + + // single-path escape + + // nonescaped-ensure + var startoffset = offset; + var max = StringEncoding.UTF8.GetMaxByteCount(value.Length) + 2; + BinaryUtil.EnsureCapacity(ref buffer, startoffset, max); + + var from = 0; + var to = value.Length; + + buffer[offset++] = (byte)'\"'; + + // for JIT Optimization, for-loop i < str.Length + for (int i = 0; i < value.Length; i++) + { + byte escapeChar = default(byte); + switch (value[i]) + { + case '"': + escapeChar = (byte)'"'; + break; + case '\\': + escapeChar = (byte)'\\'; + break; + case '\b': + escapeChar = (byte)'b'; + break; + case '\f': + escapeChar = (byte)'f'; + break; + case '\n': + escapeChar = (byte)'n'; + break; + case '\r': + escapeChar = (byte)'r'; + break; + case '\t': + escapeChar = (byte)'t'; + break; + // use switch jumptable + case (char)0: + case (char)1: + case (char)2: + case (char)3: + case (char)4: + case (char)5: + case (char)6: + case (char)7: + case (char)11: + case (char)14: + case (char)15: + case (char)16: + case (char)17: + case (char)18: + case (char)19: + case (char)20: + case (char)21: + case (char)22: + case (char)23: + case (char)24: + case (char)25: + case (char)26: + case (char)27: + case (char)28: + case (char)29: + case (char)30: + case (char)31: + case (char)32: + case (char)33: + case (char)35: + case (char)36: + case (char)37: + case (char)38: + case (char)39: + case (char)40: + case (char)41: + case (char)42: + case (char)43: + case (char)44: + case (char)45: + case (char)46: + case (char)47: + case (char)48: + case (char)49: + case (char)50: + case (char)51: + case (char)52: + case (char)53: + case (char)54: + case (char)55: + case (char)56: + case (char)57: + case (char)58: + case (char)59: + case (char)60: + case (char)61: + case (char)62: + case (char)63: + case (char)64: + case (char)65: + case (char)66: + case (char)67: + case (char)68: + case (char)69: + case (char)70: + case (char)71: + case (char)72: + case (char)73: + case (char)74: + case (char)75: + case (char)76: + case (char)77: + case (char)78: + case (char)79: + case (char)80: + case (char)81: + case (char)82: + case (char)83: + case (char)84: + case (char)85: + case (char)86: + case (char)87: + case (char)88: + case (char)89: + case (char)90: + case (char)91: + default: + continue; + } + + max += 2; + BinaryUtil.EnsureCapacity(ref buffer, startoffset, max); // check +escape capacity + + offset += StringEncoding.UTF8.GetBytes(value, from, i - from, buffer, offset); + from = i + 1; + buffer[offset++] = (byte)'\\'; + buffer[offset++] = escapeChar; + } + + if (from != value.Length) + { + offset += StringEncoding.UTF8.GetBytes(value, from, value.Length - from, buffer, offset); + } + + buffer[offset++] = (byte)'\"'; + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/AttributeFormatterResolver.cs b/Unity3D/3rdLib/Utf8Json/Resolvers/AttributeFormatterResolver.cs new file mode 100644 index 0000000..4d12dbb --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/AttributeFormatterResolver.cs @@ -0,0 +1,61 @@ +using System; +using System.Reflection; +using System.Collections.Generic; +using System.Text; +using Utf8Json.Internal; + +namespace Utf8Json.Resolvers +{ + /// + /// Get formatter from [JsonFormatter] attribute. + /// + public sealed class AttributeFormatterResolver : IJsonFormatterResolver + { + public static IJsonFormatterResolver Instance = new AttributeFormatterResolver(); + + AttributeFormatterResolver() + { + + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { +#if (UNITY_METRO || UNITY_WSA) && !NETFX_CORE + var attr = (JsonFormatterAttribute)typeof(T).GetCustomAttributes(typeof(JsonFormatterAttribute), true).FirstOrDefault(); +#else + var attr = typeof(T).GetTypeInfo().GetCustomAttribute(); +#endif + if (attr == null) + { + return; + } + + try + { + if (attr.FormatterType.IsGenericType && !attr.FormatterType.GetTypeInfo().IsConstructedGenericType()) + { + var t = attr.FormatterType.MakeGenericType(typeof(T)); // use T self + formatter = (IJsonFormatter)Activator.CreateInstance(t, attr.Arguments); + } + else + { + formatter = (IJsonFormatter)Activator.CreateInstance(attr.FormatterType, attr.Arguments); + } + } + catch (Exception ex) + { + throw new InvalidOperationException("Can not create formatter from JsonFormatterAttribute, check the target formatter is public and has constructor with right argument. FormatterType:" + attr.FormatterType.Name, ex); + } + } + } + } +} diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/AttributeFormatterResolver.cs.meta b/Unity3D/3rdLib/Utf8Json/Resolvers/AttributeFormatterResolver.cs.meta new file mode 100644 index 0000000..b204763 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/AttributeFormatterResolver.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a9818ac7b5d446e98793a9a8532bd285 +timeCreated: 1668660997 \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/BuiltinResolver.cs b/Unity3D/3rdLib/Utf8Json/Resolvers/BuiltinResolver.cs new file mode 100644 index 0000000..e4319c6 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/BuiltinResolver.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using Utf8Json.Formatters; + +namespace Utf8Json.Resolvers +{ + public sealed class BuiltinResolver : IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new BuiltinResolver(); + + BuiltinResolver() + { + + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + // Reduce IL2CPP code generate size(don't write long code in ) + formatter = (IJsonFormatter)BuiltinResolverGetFormatterHelper.GetFormatter(typeof(T)); + } + } + + // used from PrimitiveObjectFormatter + internal static class BuiltinResolverGetFormatterHelper + { + static readonly Dictionary formatterMap = new Dictionary() + { + // Primitive + {typeof(Int16), Int16Formatter.Default}, + {typeof(Int32), Int32Formatter.Default}, + {typeof(Int64), Int64Formatter.Default}, + {typeof(UInt16), UInt16Formatter.Default}, + {typeof(UInt32), UInt32Formatter.Default}, + {typeof(UInt64), UInt64Formatter.Default}, + {typeof(Single), SingleFormatter.Default}, + {typeof(Double), DoubleFormatter.Default}, + {typeof(bool), BooleanFormatter.Default}, + {typeof(byte), ByteFormatter.Default}, + {typeof(sbyte), SByteFormatter.Default}, + + // Nulllable Primitive + {typeof(Nullable), NullableInt16Formatter.Default}, + {typeof(Nullable), NullableInt32Formatter.Default}, + {typeof(Nullable), NullableInt64Formatter.Default}, + {typeof(Nullable), NullableUInt16Formatter.Default}, + {typeof(Nullable), NullableUInt32Formatter.Default}, + {typeof(Nullable), NullableUInt64Formatter.Default}, + {typeof(Nullable), NullableSingleFormatter.Default}, + {typeof(Nullable), NullableDoubleFormatter.Default}, + {typeof(Nullable), NullableBooleanFormatter.Default}, + {typeof(Nullable), NullableByteFormatter.Default}, + {typeof(Nullable), NullableSByteFormatter.Default}, + + // StandardClassLibraryFormatter + + // DateTime + {typeof(DateTime), ISO8601DateTimeFormatter.Default}, // ISO8601 + {typeof(TimeSpan), ISO8601TimeSpanFormatter.Default}, + {typeof(DateTimeOffset), ISO8601DateTimeOffsetFormatter.Default}, + {typeof(DateTime?), new StaticNullableFormatter(ISO8601DateTimeFormatter.Default)}, // ISO8601 + {typeof(TimeSpan?), new StaticNullableFormatter(ISO8601TimeSpanFormatter.Default)}, + {typeof(DateTimeOffset?),new StaticNullableFormatter(ISO8601DateTimeOffsetFormatter.Default)}, + + {typeof(string), NullableStringFormatter.Default}, + {typeof(char), CharFormatter.Default}, + {typeof(Nullable), NullableCharFormatter.Default}, + {typeof(decimal), DecimalFormatter.Default}, + {typeof(decimal?), new StaticNullableFormatter(DecimalFormatter.Default)}, + {typeof(Guid), GuidFormatter.Default}, + {typeof(Guid?), new StaticNullableFormatter(GuidFormatter.Default)}, + {typeof(Uri), UriFormatter.Default}, + {typeof(Version), VersionFormatter.Default}, + {typeof(StringBuilder), StringBuilderFormatter.Default}, + {typeof(BitArray), BitArrayFormatter.Default}, + {typeof(Type), TypeFormatter.Default}, + + // special primitive + {typeof(byte[]), ByteArrayFormatter.Default}, + + // otpmitized primitive array formatter + {typeof(Int16[]), Int16ArrayFormatter.Default}, + {typeof(Int32[]), Int32ArrayFormatter.Default}, + {typeof(Int64[]), Int64ArrayFormatter.Default}, + {typeof(UInt16[]), UInt16ArrayFormatter.Default}, + {typeof(UInt32[]), UInt32ArrayFormatter.Default}, + {typeof(UInt64[]), UInt64ArrayFormatter.Default}, + {typeof(Single[]), SingleArrayFormatter.Default}, + {typeof(Double[]), DoubleArrayFormatter.Default}, + {typeof(Boolean[]), BooleanArrayFormatter.Default}, + {typeof(SByte[]), SByteArrayFormatter.Default}, + + {typeof(Char[]), CharArrayFormatter.Default}, + {typeof(string[]), NullableStringArrayFormatter.Default}, + + // well known collections + {typeof(List), new ListFormatter()}, + {typeof(List), new ListFormatter()}, + {typeof(List), new ListFormatter()}, + {typeof(List), new ListFormatter()}, + {typeof(List), new ListFormatter()}, + {typeof(List), new ListFormatter()}, + {typeof(List), new ListFormatter()}, + {typeof(List), new ListFormatter()}, + {typeof(List), new ListFormatter()}, + {typeof(List), new ListFormatter()}, + {typeof(List), new ListFormatter()}, + {typeof(List), new ListFormatter()}, + {typeof(List), new ListFormatter()}, + {typeof(List), new ListFormatter()}, + + { typeof(ArraySegment), ByteArraySegmentFormatter.Default }, + { typeof(ArraySegment?),new StaticNullableFormatter>(ByteArraySegmentFormatter.Default) }, + + #if NETSTANDARD + {typeof(System.Numerics.BigInteger), BigIntegerFormatter.Default}, + {typeof(System.Numerics.BigInteger?), new StaticNullableFormatter(BigIntegerFormatter.Default)}, + {typeof(System.Numerics.Complex), ComplexFormatter.Default}, + {typeof(System.Numerics.Complex?), new StaticNullableFormatter(ComplexFormatter.Default)}, + {typeof(System.Dynamic.ExpandoObject), ExpandoObjectFormatter.Default }, + {typeof(System.Threading.Tasks.Task), TaskUnitFormatter.Default}, + #endif + }; + + internal static object GetFormatter(Type t) + { + object formatter; + if (formatterMap.TryGetValue(t, out formatter)) + { + return formatter; + } + + return null; + } + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/BuiltinResolver.cs.meta b/Unity3D/3rdLib/Utf8Json/Resolvers/BuiltinResolver.cs.meta new file mode 100644 index 0000000..6d47912 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/BuiltinResolver.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3aed887c2fd642dd86e16bee452d29b8 +timeCreated: 1668660996 \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/CompositeResolver.cs b/Unity3D/3rdLib/Utf8Json/Resolvers/CompositeResolver.cs new file mode 100644 index 0000000..f4ced9b --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/CompositeResolver.cs @@ -0,0 +1,228 @@ +using System; +using System.Reflection; +using System.Reflection.Emit; +using Utf8Json.Internal.Emit; + +namespace Utf8Json.Resolvers +{ + public sealed class CompositeResolver : IJsonFormatterResolver + { + public static readonly CompositeResolver Instance = new CompositeResolver(); + + static bool isFreezed = false; + static IJsonFormatter[] formatters = new IJsonFormatter[0]; + static IJsonFormatterResolver[] resolvers = new IJsonFormatterResolver[0]; + + CompositeResolver() + { + } + + public static void Register(params IJsonFormatterResolver[] resolvers) + { + if (isFreezed) + { + throw new InvalidOperationException("Register must call on startup(before use GetFormatter)."); + } + + CompositeResolver.resolvers = resolvers; + } + + public static void Register(params IJsonFormatter[] formatters) + { + if (isFreezed) + { + throw new InvalidOperationException("Register must call on startup(before use GetFormatter)."); + } + + CompositeResolver.formatters = formatters; + } + + public static void Register(IJsonFormatter[] formatters, IJsonFormatterResolver[] resolvers) + { + if (isFreezed) + { + throw new InvalidOperationException("Register must call on startup(before use GetFormatter)."); + } + + CompositeResolver.resolvers = resolvers; + CompositeResolver.formatters = formatters; + } + + public static void RegisterAndSetAsDefault(params IJsonFormatterResolver[] resolvers) + { + Register(resolvers); + JsonSerializer.SetDefaultResolver(CompositeResolver.Instance); + } + + public static void RegisterAndSetAsDefault(params IJsonFormatter[] formatters) + { + Register(formatters); + JsonSerializer.SetDefaultResolver(CompositeResolver.Instance); + } + + public static void RegisterAndSetAsDefault(IJsonFormatter[] formatters, IJsonFormatterResolver[] resolvers) + { + Register(formatters); + Register(resolvers); + JsonSerializer.SetDefaultResolver(CompositeResolver.Instance); + } + + public static IJsonFormatterResolver Create(params IJsonFormatter[] formatters) + { + return Create(formatters, new IJsonFormatterResolver[0]); + } + + public static IJsonFormatterResolver Create(params IJsonFormatterResolver[] resolvers) + { + return Create(new IJsonFormatter[0], resolvers); + } + + public static IJsonFormatterResolver Create(IJsonFormatter[] formatters, IJsonFormatterResolver[] resolvers) + { + return DynamicCompositeResolver.Create(formatters, resolvers); + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + isFreezed = true; + + foreach (var item in formatters) + { + foreach (var implInterface in item.GetType().GetTypeInfo().ImplementedInterfaces) + { + var ti = implInterface.GetTypeInfo(); + if (ti.IsGenericType && ti.GenericTypeArguments[0] == typeof(T)) + { + formatter = (IJsonFormatter)item; + return; + } + } + } + + foreach (var item in resolvers) + { + var f = item.GetFormatter(); + if (f != null) + { + formatter = f; + return; + } + } + } + } + } + + public abstract class DynamicCompositeResolver : IJsonFormatterResolver + { + const string ModuleName = "Utf8Json.Resolvers.DynamicCompositeResolver"; + + static readonly DynamicAssembly assembly; + + static DynamicCompositeResolver() + { + assembly = new DynamicAssembly(ModuleName); + } + +#if DEBUG && (NET45 || NET47) + public static AssemblyBuilder Save() + { + return assembly.Save(); + } +#endif + + public static IJsonFormatterResolver Create(IJsonFormatter[] formatters, IJsonFormatterResolver[] resolvers) + { + var id = Guid.NewGuid().ToString().Replace("-", ""); + var resolverType = assembly.DefineType("DynamicCompositeResolver_" + id, TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed, typeof(DynamicCompositeResolver)); + var cacheType = assembly.DefineType("DynamicCompositeResolverCache_" + id, TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed, null); + var genericP = cacheType.DefineGenericParameters("T")[0]; + + var resolverInstanceField = resolverType.DefineField("instance", resolverType, FieldAttributes.Public | FieldAttributes.Static); + + var f = cacheType.DefineField("formatter", typeof(IJsonFormatter<>).MakeGenericType(genericP), FieldAttributes.Static | FieldAttributes.Public); + { + var cctor = cacheType.DefineConstructor(MethodAttributes.Static, CallingConventions.Standard, Type.EmptyTypes); + var il = cctor.GetILGenerator(); + il.EmitLdsfld(resolverInstanceField); + il.EmitCall(typeof(DynamicCompositeResolver).GetMethod("GetFormatterLoop").MakeGenericMethod(genericP)); + il.Emit(OpCodes.Stsfld, f); + il.Emit(OpCodes.Ret); + } + var cacheTypeT = cacheType.CreateTypeInfo().AsType(); + + { + var ctor = resolverType.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] { typeof(IJsonFormatter[]), typeof(IJsonFormatterResolver[]) }); + var il = ctor.GetILGenerator(); + il.EmitLdarg(0); + il.EmitLdarg(1); + il.EmitLdarg(2); + il.Emit(OpCodes.Call, typeof(DynamicCompositeResolver).GetConstructors()[0]); + il.Emit(OpCodes.Ret); + } + { + var m = resolverType.DefineMethod("GetFormatter", MethodAttributes.Public | MethodAttributes.Virtual); + + var gpp = m.DefineGenericParameters("T")[0]; + m.SetReturnType(typeof(IJsonFormatter<>).MakeGenericType(gpp)); + + var il = m.GetILGenerator(); + var formatterField = TypeBuilder.GetField(cacheTypeT.MakeGenericType(gpp), cacheTypeT.GetField("formatter", BindingFlags.Public | BindingFlags.Static | BindingFlags.GetField)); + il.EmitLdsfld(formatterField); + il.Emit(OpCodes.Ret); + } + + var resolverT = resolverType.CreateTypeInfo().AsType(); + var instance = Activator.CreateInstance(resolverT, new object[] { formatters, resolvers }); + var finfo = instance.GetType().GetField("instance", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + finfo.SetValue(null, instance); + + return (IJsonFormatterResolver)instance; + } + + public readonly IJsonFormatter[] formatters; + public readonly IJsonFormatterResolver[] resolvers; + + public DynamicCompositeResolver(IJsonFormatter[] formatters, IJsonFormatterResolver[] resolvers) + { + this.formatters = formatters; + this.resolvers = resolvers; + } + + public IJsonFormatter GetFormatterLoop() + { + foreach (var item in formatters) + { + foreach (var implInterface in item.GetType().GetTypeInfo().ImplementedInterfaces) + { + var ti = implInterface.GetTypeInfo(); + if (ti.IsGenericType && ti.GenericTypeArguments[0] == typeof(T)) + { + return (IJsonFormatter)(object)item; + } + } + } + + foreach (var item in resolvers) + { + var f = item.GetFormatter(); + if (f != null) + { + return f; + } + } + + return null; + } + + public abstract IJsonFormatter GetFormatter(); + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/CompositeResolver.cs.meta b/Unity3D/3rdLib/Utf8Json/Resolvers/CompositeResolver.cs.meta new file mode 100644 index 0000000..f0d5719 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/CompositeResolver.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a270a7130df3467d8d03bdddea1d6cbd +timeCreated: 1668660996 \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/DynamicGenericResolver.cs b/Unity3D/3rdLib/Utf8Json/Resolvers/DynamicGenericResolver.cs new file mode 100644 index 0000000..643cdc3 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/DynamicGenericResolver.cs @@ -0,0 +1,309 @@ +using System.Reflection; +using System.Collections; +using System.Linq; +using Utf8Json.Internal; +using System; +using Utf8Json.Formatters; +using System.Collections.Generic; +using Utf8Json.Resolvers.Internal; +using System.Collections.ObjectModel; + +#if NETSTANDARD +using System.Threading.Tasks; +#endif + +namespace Utf8Json.Resolvers +{ + public sealed class DynamicGenericResolver : IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new DynamicGenericResolver(); + + DynamicGenericResolver() + { + + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + formatter = (IJsonFormatter)DynamicGenericResolverGetFormatterHelper.GetFormatter(typeof(T)); + } + } + } +} + +namespace Utf8Json.Resolvers.Internal +{ + internal static class DynamicGenericResolverGetFormatterHelper + { + static readonly Dictionary formatterMap = new Dictionary() + { + {typeof(List<>), typeof(ListFormatter<>)}, + {typeof(LinkedList<>), typeof(LinkedListFormatter<>)}, + {typeof(Queue<>), typeof(QeueueFormatter<>)}, + {typeof(Stack<>), typeof(StackFormatter<>)}, + {typeof(HashSet<>), typeof(HashSetFormatter<>)}, + {typeof(ReadOnlyCollection<>), typeof(ReadOnlyCollectionFormatter<>)}, + {typeof(IList<>), typeof(InterfaceListFormatter<>)}, + {typeof(ICollection<>), typeof(InterfaceCollectionFormatter<>)}, + {typeof(IEnumerable<>), typeof(InterfaceEnumerableFormatter<>)}, + {typeof(Dictionary<,>), typeof(DictionaryFormatter<,>)}, + {typeof(IDictionary<,>), typeof(InterfaceDictionaryFormatter<,>)}, + {typeof(SortedDictionary<,>), typeof(SortedDictionaryFormatter<,>)}, + {typeof(SortedList<,>), typeof(SortedListFormatter<,>)}, + {typeof(ILookup<,>), typeof(InterfaceLookupFormatter<,>)}, + {typeof(IGrouping<,>), typeof(InterfaceGroupingFormatter<,>)}, + #if NETSTANDARD + {typeof(ObservableCollection<>), typeof(ObservableCollectionFormatter<>)}, + {typeof(ReadOnlyObservableCollection<>),(typeof(ReadOnlyObservableCollectionFormatter<>))}, + {typeof(IReadOnlyList<>), typeof(InterfaceReadOnlyListFormatter<>)}, + {typeof(IReadOnlyCollection<>), typeof(InterfaceReadOnlyCollectionFormatter<>)}, + {typeof(ISet<>), typeof(InterfaceSetFormatter<>)}, + {typeof(System.Collections.Concurrent.ConcurrentBag<>), typeof(ConcurrentBagFormatter<>)}, + {typeof(System.Collections.Concurrent.ConcurrentQueue<>), typeof(ConcurrentQueueFormatter<>)}, + {typeof(System.Collections.Concurrent.ConcurrentStack<>), typeof(ConcurrentStackFormatter<>)}, + {typeof(ReadOnlyDictionary<,>), typeof(ReadOnlyDictionaryFormatter<,>)}, + {typeof(IReadOnlyDictionary<,>), typeof(InterfaceReadOnlyDictionaryFormatter<,>)}, + {typeof(System.Collections.Concurrent.ConcurrentDictionary<,>), typeof(ConcurrentDictionaryFormatter<,>)}, + {typeof(Lazy<>), typeof(LazyFormatter<>)}, + {typeof(Task<>), typeof(TaskValueFormatter<>)}, + #endif + }; + + // Reduce IL2CPP code generate size(don't write long code in ) + internal static object GetFormatter(Type t) + { + var ti = t.GetTypeInfo(); + + if (t.IsArray) + { + var rank = t.GetArrayRank(); + if (rank == 1) + { + if (t.GetElementType() == typeof(byte)) // byte[] is also supported in builtin formatter. + { + return ByteArrayFormatter.Default; + } + + return Activator.CreateInstance(typeof(ArrayFormatter<>).MakeGenericType(t.GetElementType())); + } + else if (rank == 2) + { + return Activator.CreateInstance(typeof(TwoDimentionalArrayFormatter<>).MakeGenericType(t.GetElementType())); + } + else if (rank == 3) + { + return Activator.CreateInstance(typeof(ThreeDimentionalArrayFormatter<>).MakeGenericType(t.GetElementType())); + } + else if (rank == 4) + { + return Activator.CreateInstance(typeof(FourDimentionalArrayFormatter<>).MakeGenericType(t.GetElementType())); + } + else + { + return null; // not supported built-in + } + } + else if (ti.IsGenericType) + { + var genericType = ti.GetGenericTypeDefinition(); + var genericTypeInfo = genericType.GetTypeInfo(); + var isNullable = genericTypeInfo.IsNullable(); + var nullableElementType = isNullable ? ti.GenericTypeArguments[0] : null; + + if (genericType == typeof(KeyValuePair<,>)) + { + return CreateInstance(typeof(KeyValuePairFormatter<,>), ti.GenericTypeArguments); + } + else if (isNullable && nullableElementType.GetTypeInfo().IsConstructedGenericType() && nullableElementType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>)) + { + return CreateInstance(typeof(NullableFormatter<>), new[] { nullableElementType }); + } + +#if NETSTANDARD + + // ValueTask + else if (genericType == typeof(ValueTask<>)) + { + return CreateInstance(typeof(ValueTaskFormatter<>), ti.GenericTypeArguments); + } + else if (isNullable && nullableElementType.IsConstructedGenericType && nullableElementType.GetGenericTypeDefinition() == typeof(ValueTask<>)) + { + return CreateInstance(typeof(NullableFormatter<>), new[] { nullableElementType }); + } + + // Tuple + else if (ti.FullName.StartsWith("System.Tuple")) + { + Type tupleFormatterType = null; + switch (ti.GenericTypeArguments.Length) + { + case 1: + tupleFormatterType = typeof(TupleFormatter<>); + break; + case 2: + tupleFormatterType = typeof(TupleFormatter<,>); + break; + case 3: + tupleFormatterType = typeof(TupleFormatter<,,>); + break; + case 4: + tupleFormatterType = typeof(TupleFormatter<,,,>); + break; + case 5: + tupleFormatterType = typeof(TupleFormatter<,,,,>); + break; + case 6: + tupleFormatterType = typeof(TupleFormatter<,,,,,>); + break; + case 7: + tupleFormatterType = typeof(TupleFormatter<,,,,,,>); + break; + case 8: + tupleFormatterType = typeof(TupleFormatter<,,,,,,,>); + break; + default: + break; + } + + return CreateInstance(tupleFormatterType, ti.GenericTypeArguments); + } + + // ValueTuple + else if (ti.FullName.StartsWith("System.ValueTuple")) + { + Type tupleFormatterType = null; + switch (ti.GenericTypeArguments.Length) + { + case 1: + tupleFormatterType = typeof(ValueTupleFormatter<>); + break; + case 2: + tupleFormatterType = typeof(ValueTupleFormatter<,>); + break; + case 3: + tupleFormatterType = typeof(ValueTupleFormatter<,,>); + break; + case 4: + tupleFormatterType = typeof(ValueTupleFormatter<,,,>); + break; + case 5: + tupleFormatterType = typeof(ValueTupleFormatter<,,,,>); + break; + case 6: + tupleFormatterType = typeof(ValueTupleFormatter<,,,,,>); + break; + case 7: + tupleFormatterType = typeof(ValueTupleFormatter<,,,,,,>); + break; + case 8: + tupleFormatterType = typeof(ValueTupleFormatter<,,,,,,,>); + break; + default: + break; + } + + return CreateInstance(tupleFormatterType, ti.GenericTypeArguments); + } + +#endif + + // ArraySegement + else if (genericType == typeof(ArraySegment<>)) + { + if (ti.GenericTypeArguments[0] == typeof(byte)) + { + return ByteArraySegmentFormatter.Default; + } + else + { + return CreateInstance(typeof(ArraySegmentFormatter<>), ti.GenericTypeArguments); + } + } + else if (isNullable && nullableElementType.GetTypeInfo().IsConstructedGenericType() && nullableElementType.GetGenericTypeDefinition() == typeof(ArraySegment<>)) + { + if (nullableElementType == typeof(ArraySegment)) + { + return new StaticNullableFormatter>(ByteArraySegmentFormatter.Default); + } + else + { + return CreateInstance(typeof(NullableFormatter<>), new[] { nullableElementType }); + } + } + + // Mapped formatter + else + { + Type formatterType; + if (formatterMap.TryGetValue(genericType, out formatterType)) + { + return CreateInstance(formatterType, ti.GenericTypeArguments); + } + + // generic collection + else if (ti.GenericTypeArguments.Length == 1 + && ti.ImplementedInterfaces.Any(x => x.GetTypeInfo().IsConstructedGenericType() && x.GetGenericTypeDefinition() == typeof(ICollection<>)) + && ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0)) + { + var elemType = ti.GenericTypeArguments[0]; + return CreateInstance(typeof(GenericCollectionFormatter<,>), new[] { elemType, t }); + } + // generic dictionary + else if (ti.GenericTypeArguments.Length == 2 + && ti.ImplementedInterfaces.Any(x => x.GetTypeInfo().IsConstructedGenericType() && x.GetGenericTypeDefinition() == typeof(IDictionary<,>)) + && ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0)) + { + var keyType = ti.GenericTypeArguments[0]; + var valueType = ti.GenericTypeArguments[1]; + return CreateInstance(typeof(GenericDictionaryFormatter<,,>), new[] { keyType, valueType, t }); + } + } + } + else + { + // NonGeneric Collection + if (t == typeof(IEnumerable)) + { + return NonGenericInterfaceEnumerableFormatter.Default; + } + else if (t == typeof(ICollection)) + { + return NonGenericInterfaceCollectionFormatter.Default; + } + else if (t == typeof(IList)) + { + return NonGenericInterfaceListFormatter.Default; + } + else if (t == typeof(IDictionary)) + { + return NonGenericInterfaceDictionaryFormatter.Default; + } + if (typeof(IList).GetTypeInfo().IsAssignableFrom(ti) && ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0)) + { + return Activator.CreateInstance(typeof(NonGenericListFormatter<>).MakeGenericType(t)); + } + else if (typeof(IDictionary).GetTypeInfo().IsAssignableFrom(ti) && ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0)) + { + return Activator.CreateInstance(typeof(NonGenericDictionaryFormatter<>).MakeGenericType(t)); + } + } + + return null; + } + + static object CreateInstance(Type genericType, Type[] genericTypeArguments, params object[] arguments) + { + return Activator.CreateInstance(genericType.MakeGenericType(genericTypeArguments), arguments); + } + } +} + diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/DynamicGenericResolver.cs.meta b/Unity3D/3rdLib/Utf8Json/Resolvers/DynamicGenericResolver.cs.meta new file mode 100644 index 0000000..a7f1cbc --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/DynamicGenericResolver.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 778188ad03464177a45b91f45d5cc8cd +timeCreated: 1668660997 \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/DynamicObjectResolver.cs b/Unity3D/3rdLib/Utf8Json/Resolvers/DynamicObjectResolver.cs new file mode 100644 index 0000000..8ba36e0 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/DynamicObjectResolver.cs @@ -0,0 +1,1606 @@ +using System; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using Utf8Json.Internal.Emit; +using Utf8Json.Internal; +using Utf8Json.Formatters; +using System.Text.RegularExpressions; +using System.Threading; +using System.Reflection.Emit; +using Utf8Json.Resolvers.Internal; + +namespace Utf8Json.Resolvers +{ + /// + /// ObjectResolver by dynamic code generation. + /// + public static class DynamicObjectResolver + { + /// AllowPrivate:False, ExcludeNull:False, NameMutate:Original + public static readonly IJsonFormatterResolver Default = DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateOriginal.Instance; + /// AllowPrivate:False, ExcludeNull:False, NameMutate:CamelCase + public static readonly IJsonFormatterResolver CamelCase = DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateCamelCase.Instance; + /// AllowPrivate:False, ExcludeNull:False, NameMutate:SnakeCase + public static readonly IJsonFormatterResolver SnakeCase = DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateSnakeCase.Instance; + /// AllowPrivate:False, ExcludeNull:True, NameMutate:Original + public static readonly IJsonFormatterResolver ExcludeNull = DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateOriginal.Instance; + /// AllowPrivate:False, ExcludeNull:True, NameMutate:CamelCase + public static readonly IJsonFormatterResolver ExcludeNullCamelCase = DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateCamelCase.Instance; + /// AllowPrivate:False, ExcludeNull:True, NameMutate:SnakeCase + public static readonly IJsonFormatterResolver ExcludeNullSnakeCase = DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateSnakeCase.Instance; + + /// AllowPrivate:True, ExcludeNull:False, NameMutate:Original + public static readonly IJsonFormatterResolver AllowPrivate = DynamicObjectResolverAllowPrivateTrueExcludeNullFalseNameMutateOriginal.Instance; + /// AllowPrivate:True, ExcludeNull:False, NameMutate:CamelCase + public static readonly IJsonFormatterResolver AllowPrivateCamelCase = DynamicObjectResolverAllowPrivateTrueExcludeNullFalseNameMutateCamelCase.Instance; + /// AllowPrivate:True, ExcludeNull:False, NameMutate:SnakeCase + public static readonly IJsonFormatterResolver AllowPrivateSnakeCase = DynamicObjectResolverAllowPrivateTrueExcludeNullFalseNameMutateSnakeCase.Instance; + /// AllowPrivate:True, ExcludeNull:True, NameMutate:Original + public static readonly IJsonFormatterResolver AllowPrivateExcludeNull = DynamicObjectResolverAllowPrivateTrueExcludeNullTrueNameMutateOriginal.Instance; + /// AllowPrivate:True, ExcludeNull:True, NameMutate:CamelCase + public static readonly IJsonFormatterResolver AllowPrivateExcludeNullCamelCase = DynamicObjectResolverAllowPrivateTrueExcludeNullTrueNameMutateCamelCase.Instance; + /// AllowPrivate:True, ExcludeNull:True, NameMutate:SnakeCase + public static readonly IJsonFormatterResolver AllowPrivateExcludeNullSnakeCase = DynamicObjectResolverAllowPrivateTrueExcludeNullTrueNameMutateSnakeCase.Instance; + } +} + +namespace Utf8Json.Resolvers.Internal +{ +#if DEBUG && (NET45 || NET47) + public interface ISave + { + AssemblyBuilder Save(); + } +#endif + + #region DynamicAssembly + + internal sealed class DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateOriginal : IJsonFormatterResolver +#if DEBUG && (NET45 || NET47) + , ISave +#endif + { + // configuration + public static readonly IJsonFormatterResolver Instance = new DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateOriginal(); + static readonly Func nameMutator = StringMutator.Original; + static readonly bool excludeNull = false; + const string ModuleName = "Utf8Json.Resolvers.DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateOriginal"; + + static readonly DynamicAssembly assembly; + + static DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateOriginal() + { + assembly = new DynamicAssembly(ModuleName); + } + + DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateOriginal() + { + } + +#if DEBUG && (NET45 || NET47) + public AssemblyBuilder Save() + { + return assembly.Save(); + } +#endif + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + formatter = (IJsonFormatter)DynamicObjectTypeBuilder.BuildFormatterToAssembly(assembly, Instance, nameMutator, excludeNull); + } + } + } + + internal sealed class DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateCamelCase : IJsonFormatterResolver +#if DEBUG && (NET45 || NET47) + , ISave +#endif + { + // configuration + public static readonly IJsonFormatterResolver Instance = new DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateCamelCase(); + static readonly Func nameMutator = StringMutator.ToCamelCase; + static readonly bool excludeNull = false; + const string ModuleName = "Utf8Json.Resolvers.DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateCamelCase"; + + static readonly DynamicAssembly assembly; + + static DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateCamelCase() + { + assembly = new DynamicAssembly(ModuleName); + } + + DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateCamelCase() + { + } + +#if DEBUG && (NET45 || NET47) + public AssemblyBuilder Save() + { + return assembly.Save(); + } +#endif + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + formatter = (IJsonFormatter)DynamicObjectTypeBuilder.BuildFormatterToAssembly(assembly, Instance, nameMutator, excludeNull); + } + } + } + + internal sealed class DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateSnakeCase : IJsonFormatterResolver +#if DEBUG && (NET45 || NET47) + , ISave +#endif + { + // configuration + public static readonly IJsonFormatterResolver Instance = new DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateSnakeCase(); + static readonly Func nameMutator = StringMutator.ToSnakeCase; + static readonly bool excludeNull = false; + const string ModuleName = "Utf8Json.Resolvers.DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateSnakeCase"; + + static readonly DynamicAssembly assembly; + + static DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateSnakeCase() + { + assembly = new DynamicAssembly(ModuleName); + } + + DynamicObjectResolverAllowPrivateFalseExcludeNullFalseNameMutateSnakeCase() + { + } + +#if DEBUG && (NET45 || NET47) + public AssemblyBuilder Save() + { + return assembly.Save(); + } +#endif + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + formatter = (IJsonFormatter)DynamicObjectTypeBuilder.BuildFormatterToAssembly(assembly, Instance, nameMutator, excludeNull); + } + } + } + + internal sealed class DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateOriginal : IJsonFormatterResolver +#if DEBUG && (NET45 || NET47) + , ISave +#endif + { + // configuration + public static readonly IJsonFormatterResolver Instance = new DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateOriginal(); + static readonly Func nameMutator = StringMutator.Original; + static readonly bool excludeNull = true; + const string ModuleName = "Utf8Json.Resolvers.DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateOriginal"; + + static readonly DynamicAssembly assembly; + + static DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateOriginal() + { + assembly = new DynamicAssembly(ModuleName); + } + + DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateOriginal() + { + } + +#if DEBUG && (NET45 || NET47) + public AssemblyBuilder Save() + { + return assembly.Save(); + } +#endif + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + formatter = (IJsonFormatter)DynamicObjectTypeBuilder.BuildFormatterToAssembly(assembly, Instance, nameMutator, excludeNull); + } + } + } + + internal sealed class DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateCamelCase : IJsonFormatterResolver +#if DEBUG && (NET45 || NET47) + , ISave +#endif + { + // configuration + public static readonly IJsonFormatterResolver Instance = new DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateCamelCase(); + static readonly Func nameMutator = StringMutator.ToCamelCase; + static readonly bool excludeNull = true; + const string ModuleName = "Utf8Json.Resolvers.DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateCamelCase"; + + static readonly DynamicAssembly assembly; + + static DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateCamelCase() + { + assembly = new DynamicAssembly(ModuleName); + } + + DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateCamelCase() + { + } + +#if DEBUG && (NET45 || NET47) + public AssemblyBuilder Save() + { + return assembly.Save(); + } +#endif + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + formatter = (IJsonFormatter)DynamicObjectTypeBuilder.BuildFormatterToAssembly(assembly, Instance, nameMutator, excludeNull); + } + } + } + + internal sealed class DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateSnakeCase : IJsonFormatterResolver +#if DEBUG && (NET45 || NET47) + , ISave +#endif + { + // configuration + public static readonly IJsonFormatterResolver Instance = new DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateSnakeCase(); + static readonly Func nameMutator = StringMutator.ToSnakeCase; + static readonly bool excludeNull = true; + const string ModuleName = "Utf8Json.Resolvers.DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateSnakeCase"; + + static readonly DynamicAssembly assembly; + + static DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateSnakeCase() + { + assembly = new DynamicAssembly(ModuleName); + } + + DynamicObjectResolverAllowPrivateFalseExcludeNullTrueNameMutateSnakeCase() + { + } + +#if DEBUG && (NET45 || NET47) + public AssemblyBuilder Save() + { + return assembly.Save(); + } +#endif + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + formatter = (IJsonFormatter)DynamicObjectTypeBuilder.BuildFormatterToAssembly(assembly, Instance, nameMutator, excludeNull); + } + } + } + + #endregion + + #region DynamicMethod + + internal sealed class DynamicObjectResolverAllowPrivateTrueExcludeNullFalseNameMutateOriginal : IJsonFormatterResolver + { + // configuration + public static readonly IJsonFormatterResolver Instance = new DynamicObjectResolverAllowPrivateTrueExcludeNullFalseNameMutateOriginal(); + static readonly Func nameMutator = StringMutator.Original; + static readonly bool excludeNull = false; + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + formatter = (IJsonFormatter)DynamicObjectTypeBuilder.BuildFormatterToDynamicMethod(Instance, nameMutator, excludeNull, true); + } + } + } + + internal sealed class DynamicObjectResolverAllowPrivateTrueExcludeNullFalseNameMutateCamelCase : IJsonFormatterResolver + { + // configuration + public static readonly IJsonFormatterResolver Instance = new DynamicObjectResolverAllowPrivateTrueExcludeNullFalseNameMutateCamelCase(); + static readonly Func nameMutator = StringMutator.ToCamelCase; + static readonly bool excludeNull = false; + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + formatter = (IJsonFormatter)DynamicObjectTypeBuilder.BuildFormatterToDynamicMethod(Instance, nameMutator, excludeNull, true); + } + } + } + + internal sealed class DynamicObjectResolverAllowPrivateTrueExcludeNullFalseNameMutateSnakeCase : IJsonFormatterResolver + { + // configuration + public static readonly IJsonFormatterResolver Instance = new DynamicObjectResolverAllowPrivateTrueExcludeNullFalseNameMutateSnakeCase(); + static readonly Func nameMutator = StringMutator.ToSnakeCase; + static readonly bool excludeNull = false; + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + formatter = (IJsonFormatter)DynamicObjectTypeBuilder.BuildFormatterToDynamicMethod(Instance, nameMutator, excludeNull, true); + } + } + } + + internal sealed class DynamicObjectResolverAllowPrivateTrueExcludeNullTrueNameMutateOriginal : IJsonFormatterResolver + { + // configuration + public static readonly IJsonFormatterResolver Instance = new DynamicObjectResolverAllowPrivateTrueExcludeNullTrueNameMutateOriginal(); + static readonly Func nameMutator = StringMutator.Original; + static readonly bool excludeNull = true; + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + formatter = (IJsonFormatter)DynamicObjectTypeBuilder.BuildFormatterToDynamicMethod(Instance, nameMutator, excludeNull, true); + } + } + } + + internal sealed class DynamicObjectResolverAllowPrivateTrueExcludeNullTrueNameMutateCamelCase : IJsonFormatterResolver + { + // configuration + public static readonly IJsonFormatterResolver Instance = new DynamicObjectResolverAllowPrivateTrueExcludeNullTrueNameMutateCamelCase(); + static readonly Func nameMutator = StringMutator.ToCamelCase; + static readonly bool excludeNull = true; + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + formatter = (IJsonFormatter)DynamicObjectTypeBuilder.BuildFormatterToDynamicMethod(Instance, nameMutator, excludeNull, true); + } + } + } + + internal sealed class DynamicObjectResolverAllowPrivateTrueExcludeNullTrueNameMutateSnakeCase : IJsonFormatterResolver + { + // configuration + public static readonly IJsonFormatterResolver Instance = new DynamicObjectResolverAllowPrivateTrueExcludeNullTrueNameMutateSnakeCase(); + static readonly Func nameMutator = StringMutator.ToSnakeCase; + static readonly bool excludeNull = true; + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + formatter = (IJsonFormatter)DynamicObjectTypeBuilder.BuildFormatterToDynamicMethod(Instance, nameMutator, excludeNull, true); + } + } + } + + #endregion + + internal static class DynamicObjectTypeBuilder + { +#if NETSTANDARD + static readonly Regex SubtractFullNameRegex = new Regex(@", Version=\d+.\d+.\d+.\d+, Culture=\w+, PublicKeyToken=\w+", RegexOptions.Compiled); +#else + static readonly Regex SubtractFullNameRegex = new Regex(@", Version=\d+.\d+.\d+.\d+, Culture=\w+, PublicKeyToken=\w+"); +#endif + + + static int nameSequence = 0; + + static HashSet ignoreTypes = new HashSet + { + {typeof(object)}, + {typeof(short)}, + {typeof(int)}, + {typeof(long)}, + {typeof(ushort)}, + {typeof(uint)}, + {typeof(ulong)}, + {typeof(float)}, + {typeof(double)}, + {typeof(bool)}, + {typeof(byte)}, + {typeof(sbyte)}, + {typeof(decimal)}, + {typeof(char)}, + {typeof(string)}, + {typeof(System.Guid)}, + {typeof(System.TimeSpan)}, + {typeof(System.DateTime)}, + {typeof(System.DateTimeOffset)}, + }; + + static HashSet jsonPrimitiveTypes = new HashSet + { + {typeof(short)}, + {typeof(int)}, + {typeof(long)}, + {typeof(ushort)}, + {typeof(uint)}, + {typeof(ulong)}, + {typeof(float)}, + {typeof(double)}, + {typeof(bool)}, + {typeof(byte)}, + {typeof(sbyte)}, + {typeof(string)}, + }; + + public static object BuildFormatterToAssembly(DynamicAssembly assembly, IJsonFormatterResolver selfResolver, Func nameMutator, bool excludeNull) + { + var ti = typeof(T).GetTypeInfo(); + + if (ti.IsNullable()) + { + ti = ti.GenericTypeArguments[0].GetTypeInfo(); + + var innerFormatter = selfResolver.GetFormatterDynamic(ti.AsType()); + if (innerFormatter == null) + { + return null; + } + return (IJsonFormatter)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), new object[] { innerFormatter }); + } + + Type elementType; + if (typeof(Exception).GetTypeInfo().IsAssignableFrom(ti)) + { + return DynamicObjectTypeBuilder.BuildAnonymousFormatter(typeof(T), nameMutator, excludeNull, false, true); + } + else if (ti.IsAnonymous() || TryGetInterfaceEnumerableElementType(typeof(T), out elementType)) + { + return DynamicObjectTypeBuilder.BuildAnonymousFormatter(typeof(T), nameMutator, excludeNull, false, false); + } + + var formatterTypeInfo = DynamicObjectTypeBuilder.BuildType(assembly, typeof(T), nameMutator, excludeNull); + if (formatterTypeInfo == null) return null; + + return (IJsonFormatter)Activator.CreateInstance(formatterTypeInfo.AsType()); + } + + public static object BuildFormatterToDynamicMethod(IJsonFormatterResolver selfResolver, Func nameMutator, bool excludeNull, bool allowPrivate) + { + var ti = typeof(T).GetTypeInfo(); + + if (ti.IsNullable()) + { + ti = ti.GenericTypeArguments[0].GetTypeInfo(); + + var innerFormatter = selfResolver.GetFormatterDynamic(ti.AsType()); + if (innerFormatter == null) + { + return null; + } + return (IJsonFormatter)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), new object[] { innerFormatter }); + } + if (typeof(Exception).GetTypeInfo().IsAssignableFrom(ti)) + { + return DynamicObjectTypeBuilder.BuildAnonymousFormatter(typeof(T), nameMutator, excludeNull, false, true); + } + else + { + return DynamicObjectTypeBuilder.BuildAnonymousFormatter(typeof(T), nameMutator, excludeNull, allowPrivate, false); + } + } + + static TypeInfo BuildType(DynamicAssembly assembly, Type type, Func nameMutator, bool excludeNull) + { + if (ignoreTypes.Contains(type)) return null; + + var serializationInfo = new MetaType(type, nameMutator, false); // allowPrivate:false + var hasShouldSerialize = serializationInfo.Members.Any(x => x.ShouldSerializeMethodInfo != null); + + var formatterType = typeof(IJsonFormatter<>).MakeGenericType(type); + var typeBuilder = assembly.DefineType("Utf8Json.Formatters." + SubtractFullNameRegex.Replace(type.FullName, "").Replace(".", "_") + "Formatter" + Interlocked.Increment(ref nameSequence), TypeAttributes.Public | TypeAttributes.Sealed, null, new[] { formatterType }); + + FieldBuilder stringByteKeysField; + Dictionary customFormatterLookup; + + // for serialize, bake cache. + { + var method = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes); + stringByteKeysField = typeBuilder.DefineField("stringByteKeys", typeof(byte[][]), FieldAttributes.Private | FieldAttributes.InitOnly); + + var il = method.GetILGenerator(); + customFormatterLookup = BuildConstructor(typeBuilder, serializationInfo, method, stringByteKeysField, il, excludeNull, hasShouldSerialize); + } + + { + var method = typeBuilder.DefineMethod("Serialize", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, + null, + new Type[] { typeof(JsonWriter).MakeByRefType(), type, typeof(IJsonFormatterResolver) }); + + var il = method.GetILGenerator(); + BuildSerialize(type, serializationInfo, il, () => + { + il.EmitLoadThis(); + il.EmitLdfld(stringByteKeysField); + }, (index, member) => + { + FieldInfo fi; + if (!customFormatterLookup.TryGetValue(member, out fi)) return false; + + il.EmitLoadThis(); + il.EmitLdfld(fi); + return true; + }, excludeNull, hasShouldSerialize, 1); // firstArgIndex:0 is this. + } + + { + var method = typeBuilder.DefineMethod("Deserialize", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, + type, + new Type[] { typeof(JsonReader).MakeByRefType(), typeof(IJsonFormatterResolver) }); + + var il = method.GetILGenerator(); + BuildDeserialize(type, serializationInfo, il, (index, member) => + { + FieldInfo fi; + if (!customFormatterLookup.TryGetValue(member, out fi)) return false; + + il.EmitLoadThis(); + il.EmitLdfld(fi); + return true; + }, false, 1); // firstArgIndex:0 is this. + } + + return typeBuilder.CreateTypeInfo(); + } + + public static object BuildAnonymousFormatter(Type type, Func nameMutator, bool excludeNull, bool allowPrivate, bool isException) + { + if (ignoreTypes.Contains(type)) return false; + + MetaType serializationInfo; + if (isException) + { + var ignoreSet = new HashSet(new[] + { + "HelpLink", "TargetSite", "HResult", "Data", "ClassName", "InnerException" + }.Select(x => nameMutator(x))); + + // special case for exception, modify + serializationInfo = new MetaType(type, nameMutator, false); + + serializationInfo.BestmatchConstructor = null; + serializationInfo.ConstructorParameters = new MetaMember[0]; + serializationInfo.Members = new[] { new StringConstantValueMetaMember(nameMutator("ClassName"), type.FullName) } + .Concat(serializationInfo.Members.Where(x => !ignoreSet.Contains(x.Name))) + .Concat(new[] { new InnerExceptionMetaMember(nameMutator("InnerException")) }) + .ToArray(); + } + else + { + serializationInfo = new MetaType(type, nameMutator, allowPrivate); // can be allowPrivate:true + } + var hasShouldSerialize = serializationInfo.Members.Any(x => x.ShouldSerializeMethodInfo != null); + + // build instance instead of emit constructor. + List stringByteKeysField = new List(); + var i = 0; + foreach (var item in serializationInfo.Members.Where(x => x.IsReadable)) + { + if (excludeNull || hasShouldSerialize) + { + stringByteKeysField.Add(JsonWriter.GetEncodedPropertyName(item.Name)); + } + else + { + if (i == 0) + { + stringByteKeysField.Add(JsonWriter.GetEncodedPropertyNameWithBeginObject(item.Name)); + } + else + { + stringByteKeysField.Add(JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator(item.Name)); + } + } + i++; + } + + List serializeCustomFormatters = new List(); + List deserializeCustomFormatters = new List(); + foreach (var item in serializationInfo.Members.Where(x => x.IsReadable)) + { + var attr = item.GetCustomAttribute(true); + if (attr != null) + { + var formatter = Activator.CreateInstance(attr.FormatterType, attr.Arguments); + serializeCustomFormatters.Add(formatter); + } + else + { + serializeCustomFormatters.Add(null); + } + } + foreach (var item in serializationInfo.Members) // not only for writable because for use ctor. + { + var attr = item.GetCustomAttribute(true); + if (attr != null) + { + var formatter = Activator.CreateInstance(attr.FormatterType, attr.Arguments); + deserializeCustomFormatters.Add(formatter); + } + else + { + deserializeCustomFormatters.Add(null); + } + } + + var serialize = new DynamicMethod("Serialize", null, new Type[] { typeof(byte[][]), typeof(object[]), typeof(JsonWriter).MakeByRefType(), type, typeof(IJsonFormatterResolver) }, type.Module, true); + { + var il = serialize.GetILGenerator(); + BuildSerialize(type, serializationInfo, il, () => + { + il.EmitLdarg(0); + }, (index, member) => + { + if (serializeCustomFormatters.Count == 0) return false; + if (serializeCustomFormatters[index] == null) return false; + + il.EmitLdarg(1); // read object[] + il.EmitLdc_I4(index); + il.Emit(OpCodes.Ldelem_Ref); // object + il.Emit(OpCodes.Castclass, serializeCustomFormatters[index].GetType()); + return true; + }, excludeNull, hasShouldSerialize, 2); + } + + var deserialize = new DynamicMethod("Deserialize", type, new Type[] { typeof(object[]), typeof(JsonReader).MakeByRefType(), typeof(IJsonFormatterResolver) }, type.Module, true); + { + var il = deserialize.GetILGenerator(); + BuildDeserialize(type, serializationInfo, il, (index, member) => + { + if (deserializeCustomFormatters.Count == 0) return false; + if (deserializeCustomFormatters[index] == null) return false; + + il.EmitLdarg(0); // read object[] + il.EmitLdc_I4(index); + il.Emit(OpCodes.Ldelem_Ref); // object + il.Emit(OpCodes.Castclass, deserializeCustomFormatters[index].GetType()); + return true; + }, true, 1); + } + + object serializeDelegate = serialize.CreateDelegate(typeof(AnonymousJsonSerializeAction<>).MakeGenericType(type)); + object deserializeDelegate = deserialize.CreateDelegate(typeof(AnonymousJsonDeserializeFunc<>).MakeGenericType(type)); + + return Activator.CreateInstance(typeof(DynamicMethodAnonymousFormatter<>).MakeGenericType(type), + new[] { stringByteKeysField.ToArray(), serializeCustomFormatters.ToArray(), deserializeCustomFormatters.ToArray(), serializeDelegate, deserializeDelegate }); + } + + static Dictionary BuildConstructor(TypeBuilder builder, MetaType info, ConstructorInfo method, FieldBuilder stringByteKeysField, ILGenerator il, bool excludeNull, bool hasShouldSerialize) + { + il.EmitLdarg(0); + il.Emit(OpCodes.Call, EmitInfo.ObjectCtor); + + var writeCount = info.Members.Count(x => x.IsReadable); + il.EmitLdarg(0); + il.EmitLdc_I4(writeCount); + il.Emit(OpCodes.Newarr, typeof(byte[])); + + var i = 0; + foreach (var item in info.Members.Where(x => x.IsReadable)) + { + il.Emit(OpCodes.Dup); + il.EmitLdc_I4(i); + il.Emit(OpCodes.Ldstr, item.Name); + if (excludeNull || hasShouldSerialize) + { + il.EmitCall(EmitInfo.JsonWriter.GetEncodedPropertyName); + } + else + { + if (i == 0) + { + il.EmitCall(EmitInfo.JsonWriter.GetEncodedPropertyNameWithBeginObject); + } + else + { + il.EmitCall(EmitInfo.JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator); + } + } + + il.Emit(OpCodes.Stelem_Ref); + i++; + } + + il.Emit(OpCodes.Stfld, stringByteKeysField); + + var customFormatterField = BuildCustomFormatterField(builder, info, il); + il.Emit(OpCodes.Ret); + return customFormatterField; + } + + static Dictionary BuildCustomFormatterField(TypeBuilder builder, MetaType info, ILGenerator il) + { + Dictionary dict = new Dictionary(); + foreach (var item in info.Members.Where(x => x.IsReadable || x.IsWritable)) + { + var attr = item.GetCustomAttribute(true); + if (attr != null) + { + // var attr = typeof(Foo).Get .GetCustomAttribute(true); + // this.f = Activator.CreateInstance(attr.FormatterType, attr.Arguments); + + var f = builder.DefineField(item.Name + "_formatter", attr.FormatterType, FieldAttributes.Private | FieldAttributes.InitOnly); + + var bindingFlags = (int)(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + + var attrVar = il.DeclareLocal(typeof(JsonFormatterAttribute)); + + il.Emit(OpCodes.Ldtoken, info.Type); + il.EmitCall(EmitInfo.GetTypeFromHandle); + il.Emit(OpCodes.Ldstr, item.MemberName); + il.EmitLdc_I4(bindingFlags); + if (item.IsProperty) + { + il.EmitCall(EmitInfo.TypeGetProperty); + } + else + { + il.EmitCall(EmitInfo.TypeGetField); + } + + il.EmitTrue(); + il.EmitCall(EmitInfo.GetCustomAttributeJsonFormatterAttribute); + il.EmitStloc(attrVar); + + il.EmitLoadThis(); + + il.EmitLdloc(attrVar); + il.EmitCall(EmitInfo.JsonFormatterAttr.FormatterType); + il.EmitLdloc(attrVar); + il.EmitCall(EmitInfo.JsonFormatterAttr.Arguments); + il.EmitCall(EmitInfo.ActivatorCreateInstance); + + il.Emit(OpCodes.Castclass, attr.FormatterType); + il.Emit(OpCodes.Stfld, f); + + dict.Add(item, f); + } + } + + return dict; + } + + static void BuildSerialize(Type type, MetaType info, ILGenerator il, Action emitStringByteKeys, Func tryEmitLoadCustomFormatter, bool excludeNull, bool hasShouldSerialize, int firstArgIndex) + { + var argWriter = new ArgumentField(il, firstArgIndex); + var argValue = new ArgumentField(il, firstArgIndex + 1, type); + var argResolver = new ArgumentField(il, firstArgIndex + 2); + + var typeInfo = type.GetTypeInfo(); + + // special case for serialize exception... + var innerExceptionMetaMember = info.Members.OfType().FirstOrDefault(); + if (innerExceptionMetaMember != null) + { + innerExceptionMetaMember.argWriter = argWriter; + innerExceptionMetaMember.argValue = argValue; + innerExceptionMetaMember.argResolver = argResolver; + } + + // Special case for serialize IEnumerable<>. + if (info.IsClass && info.BestmatchConstructor == null) + { + Type elementType; + if (TryGetInterfaceEnumerableElementType(type, out elementType)) + { + var t = typeof(IEnumerable<>).MakeGenericType(elementType); + + argResolver.EmitLoad(); + il.EmitCall(EmitInfo.GetFormatterWithVerify.MakeGenericMethod(t)); + + argWriter.EmitLoad(); + argValue.EmitLoad(); + argResolver.EmitLoad(); + il.EmitCall(EmitInfo.Serialize(t)); + il.Emit(OpCodes.Ret); + return; + } + } + + // if(value == null) { writer.WriteNull(); return; } + if (info.IsClass) + { + var elseBody = il.DefineLabel(); + + argValue.EmitLoad(); + il.Emit(OpCodes.Brtrue_S, elseBody); + + argWriter.EmitLoad(); + il.EmitCall(EmitInfo.JsonWriter.WriteNull); + il.Emit(OpCodes.Ret); // return; + + il.MarkLabel(elseBody); + } + + // special case for exception + if (type == typeof(Exception)) + { + //var exceptionType = value.GetType(); + //if (exceptionType != typeof(Exception)) + //{ + // JsonSerializer.NonGeneric.Serialize(exceptionType, ref writer, value, formatterResolver); + // return; + //} + + var elseBody = il.DefineLabel(); + var exceptionType = il.DeclareLocal(typeof(Type)); + argValue.EmitLoad(); + il.EmitCall(EmitInfo.GetTypeMethod); + il.EmitStloc(exceptionType); + il.EmitLdloc(exceptionType); + il.Emit(OpCodes.Ldtoken, typeof(Exception)); + il.EmitCall(EmitInfo.GetTypeFromHandle); + il.EmitCall(EmitInfo.TypeEquals); + il.Emit(OpCodes.Brtrue, elseBody); + + il.EmitLdloc(exceptionType); + argWriter.EmitLoad(); + argValue.EmitLoad(); + argResolver.EmitLoad(); + il.EmitCall(EmitInfo.NongenericSerialize); + il.Emit(OpCodes.Ret); // return; + + il.MarkLabel(elseBody); + } + + // for-loop WriteRaw -> WriteValue, EndObject + LocalBuilder wrote = null; + Label endObjectLabel = il.DefineLabel(); + Label[] labels = null; + if (excludeNull || hasShouldSerialize) + { + // wrote = false; writer.WriteBeginObject(); + wrote = il.DeclareLocal(typeof(bool)); + argWriter.EmitLoad(); + il.EmitCall(EmitInfo.JsonWriter.WriteBeginObject); + labels = info.Members.Where(x => x.IsReadable).Select(_ => il.DefineLabel()).ToArray(); + } + + var index = 0; + foreach (var item in info.Members.Where(x => x.IsReadable)) + { + if (excludeNull || hasShouldSerialize) + { + il.MarkLabel(labels[index]); + + // if(value.X != null) + if (excludeNull) + { + if (item.Type.GetTypeInfo().IsNullable()) + { + var local = il.DeclareLocal(item.Type); + + argValue.EmitLoad(); + item.EmitLoadValue(il); + il.EmitStloc(local); + il.EmitLdloca(local); + il.EmitCall(EmitInfo.GetNullableHasValue(item.Type.GetGenericArguments()[0])); + il.Emit(OpCodes.Brfalse_S, (index < labels.Length - 1) ? labels[index + 1] : endObjectLabel); // null, next label + } + else if (!item.Type.IsValueType && !(item is StringConstantValueMetaMember)) + { + argValue.EmitLoad(); + item.EmitLoadValue(il); + il.Emit(OpCodes.Brfalse_S, (index < labels.Length - 1) ? labels[index + 1] : endObjectLabel); // null, next label + } + } + if (hasShouldSerialize && item.ShouldSerializeMethodInfo != null) + { + argValue.EmitLoad(); + il.EmitCall(item.ShouldSerializeMethodInfo); + il.Emit(OpCodes.Brfalse_S, (index < labels.Length - 1) ? labels[index + 1] : endObjectLabel); // false, next label + } + + // if(wrote) + var toWrite = il.DefineLabel(); + var flagTrue = il.DefineLabel(); + il.EmitLdloc(wrote); + il.Emit(OpCodes.Brtrue_S, flagTrue); + + il.EmitTrue(); + il.EmitStloc(wrote); + il.Emit(OpCodes.Br, toWrite); + + il.MarkLabel(flagTrue); + argWriter.EmitLoad(); + il.EmitCall(EmitInfo.JsonWriter.WriteValueSeparator); + + il.MarkLabel(toWrite); + } + + // WriteRaw + argWriter.EmitLoad(); + emitStringByteKeys(); + il.EmitLdc_I4(index); + il.Emit(OpCodes.Ldelem_Ref); +#if NETSTANDARD + // same as in constructor + byte[] rawField; + if (excludeNull || hasShouldSerialize) + { + rawField = JsonWriter.GetEncodedPropertyName(item.Name); + } + else + { + rawField = (index == 0) ? JsonWriter.GetEncodedPropertyNameWithBeginObject(item.Name) : JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator(item.Name); + } + if (rawField.Length < 32) + { + if (UnsafeMemory.Is32Bit) + { + il.EmitCall(typeof(UnsafeMemory32).GetRuntimeMethod("WriteRaw" + rawField.Length, new[] { typeof(JsonWriter).MakeByRefType(), typeof(byte[]) })); + } + else + { + il.EmitCall(typeof(UnsafeMemory64).GetRuntimeMethod("WriteRaw" + rawField.Length, new[] { typeof(JsonWriter).MakeByRefType(), typeof(byte[]) })); + } + } + else + { + il.EmitCall(EmitInfo.UnsafeMemory_MemoryCopy); + } +#else + il.EmitCall(EmitInfo.JsonWriter.WriteRaw); +#endif + + // EmitValue + EmitSerializeValue(typeInfo, item, il, index, tryEmitLoadCustomFormatter, argWriter, argValue, argResolver); + + index++; + } + + il.MarkLabel(endObjectLabel); + + // for case of empty + if (!excludeNull && index == 0) + { + argWriter.EmitLoad(); + il.EmitCall(EmitInfo.JsonWriter.WriteBeginObject); + } + + argWriter.EmitLoad(); + il.EmitCall(EmitInfo.JsonWriter.WriteEndObject); + il.Emit(OpCodes.Ret); + } + + static void EmitSerializeValue(TypeInfo type, MetaMember member, ILGenerator il, int index, Func tryEmitLoadCustomFormatter, ArgumentField writer, ArgumentField argValue, ArgumentField argResolver) + { + var t = member.Type; + if (member is InnerExceptionMetaMember) + { + (member as InnerExceptionMetaMember).EmitSerializeDirectly(il); + } + else if (tryEmitLoadCustomFormatter(index, member)) + { + writer.EmitLoad(); + argValue.EmitLoad(); + member.EmitLoadValue(il); + argResolver.EmitLoad(); + il.EmitCall(EmitInfo.Serialize(t)); + } + else if (jsonPrimitiveTypes.Contains(t)) + { + writer.EmitLoad(); + argValue.EmitLoad(); + member.EmitLoadValue(il); + il.EmitCall(typeof(JsonWriter).GetTypeInfo().GetDeclaredMethods("Write" + t.Name).OrderByDescending(x => x.GetParameters().Length).First()); + } + else + { + argResolver.EmitLoad(); + il.Emit(OpCodes.Call, EmitInfo.GetFormatterWithVerify.MakeGenericMethod(t)); + writer.EmitLoad(); + argValue.EmitLoad(); + member.EmitLoadValue(il); + argResolver.EmitLoad(); + il.EmitCall(EmitInfo.Serialize(t)); + } + } + + static void BuildDeserialize(Type type, MetaType info, ILGenerator il, Func tryEmitLoadCustomFormatter, bool useGetUninitializedObject, int firstArgIndex) + { + if (info.IsClass && info.BestmatchConstructor == null && !(useGetUninitializedObject && info.IsConcreteClass)) + { + il.Emit(OpCodes.Ldstr, "generated serializer for " + type.Name + " does not support deserialize."); + il.Emit(OpCodes.Newobj, EmitInfo.InvalidOperationExceptionConstructor); + il.Emit(OpCodes.Throw); + return; + } + + var argReader = new ArgumentField(il, firstArgIndex); + var argResolver = new ArgumentField(il, firstArgIndex + 1); + + // if (reader.ReadIsNull()) return null; + { + var elseBody = il.DefineLabel(); + + argReader.EmitLoad(); + il.EmitCall(EmitInfo.JsonReader.ReadIsNull); + il.Emit(OpCodes.Brfalse_S, elseBody); + + if (info.IsClass) + { + il.Emit(OpCodes.Ldnull); + il.Emit(OpCodes.Ret); // return; + } + else + { + il.Emit(OpCodes.Ldstr, "json value is null, struct is not supported"); + il.Emit(OpCodes.Newobj, EmitInfo.InvalidOperationExceptionConstructor); + il.Emit(OpCodes.Throw); + } + + il.MarkLabel(elseBody); + } + + // read '{' + argReader.EmitLoad(); + il.EmitCall(EmitInfo.JsonReader.ReadIsBeginObjectWithVerify); + + // check side-effect-free for optimize set member value(reduce is-exists-member on json check) + var isSideEffectFreeType = true; + if (info.BestmatchConstructor != null) + { + isSideEffectFreeType = IsSideEffectFreeConstructorType(info.BestmatchConstructor); + // if set only property, it is not side-effect but same as has side-effect + var hasSetOnlyMember = info.Members.Any(x => !x.IsReadable && x.IsWritable); + if (hasSetOnlyMember) + { + isSideEffectFreeType = false; + } + } + + // make local fields + var infoList = info.Members + .Select(item => new DeserializeInfo + { + MemberInfo = item, + LocalField = il.DeclareLocal(item.Type), + IsDeserializedField = isSideEffectFreeType ? null : il.DeclareLocal(typeof(bool)) + }) + .ToArray(); + + var countField = il.DeclareLocal(typeof(int)); + + // read member loop + { + var automata = new AutomataDictionary(); + for (int i = 0; i < info.Members.Length; i++) + { + automata.Add(JsonWriter.GetEncodedPropertyNameWithoutQuotation(info.Members[i].Name), i); + } + + var baseBytes = il.DeclareLocal(typeof(byte[])); + var buffer = il.DeclareLocal(typeof(byte).MakeByRefType(), true); + var keyArraySegment = il.DeclareLocal(typeof(ArraySegment)); + var longKey = il.DeclareLocal(typeof(ulong)); + var p = il.DeclareLocal(typeof(byte*)); + var rest = il.DeclareLocal(typeof(int)); + + // baseBytes = reader.GetBufferUnsafe(); + // fixed (byte* buffer = &baseBytes[0]) { + argReader.EmitLoad(); + il.EmitCall(EmitInfo.JsonReader.GetBufferUnsafe); + il.EmitStloc(baseBytes); + + il.EmitLdloc(baseBytes); + il.EmitLdc_I4(0); + il.Emit(OpCodes.Ldelema, typeof(byte)); + il.EmitStloc(buffer); + + // while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) // "}", skip "," when count != 0 + var continueWhile = il.DefineLabel(); + var breakWhile = il.DefineLabel(); + var readNext = il.DefineLabel(); + + il.MarkLabel(continueWhile); + + argReader.EmitLoad(); + il.EmitLdloca(countField); // ref count field(use ldloca) + il.EmitCall(EmitInfo.JsonReader.ReadIsEndObjectWithSkipValueSeparator); + il.Emit(OpCodes.Brtrue, breakWhile); // found '}', break + + argReader.EmitLoad(); + il.EmitCall(EmitInfo.JsonReader.ReadPropertyNameSegmentUnsafe); + il.EmitStloc(keyArraySegment); + + // p = buffer + arraySegment.Offset + il.EmitLdloc(buffer); + il.Emit(OpCodes.Conv_I); + il.EmitLdloca(keyArraySegment); + il.EmitCall(typeof(ArraySegment).GetRuntimeProperty("Offset").GetGetMethod()); + il.Emit(OpCodes.Add); + il.EmitStloc(p); + + // rest = arraySegment.Count + il.EmitLdloca(keyArraySegment); + il.EmitCall(typeof(ArraySegment).GetRuntimeProperty("Count").GetGetMethod()); + il.EmitStloc(rest); + + // if(rest == 0) goto End + il.EmitLdloc(rest); + il.Emit(OpCodes.Brfalse, readNext); + + //// gen automata name lookup + automata.EmitMatch(il, p, rest, longKey, x => + { + var i = x.Value; + if (infoList[i].MemberInfo != null) + { + EmitDeserializeValue(il, infoList[i], i, tryEmitLoadCustomFormatter, argReader, argResolver); + if (!isSideEffectFreeType) + { + il.EmitTrue(); + il.EmitStloc(infoList[i].IsDeserializedField); + } + il.Emit(OpCodes.Br, continueWhile); + } + else + { + il.Emit(OpCodes.Br, readNext); + } + }, () => + { + il.Emit(OpCodes.Br, readNext); + }); + + il.MarkLabel(readNext); + argReader.EmitLoad(); + il.EmitCall(EmitInfo.JsonReader.ReadNextBlock); + + il.Emit(OpCodes.Br, continueWhile); // loop again + + il.MarkLabel(breakWhile); + + // end fixed + il.Emit(OpCodes.Ldc_I4_0); + il.Emit(OpCodes.Conv_U); + il.EmitStloc(buffer); + } + + // create result object + var localResult = EmitNewObject(il, type, info, infoList, isSideEffectFreeType); + + if (localResult != null) + { + il.Emit(OpCodes.Ldloc, localResult); + } + + il.Emit(OpCodes.Ret); + } + + static void EmitDeserializeValue(ILGenerator il, DeserializeInfo info, int index, Func tryEmitLoadCustomFormatter, ArgumentField reader, ArgumentField argResolver) + { + var member = info.MemberInfo; + var t = member.Type; + if (tryEmitLoadCustomFormatter(index, member)) + { + reader.EmitLoad(); + argResolver.EmitLoad(); + il.EmitCall(EmitInfo.Deserialize(t)); + } + else if (jsonPrimitiveTypes.Contains(t)) + { + reader.EmitLoad(); + il.EmitCall(typeof(JsonReader).GetTypeInfo().GetDeclaredMethods("Read" + t.Name).OrderByDescending(x => x.GetParameters().Length).First()); + } + else + { + argResolver.EmitLoad(); + il.Emit(OpCodes.Call, EmitInfo.GetFormatterWithVerify.MakeGenericMethod(t)); + reader.EmitLoad(); + argResolver.EmitLoad(); + il.EmitCall(EmitInfo.Deserialize(t)); + } + + il.EmitStloc(info.LocalField); + } + + static LocalBuilder EmitNewObject(ILGenerator il, Type type, MetaType info, DeserializeInfo[] members, bool isSideEffectFreeType) + { + if (info.IsClass) + { + LocalBuilder result = null; + if (!isSideEffectFreeType) + { + result = il.DeclareLocal(type); + } + + if (info.BestmatchConstructor != null) + { + foreach (var item in info.ConstructorParameters) + { + var local = members.First(x => x.MemberInfo == item); + il.EmitLdloc(local.LocalField); + } + il.Emit(OpCodes.Newobj, info.BestmatchConstructor); + } + else + { + il.Emit(OpCodes.Ldtoken, type); + il.EmitCall(EmitInfo.GetTypeFromHandle); + il.EmitCall(EmitInfo.GetUninitializedObject); + } + if (!isSideEffectFreeType) + { + il.EmitStloc(result); + } + + foreach (var item in members.Where(x => x.MemberInfo != null && x.MemberInfo.IsWritable)) + { + if (isSideEffectFreeType) + { + il.Emit(OpCodes.Dup); + il.EmitLdloc(item.LocalField); + item.MemberInfo.EmitStoreValue(il); + } + else + { + var next = il.DefineLabel(); + il.EmitLdloc(item.IsDeserializedField); + il.Emit(OpCodes.Brfalse, next); + + il.EmitLdloc(result); + il.EmitLdloc(item.LocalField); + item.MemberInfo.EmitStoreValue(il); + + il.MarkLabel(next); + } + } + + return result; + } + else + { + var result = il.DeclareLocal(type); + if (info.BestmatchConstructor == null) + { + il.Emit(OpCodes.Ldloca, result); + il.Emit(OpCodes.Initobj, type); + } + else + { + foreach (var item in info.ConstructorParameters) + { + var local = members.First(x => x.MemberInfo == item); + il.EmitLdloc(local.LocalField); + } + il.Emit(OpCodes.Newobj, info.BestmatchConstructor); + il.Emit(OpCodes.Stloc, result); + } + + foreach (var item in members.Where(x => x.MemberInfo != null && x.MemberInfo.IsWritable)) + { + if (isSideEffectFreeType) + { + il.EmitLdloca(result); + il.EmitLdloc(item.LocalField); + item.MemberInfo.EmitStoreValue(il); + } + else + { + var next = il.DefineLabel(); + il.EmitLdloc(item.IsDeserializedField); + il.Emit(OpCodes.Brfalse, next); + + il.EmitLdloca(result); + il.EmitLdloc(item.LocalField); + item.MemberInfo.EmitStoreValue(il); + + il.MarkLabel(next); + } + } + + return result; // struct returns local result field + } + } + + static bool IsSideEffectFreeConstructorType(ConstructorInfo ctorInfo) + { + var methodBody = ctorInfo.GetMethodBody(); + if (methodBody == null) return false; // can't analysis + + var array = methodBody.GetILAsByteArray(); + if (array == null) return false; + + // (ldarg.0, call(empty ctor), ret) == side-effect free. + // Release build is 7, Debug build has nop(or nop like code) so should use ILStreamReader + var opCodes = new List(); + using (var reader = new ILStreamReader(array)) + { + while (!reader.EndOfStream) + { + var code = reader.ReadOpCode(); + if (code != OpCodes.Nop + && code != OpCodes.Ldloc_0 + && code != OpCodes.Ldloc_S + && code != OpCodes.Stloc_0 + && code != OpCodes.Stloc_S + && code != OpCodes.Blt + && code != OpCodes.Blt_S + && code != OpCodes.Bgt + && code != OpCodes.Bgt_S) + { + opCodes.Add(code); + if (opCodes.Count == 4) break; + } + } + } + + if (opCodes.Count == 3 + && opCodes[0] == System.Reflection.Emit.OpCodes.Ldarg_0 + && opCodes[1] == System.Reflection.Emit.OpCodes.Call + && opCodes[2] == System.Reflection.Emit.OpCodes.Ret) + { + if (ctorInfo.DeclaringType.BaseType == typeof(object)) + { + return true; + } + else + { + // use empty constuctor. + var bassCtorInfo = ctorInfo.DeclaringType.BaseType.GetConstructor(Type.EmptyTypes); + if (bassCtorInfo == null) + { + return false; + } + else + { + // check parent constructor + return IsSideEffectFreeConstructorType(bassCtorInfo); + } + } + } + + return false; + } + + static bool TryGetInterfaceEnumerableElementType(Type type, out Type elementType) + { + foreach (var implInterface in type.GetInterfaces()) + { + if (implInterface.IsGenericType) + { + var genericTypeDef = implInterface.GetGenericTypeDefinition(); + if (genericTypeDef == typeof(IEnumerable<>)) + { + var args = implInterface.GetGenericArguments(); + elementType = args[0]; + return true; + } + } + } + + elementType = null; + return false; + } + + struct DeserializeInfo + { + public MetaMember MemberInfo; + public LocalBuilder LocalField; + public LocalBuilder IsDeserializedField; + } + + internal static class EmitInfo + { + public static readonly ConstructorInfo ObjectCtor = typeof(object).GetTypeInfo().DeclaredConstructors.First(x => x.GetParameters().Length == 0); + + public static readonly MethodInfo GetFormatterWithVerify = typeof(JsonFormatterResolverExtensions).GetRuntimeMethod("GetFormatterWithVerify", new[] { typeof(IJsonFormatterResolver) }); +#if NETSTANDARD + public static readonly MethodInfo UnsafeMemory_MemoryCopy = ExpressionUtility.GetMethodInfo((Utf8Json.JsonWriter writer, byte[] src) => UnsafeMemory.MemoryCopy(ref writer, src)); +#endif + public static readonly ConstructorInfo InvalidOperationExceptionConstructor = typeof(System.InvalidOperationException).GetTypeInfo().DeclaredConstructors.First(x => { var p = x.GetParameters(); return p.Length == 1 && p[0].ParameterType == typeof(string); }); + public static readonly MethodInfo GetTypeFromHandle = ExpressionUtility.GetMethodInfo(() => Type.GetTypeFromHandle(default(RuntimeTypeHandle))); + + public static readonly MethodInfo TypeGetProperty = ExpressionUtility.GetMethodInfo((Type t) => t.GetProperty(default(string), default(BindingFlags))); + public static readonly MethodInfo TypeGetField = ExpressionUtility.GetMethodInfo((Type t) => t.GetField(default(string), default(BindingFlags))); + + public static readonly MethodInfo GetCustomAttributeJsonFormatterAttribute = ExpressionUtility.GetMethodInfo(() => CustomAttributeExtensions.GetCustomAttribute(default(MemberInfo), default(bool))); + + public static readonly MethodInfo ActivatorCreateInstance = ExpressionUtility.GetMethodInfo(() => Activator.CreateInstance(default(Type), default(object[]))); + public static readonly MethodInfo GetUninitializedObject = ExpressionUtility.GetMethodInfo(() => System.Runtime.Serialization.FormatterServices.GetUninitializedObject(default(Type))); + + public static readonly MethodInfo GetTypeMethod = ExpressionUtility.GetMethodInfo((object o) => o.GetType()); + public static readonly MethodInfo TypeEquals = ExpressionUtility.GetMethodInfo((Type t) => t.Equals(default(Type))); + + public static readonly MethodInfo NongenericSerialize = ExpressionUtility.GetMethodInfo(writer => JsonSerializer.NonGeneric.Serialize(default(Type), ref writer, default(object), default(IJsonFormatterResolver))); + + public static MethodInfo Serialize(Type type) + { + return typeof(IJsonFormatter<>).MakeGenericType(type).GetRuntimeMethod("Serialize", new[] { typeof(Utf8Json.JsonWriter).MakeByRefType(), type, typeof(IJsonFormatterResolver) }); + } + + public static MethodInfo Deserialize(Type type) + { + return typeof(IJsonFormatter<>).MakeGenericType(type).GetRuntimeMethod("Deserialize", new[] { typeof(Utf8Json.JsonReader).MakeByRefType(), typeof(IJsonFormatterResolver) }); + } + + public static MethodInfo GetNullableHasValue(Type type) + { + return typeof(Nullable<>).MakeGenericType(type).GetRuntimeProperty("HasValue").GetGetMethod(); + } + + internal static class JsonWriter + { + public static readonly MethodInfo GetEncodedPropertyNameWithBeginObject = ExpressionUtility.GetMethodInfo(() => Utf8Json.JsonWriter.GetEncodedPropertyNameWithBeginObject(default(string))); + + public static readonly MethodInfo GetEncodedPropertyNameWithPrefixValueSeparator = ExpressionUtility.GetMethodInfo(() => Utf8Json.JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator(default(string))); + + public static readonly MethodInfo GetEncodedPropertyNameWithoutQuotation = ExpressionUtility.GetMethodInfo(() => Utf8Json.JsonWriter.GetEncodedPropertyNameWithoutQuotation(default(string))); + + public static readonly MethodInfo GetEncodedPropertyName = ExpressionUtility.GetMethodInfo(() => Utf8Json.JsonWriter.GetEncodedPropertyName(default(string))); + + public static readonly MethodInfo WriteNull = ExpressionUtility.GetMethodInfo((Utf8Json.JsonWriter writer) => writer.WriteNull()); + public static readonly MethodInfo WriteRaw = ExpressionUtility.GetMethodInfo((Utf8Json.JsonWriter writer) => writer.WriteRaw(default(byte[]))); + public static readonly MethodInfo WriteBeginObject = ExpressionUtility.GetMethodInfo((Utf8Json.JsonWriter writer) => writer.WriteBeginObject()); + public static readonly MethodInfo WriteEndObject = ExpressionUtility.GetMethodInfo((Utf8Json.JsonWriter writer) => writer.WriteEndObject()); + public static readonly MethodInfo WriteValueSeparator = ExpressionUtility.GetMethodInfo((Utf8Json.JsonWriter writer) => writer.WriteValueSeparator()); + + static JsonWriter() + { + } + } + + internal static class JsonReader + { + public static readonly MethodInfo ReadIsNull = ExpressionUtility.GetMethodInfo((Utf8Json.JsonReader reader) => reader.ReadIsNull()); + public static readonly MethodInfo ReadIsBeginObjectWithVerify = ExpressionUtility.GetMethodInfo((Utf8Json.JsonReader reader) => reader.ReadIsBeginObjectWithVerify()); + public static readonly MethodInfo ReadIsEndObjectWithSkipValueSeparator = ExpressionUtility.GetMethodInfo((Utf8Json.JsonReader reader, int count) => reader.ReadIsEndObjectWithSkipValueSeparator(ref count)); + public static readonly MethodInfo ReadPropertyNameSegmentUnsafe = ExpressionUtility.GetMethodInfo((Utf8Json.JsonReader reader) => reader.ReadPropertyNameSegmentRaw()); + public static readonly MethodInfo ReadNextBlock = ExpressionUtility.GetMethodInfo((Utf8Json.JsonReader reader) => reader.ReadNextBlock()); + public static readonly MethodInfo GetBufferUnsafe = ExpressionUtility.GetMethodInfo((Utf8Json.JsonReader reader) => reader.GetBufferUnsafe()); + public static readonly MethodInfo GetCurrentOffsetUnsafe = ExpressionUtility.GetMethodInfo((Utf8Json.JsonReader reader) => reader.GetCurrentOffsetUnsafe()); + + static JsonReader() + { + } + } + + internal static class JsonFormatterAttr + { + internal static readonly MethodInfo FormatterType = ExpressionUtility.GetPropertyInfo((Utf8Json.JsonFormatterAttribute attr) => attr.FormatterType).GetGetMethod(); + internal static readonly MethodInfo Arguments = ExpressionUtility.GetPropertyInfo((Utf8Json.JsonFormatterAttribute attr) => attr.Arguments).GetGetMethod(); + } + } + + internal class Utf8JsonDynamicObjectResolverException : Exception + { + public Utf8JsonDynamicObjectResolverException(string message) + : base(message) + { + + } + } + } + + internal delegate void AnonymousJsonSerializeAction(byte[][] stringByteKeysField, object[] customFormatters, ref JsonWriter writer, T value, IJsonFormatterResolver resolver); + internal delegate T AnonymousJsonDeserializeFunc(object[] customFormatters, ref JsonReader reader, IJsonFormatterResolver resolver); + + internal class DynamicMethodAnonymousFormatter : IJsonFormatter + { + readonly byte[][] stringByteKeysField; + readonly object[] serializeCustomFormatters; + readonly object[] deserializeCustomFormatters; + readonly AnonymousJsonSerializeAction serialize; + readonly AnonymousJsonDeserializeFunc deserialize; + + public DynamicMethodAnonymousFormatter(byte[][] stringByteKeysField, object[] serializeCustomFormatters, object[] deserializeCustomFormatters, AnonymousJsonSerializeAction serialize, AnonymousJsonDeserializeFunc deserialize) + { + this.stringByteKeysField = stringByteKeysField; + this.serializeCustomFormatters = serializeCustomFormatters; + this.deserializeCustomFormatters = deserializeCustomFormatters; + this.serialize = serialize; + this.deserialize = deserialize; + } + + public void Serialize(ref JsonWriter writer, T value, IJsonFormatterResolver formatterResolver) + { + if (serialize == null) throw new InvalidOperationException(this.GetType().Name + " does not support Serialize."); + serialize(stringByteKeysField, serializeCustomFormatters, ref writer, value, formatterResolver); + } + + public T Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + if (deserialize == null) throw new InvalidOperationException(this.GetType().Name + " does not support Deserialize."); + return deserialize(deserializeCustomFormatters, ref reader, formatterResolver); + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/DynamicObjectResolver.cs.meta b/Unity3D/3rdLib/Utf8Json/Resolvers/DynamicObjectResolver.cs.meta new file mode 100644 index 0000000..37a2d66 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/DynamicObjectResolver.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6d4ae2d7244d4f42ae406d190b2f1698 +timeCreated: 1668660997 \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/EnumResolver.cs b/Unity3D/3rdLib/Utf8Json/Resolvers/EnumResolver.cs new file mode 100644 index 0000000..5927f8b --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/EnumResolver.cs @@ -0,0 +1,114 @@ +using System; +using Utf8Json.Internal.Emit; +using Utf8Json.Internal; +using System.Reflection; +using System.Collections.Generic; +using System.Text; +using Utf8Json.Formatters; +using Utf8Json.Resolvers.Internal; + +namespace Utf8Json.Resolvers +{ + public static class EnumResolver + { + /// Serialize as Name. + public static readonly IJsonFormatterResolver Default = EnumDefaultResolver.Instance; + /// Serialize as Value. + public static readonly IJsonFormatterResolver UnderlyingValue = EnumUnderlyingValueResolver.Instance; + } +} + +namespace Utf8Json.Resolvers.Internal +{ + internal sealed class EnumDefaultResolver : IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new EnumDefaultResolver(); + + EnumDefaultResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + var ti = typeof(T).GetTypeInfo(); + + if (ti.IsNullable()) + { + // build underlying type and use wrapped formatter. + ti = ti.GenericTypeArguments[0].GetTypeInfo(); + if (!ti.IsEnum) + { + return; + } + + var innerFormatter = Instance.GetFormatterDynamic(ti.AsType()); + if (innerFormatter == null) + { + return; + } + formatter = (IJsonFormatter)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), new object[] { innerFormatter }); + return; + } + else if (typeof(T).IsEnum) + { + formatter = (IJsonFormatter)(object)new EnumFormatter(true); + } + } + } + } + + internal sealed class EnumUnderlyingValueResolver : IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new EnumUnderlyingValueResolver(); + + EnumUnderlyingValueResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + var ti = typeof(T).GetTypeInfo(); + + if (ti.IsNullable()) + { + // build underlying type and use wrapped formatter. + ti = ti.GenericTypeArguments[0].GetTypeInfo(); + if (!ti.IsEnum) + { + return; + } + + var innerFormatter = Instance.GetFormatterDynamic(ti.AsType()); + if (innerFormatter == null) + { + return; + } + formatter = (IJsonFormatter)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), new object[] { innerFormatter }); + return; + } + else if (typeof(T).IsEnum) + { + formatter = (IJsonFormatter)(object)new EnumFormatter(false); + } + } + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/EnumResolver.cs.meta b/Unity3D/3rdLib/Utf8Json/Resolvers/EnumResolver.cs.meta new file mode 100644 index 0000000..9ce186c --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/EnumResolver.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4d6fb4e7e5d6424885c5ed56ff13f28b +timeCreated: 1668660996 \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/PocoResolver.cs b/Unity3D/3rdLib/Utf8Json/Resolvers/PocoResolver.cs new file mode 100644 index 0000000..337b585 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/PocoResolver.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using Utf8Json.Formatters; + +namespace Utf8Json.Resolvers +{ + public class PocoResolver : global::Utf8Json.IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new PocoResolver(); + + public static DictionaryFormatter dictFormater = new DictionaryFormatter(); + private static readonly Dictionary formatterMap = new Dictionary() + { + // Primitive + {typeof(Dictionary), dictFormater }, + {typeof(object), new PocoObjectFormatter()} + }; + public IJsonFormatter GetFormatter() + { + Type t = typeof(T); + if (formatterMap.TryGetValue(t, out object formater)) + { + return (IJsonFormatter)formater; + } + else + { + throw new Exception("找不到类型" + t.Name); + } + } + } + + +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/PocoResolver.cs.meta b/Unity3D/3rdLib/Utf8Json/Resolvers/PocoResolver.cs.meta new file mode 100644 index 0000000..12d0ecb --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/PocoResolver.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8138585f104a4a68bd446b375d0cbad2 +timeCreated: 1668660996 \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/StandardResolver.cs b/Unity3D/3rdLib/Utf8Json/Resolvers/StandardResolver.cs new file mode 100644 index 0000000..5ee778f --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/StandardResolver.cs @@ -0,0 +1,875 @@ +using System.Linq; +using Utf8Json.Formatters; +using Utf8Json.Resolvers.Internal; + +namespace Utf8Json.Resolvers +{ + public static class StandardResolver + { + /// AllowPrivate:False, ExcludeNull:False, NameMutate:Original + public static readonly IJsonFormatterResolver Default = DefaultStandardResolver.Instance; + /// AllowPrivate:False, ExcludeNull:False, NameMutate:CamelCase + public static readonly IJsonFormatterResolver CamelCase = CamelCaseStandardResolver.Instance; + /// AllowPrivate:False, ExcludeNull:False, NameMutate:SnakeCase + public static readonly IJsonFormatterResolver SnakeCase = SnakeCaseStandardResolver.Instance; + /// AllowPrivate:False, ExcludeNull:True, NameMutate:Original + public static readonly IJsonFormatterResolver ExcludeNull = ExcludeNullStandardResolver.Instance; + /// AllowPrivate:False, ExcludeNull:True, NameMutate:CamelCase + public static readonly IJsonFormatterResolver ExcludeNullCamelCase = ExcludeNullCamelCaseStandardResolver.Instance; + /// AllowPrivate:False, ExcludeNull:True, NameMutate:SnakeCase + public static readonly IJsonFormatterResolver ExcludeNullSnakeCase = ExcludeNullSnakeCaseStandardResolver.Instance; + + /// AllowPrivate:True, ExcludeNull:False, NameMutate:Original + public static readonly IJsonFormatterResolver AllowPrivate = AllowPrivateStandardResolver.Instance; + /// AllowPrivate:True, ExcludeNull:False, NameMutate:CamelCase + public static readonly IJsonFormatterResolver AllowPrivateCamelCase = AllowPrivateCamelCaseStandardResolver.Instance; + /// AllowPrivate:True, ExcludeNull:False, NameMutate:SnakeCase + public static readonly IJsonFormatterResolver AllowPrivateSnakeCase = AllowPrivateSnakeCaseStandardResolver.Instance; + /// AllowPrivate:True, ExcludeNull:True, NameMutate:Original + public static readonly IJsonFormatterResolver AllowPrivateExcludeNull = AllowPrivateExcludeNullStandardResolver.Instance; + /// AllowPrivate:True, ExcludeNull:True, NameMutate:CamelCase + public static readonly IJsonFormatterResolver AllowPrivateExcludeNullCamelCase = AllowPrivateExcludeNullCamelCaseStandardResolver.Instance; + /// AllowPrivate:True, ExcludeNull:True, NameMutate:SnakeCase + public static readonly IJsonFormatterResolver AllowPrivateExcludeNullSnakeCase = AllowPrivateExcludeNullSnakeCaseStandardResolver.Instance; + } +} + +namespace Utf8Json.Resolvers.Internal +{ + internal static class StandardResolverHelper + { + internal static readonly IJsonFormatterResolver[] CompositeResolverBase = new[] + { + BuiltinResolver.Instance, // Builtin +#if !NETSTANDARD + Utf8Json.Unity.UnityResolver.Instance, +#endif + EnumResolver.Default, // Enum(default => string) + DynamicGenericResolver.Instance, // T[], List, etc... + AttributeFormatterResolver.Instance // [JsonFormatter] + }; + } + + internal sealed class DefaultStandardResolver : IJsonFormatterResolver + { + // configure + public static readonly IJsonFormatterResolver Instance = new DefaultStandardResolver(); + + static readonly IJsonFormatter fallbackFormatter = new DynamicObjectTypeFallbackFormatter(InnerResolver.Instance); + + DefaultStandardResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + if (typeof(T) == typeof(object)) + { + formatter = (IJsonFormatter)fallbackFormatter; + } + else + { + formatter = InnerResolver.Instance.GetFormatter(); + } + } + } + + sealed class InnerResolver : IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new InnerResolver(); + + static readonly IJsonFormatterResolver[] resolvers = StandardResolverHelper.CompositeResolverBase.Concat(new[] { DynamicObjectResolver.Default }).ToArray(); + + InnerResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + foreach (var item in resolvers) + { + var f = item.GetFormatter(); + if (f != null) + { + formatter = f; + return; + } + } + } + } + } + } + + internal sealed class CamelCaseStandardResolver : IJsonFormatterResolver + { + // configure + public static readonly IJsonFormatterResolver Instance = new CamelCaseStandardResolver(); + + static readonly IJsonFormatter fallbackFormatter = new DynamicObjectTypeFallbackFormatter(InnerResolver.Instance); + + CamelCaseStandardResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + if (typeof(T) == typeof(object)) + { + formatter = (IJsonFormatter)fallbackFormatter; + } + else + { + formatter = InnerResolver.Instance.GetFormatter(); + } + } + } + + sealed class InnerResolver : IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new InnerResolver(); + + static readonly IJsonFormatterResolver[] resolvers = StandardResolverHelper.CompositeResolverBase.Concat(new[] { DynamicObjectResolver.CamelCase }).ToArray(); + + InnerResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + foreach (var item in resolvers) + { + var f = item.GetFormatter(); + if (f != null) + { + formatter = f; + return; + } + } + } + } + } + } + + internal sealed class SnakeCaseStandardResolver : IJsonFormatterResolver + { + // configure + public static readonly IJsonFormatterResolver Instance = new SnakeCaseStandardResolver(); + + static readonly IJsonFormatter fallbackFormatter = new DynamicObjectTypeFallbackFormatter(InnerResolver.Instance); + + SnakeCaseStandardResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + if (typeof(T) == typeof(object)) + { + formatter = (IJsonFormatter)fallbackFormatter; + } + else + { + formatter = InnerResolver.Instance.GetFormatter(); + } + } + } + + sealed class InnerResolver : IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new InnerResolver(); + + static readonly IJsonFormatterResolver[] resolvers = StandardResolverHelper.CompositeResolverBase.Concat(new[] { DynamicObjectResolver.SnakeCase }).ToArray(); + + InnerResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + foreach (var item in resolvers) + { + var f = item.GetFormatter(); + if (f != null) + { + formatter = f; + return; + } + } + } + } + } + } + + internal sealed class ExcludeNullStandardResolver : IJsonFormatterResolver + { + // configure + public static readonly IJsonFormatterResolver Instance = new ExcludeNullStandardResolver(); + + static readonly IJsonFormatter fallbackFormatter = new DynamicObjectTypeFallbackFormatter(InnerResolver.Instance); + + ExcludeNullStandardResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + if (typeof(T) == typeof(object)) + { + formatter = (IJsonFormatter)fallbackFormatter; + } + else + { + formatter = InnerResolver.Instance.GetFormatter(); + } + } + } + + sealed class InnerResolver : IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new InnerResolver(); + + static readonly IJsonFormatterResolver[] resolvers = StandardResolverHelper.CompositeResolverBase.Concat(new[] { DynamicObjectResolver.ExcludeNull }).ToArray(); + + InnerResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + foreach (var item in resolvers) + { + var f = item.GetFormatter(); + if (f != null) + { + formatter = f; + return; + } + } + } + } + } + } + + internal sealed class ExcludeNullCamelCaseStandardResolver : IJsonFormatterResolver + { + // configure + public static readonly IJsonFormatterResolver Instance = new ExcludeNullCamelCaseStandardResolver(); + + static readonly IJsonFormatter fallbackFormatter = new DynamicObjectTypeFallbackFormatter(InnerResolver.Instance); + + ExcludeNullCamelCaseStandardResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + if (typeof(T) == typeof(object)) + { + formatter = (IJsonFormatter)fallbackFormatter; + } + else + { + formatter = InnerResolver.Instance.GetFormatter(); + } + } + } + + sealed class InnerResolver : IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new InnerResolver(); + + static readonly IJsonFormatterResolver[] resolvers = StandardResolverHelper.CompositeResolverBase.Concat(new[] { DynamicObjectResolver.ExcludeNullCamelCase }).ToArray(); + + InnerResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + foreach (var item in resolvers) + { + var f = item.GetFormatter(); + if (f != null) + { + formatter = f; + return; + } + } + } + } + } + } + + internal sealed class ExcludeNullSnakeCaseStandardResolver : IJsonFormatterResolver + { + // configure + public static readonly IJsonFormatterResolver Instance = new ExcludeNullSnakeCaseStandardResolver(); + + + static readonly IJsonFormatter fallbackFormatter = new DynamicObjectTypeFallbackFormatter(InnerResolver.Instance); + + ExcludeNullSnakeCaseStandardResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + if (typeof(T) == typeof(object)) + { + formatter = (IJsonFormatter)fallbackFormatter; + } + else + { + formatter = InnerResolver.Instance.GetFormatter(); + } + } + } + + sealed class InnerResolver : IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new InnerResolver(); + + static readonly IJsonFormatterResolver[] resolvers = StandardResolverHelper.CompositeResolverBase.Concat(new[] { DynamicObjectResolver.ExcludeNullSnakeCase }).ToArray(); + + InnerResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + foreach (var item in resolvers) + { + var f = item.GetFormatter(); + if (f != null) + { + formatter = f; + return; + } + } + } + } + } + } + + internal sealed class AllowPrivateStandardResolver : IJsonFormatterResolver + { + // configure + public static readonly IJsonFormatterResolver Instance = new AllowPrivateStandardResolver(); + + + static readonly IJsonFormatter fallbackFormatter = new DynamicObjectTypeFallbackFormatter(InnerResolver.Instance); + + AllowPrivateStandardResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + if (typeof(T) == typeof(object)) + { + formatter = (IJsonFormatter)fallbackFormatter; + } + else + { + formatter = InnerResolver.Instance.GetFormatter(); + } + } + } + + sealed class InnerResolver : IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new InnerResolver(); + + static readonly IJsonFormatterResolver[] resolvers = StandardResolverHelper.CompositeResolverBase.Concat(new[] { DynamicObjectResolver.AllowPrivate }).ToArray(); + + InnerResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + foreach (var item in resolvers) + { + var f = item.GetFormatter(); + if (f != null) + { + formatter = f; + return; + } + } + } + } + } + } + + internal sealed class AllowPrivateCamelCaseStandardResolver : IJsonFormatterResolver + { + // configure + public static readonly IJsonFormatterResolver Instance = new AllowPrivateCamelCaseStandardResolver(); + + + static readonly IJsonFormatter fallbackFormatter = new DynamicObjectTypeFallbackFormatter(InnerResolver.Instance); + + AllowPrivateCamelCaseStandardResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + if (typeof(T) == typeof(object)) + { + formatter = (IJsonFormatter)fallbackFormatter; + } + else + { + formatter = InnerResolver.Instance.GetFormatter(); + } + } + } + + sealed class InnerResolver : IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new InnerResolver(); + + static readonly IJsonFormatterResolver[] resolvers = StandardResolverHelper.CompositeResolverBase.Concat(new[] { DynamicObjectResolver.AllowPrivateCamelCase }).ToArray(); + + InnerResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + foreach (var item in resolvers) + { + var f = item.GetFormatter(); + if (f != null) + { + formatter = f; + return; + } + } + } + } + } + } + + internal sealed class AllowPrivateSnakeCaseStandardResolver : IJsonFormatterResolver + { + // configure + public static readonly IJsonFormatterResolver Instance = new AllowPrivateSnakeCaseStandardResolver(); + + + static readonly IJsonFormatter fallbackFormatter = new DynamicObjectTypeFallbackFormatter(InnerResolver.Instance); + + AllowPrivateSnakeCaseStandardResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + if (typeof(T) == typeof(object)) + { + formatter = (IJsonFormatter)fallbackFormatter; + } + else + { + formatter = InnerResolver.Instance.GetFormatter(); + } + } + } + + sealed class InnerResolver : IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new InnerResolver(); + + static readonly IJsonFormatterResolver[] resolvers = StandardResolverHelper.CompositeResolverBase.Concat(new[] { DynamicObjectResolver.AllowPrivateSnakeCase }).ToArray(); + + InnerResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + foreach (var item in resolvers) + { + var f = item.GetFormatter(); + if (f != null) + { + formatter = f; + return; + } + } + } + } + } + } + + internal sealed class AllowPrivateExcludeNullStandardResolver : IJsonFormatterResolver + { + // configure + public static readonly IJsonFormatterResolver Instance = new AllowPrivateExcludeNullStandardResolver(); + + + static readonly IJsonFormatter fallbackFormatter = new DynamicObjectTypeFallbackFormatter(InnerResolver.Instance); + + AllowPrivateExcludeNullStandardResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + if (typeof(T) == typeof(object)) + { + formatter = (IJsonFormatter)fallbackFormatter; + } + else + { + formatter = InnerResolver.Instance.GetFormatter(); + } + } + } + + sealed class InnerResolver : IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new InnerResolver(); + + static readonly IJsonFormatterResolver[] resolvers = StandardResolverHelper.CompositeResolverBase.Concat(new[] { DynamicObjectResolver.AllowPrivateExcludeNull }).ToArray(); + + InnerResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + foreach (var item in resolvers) + { + var f = item.GetFormatter(); + if (f != null) + { + formatter = f; + return; + } + } + } + } + } + } + + internal sealed class AllowPrivateExcludeNullCamelCaseStandardResolver : IJsonFormatterResolver + { + // configure + public static readonly IJsonFormatterResolver Instance = new AllowPrivateExcludeNullCamelCaseStandardResolver(); + + + static readonly IJsonFormatter fallbackFormatter = new DynamicObjectTypeFallbackFormatter(InnerResolver.Instance); + + AllowPrivateExcludeNullCamelCaseStandardResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + if (typeof(T) == typeof(object)) + { + formatter = (IJsonFormatter)fallbackFormatter; + } + else + { + formatter = InnerResolver.Instance.GetFormatter(); + } + } + } + + sealed class InnerResolver : IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new InnerResolver(); + + static readonly IJsonFormatterResolver[] resolvers = StandardResolverHelper.CompositeResolverBase.Concat(new[] { DynamicObjectResolver.AllowPrivateExcludeNullCamelCase }).ToArray(); + + InnerResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + foreach (var item in resolvers) + { + var f = item.GetFormatter(); + if (f != null) + { + formatter = f; + return; + } + } + } + } + } + } + + internal sealed class AllowPrivateExcludeNullSnakeCaseStandardResolver : IJsonFormatterResolver + { + // configure + public static readonly IJsonFormatterResolver Instance = new AllowPrivateExcludeNullSnakeCaseStandardResolver(); + + + static readonly IJsonFormatter fallbackFormatter = new DynamicObjectTypeFallbackFormatter(InnerResolver.Instance); + + AllowPrivateExcludeNullSnakeCaseStandardResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + if (typeof(T) == typeof(object)) + { + formatter = (IJsonFormatter)fallbackFormatter; + } + else + { + formatter = InnerResolver.Instance.GetFormatter(); + } + } + } + + sealed class InnerResolver : IJsonFormatterResolver + { + public static readonly IJsonFormatterResolver Instance = new InnerResolver(); + + static readonly IJsonFormatterResolver[] resolvers = StandardResolverHelper.CompositeResolverBase.Concat(new[] { DynamicObjectResolver.AllowPrivateExcludeNullSnakeCase }).ToArray(); + + InnerResolver() + { + } + + public IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly IJsonFormatter formatter; + + static FormatterCache() + { + foreach (var item in resolvers) + { + var f = item.GetFormatter(); + if (f != null) + { + formatter = f; + return; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/StandardResolver.cs.meta b/Unity3D/3rdLib/Utf8Json/Resolvers/StandardResolver.cs.meta new file mode 100644 index 0000000..7e242c5 --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/StandardResolver.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7209cf4fbde24f6f8ab3b46c3149c988 +timeCreated: 1668660996 \ No newline at end of file diff --git a/Unity3D/3rdLib/Utf8Json/Resolvers/Utf8JsonGenerated.cs b/Unity3D/3rdLib/Utf8Json/Resolvers/Utf8JsonGenerated.cs new file mode 100644 index 0000000..309867b --- /dev/null +++ b/Unity3D/3rdLib/Utf8Json/Resolvers/Utf8JsonGenerated.cs @@ -0,0 +1,2240 @@ +using System.Collections.Generic; +using System.Net.Sockets; +using UnityEngine; +using UnityEngine.UI; + +#pragma warning disable 618 +#pragma warning disable 612 +#pragma warning disable 414 +#pragma warning disable 168 + +namespace Utf8Json.Resolvers +{ + using System; + using Utf8Json; + + public class GeneratedResolver : global::Utf8Json.IJsonFormatterResolver + { + public static readonly global::Utf8Json.IJsonFormatterResolver Instance = new GeneratedResolver(); + + GeneratedResolver() + { + + } + + public global::Utf8Json.IJsonFormatter GetFormatter() + { + return FormatterCache.formatter; + } + + static class FormatterCache + { + public static readonly global::Utf8Json.IJsonFormatter formatter; + + static FormatterCache() + { + var f = GeneratedResolverGetFormatterHelper.GetFormatter(typeof(T)); + if (f != null) + { + formatter = (global::Utf8Json.IJsonFormatter)f; + } + } + } + } + + internal static class GeneratedResolverGetFormatterHelper + { + static readonly global::System.Collections.Generic.Dictionary lookup; + + static GeneratedResolverGetFormatterHelper() + { + lookup = new global::System.Collections.Generic.Dictionary(26) + { + {typeof(global::System.Collections.Generic.Dictionary), 0 }, + {typeof(global::System.Collections.Generic.List), 1 }, + {typeof(global::System.Collections.Generic.List), 2 }, + {typeof(global::System.Collections.Generic.List), 3 }, + {typeof(global::System.Collections.Generic.Dictionary), 4 }, + {typeof(object[]), 5 }, + {typeof(global::Utf8Json.IJsonFormatter[]), 6 }, + {typeof(global::Utf8Json.IJsonFormatterResolver[]), 7 }, + {typeof(global::System.Collections.Generic.List), 8 }, + {typeof(global::Game.SDKs.PocoSDK.NodeParams), 9 }, + {typeof(global::Game.SDKs.PocoSDK.NodeInfo), 10 }, + {typeof(global::CustomDumper), 11 }, + {typeof(global::PerfDataManager), 12 }, + {typeof(global::PocoManager), 13 }, + {typeof(global::TcpServer.TcpClientState), 14 }, + {typeof(global::DelayTaskObj), 15 }, + {typeof(global::TcpServer.TcpClientConnectedEventArgs), 16 }, + {typeof(global::TcpServer.TcpClientDisconnectedEventArgs), 17 }, + {typeof(global::Poco.AbstractNode), 18 }, + {typeof(global::Poco.RootNode), 19 }, + {typeof(global::Utf8Json.JsonFormatterAttribute), 20 }, + {typeof(global::Utf8Json.SerializationConstructorAttribute), 21 }, + {typeof(global::Utf8Json.FormatterNotRegisteredException), 22 }, + {typeof(global::Utf8Json.JsonParsingException), 23 }, + {typeof(global::Utf8Json.Resolvers.DynamicCompositeResolver), 24 }, + {typeof(global::Poco.UnityNode), 25 }, + }; + } + + internal static object GetFormatter(Type t) + { + int key; + if (!lookup.TryGetValue(t, out key)) return null; + + switch (key) + { + case 0: return new global::Utf8Json.Formatters.DictionaryFormatter(); + case 1: return new global::Utf8Json.Formatters.ListFormatter(); + case 2: return new global::Utf8Json.Formatters.ListFormatter(); + case 3: return new global::Utf8Json.Formatters.ListFormatter(); + case 4: return new global::Utf8Json.Formatters.DictionaryFormatter(); + case 5: return new global::Utf8Json.Formatters.ArrayFormatter(); + case 6: return new global::Utf8Json.Formatters.ArrayFormatter(); + case 7: return new global::Utf8Json.Formatters.ArrayFormatter(); + case 8: return new global::Utf8Json.Formatters.ListFormatter(); + case 9: return new Utf8Json.Formatters.Game.SDKs.PocoSDK.NodeParamsFormatter(); + case 10: return new Utf8Json.Formatters.Game.SDKs.PocoSDK.NodeInfoFormatter(); + case 11: return new Utf8Json.Formatters.CustomDumperFormatter(); + case 12: return new Utf8Json.Formatters.PerfDataManagerFormatter(); + case 13: return new Utf8Json.Formatters.PocoManagerFormatter(); + case 14: return new Utf8Json.Formatters.TcpServer.TcpClientStateFormatter(); + case 15: return new Utf8Json.Formatters.DelayTaskObjFormatter(); + case 16: return new Utf8Json.Formatters.TcpServer.TcpClientConnectedEventArgsFormatter(); + case 17: return new Utf8Json.Formatters.TcpServer.TcpClientDisconnectedEventArgsFormatter(); + case 18: return new Utf8Json.Formatters.Poco.AbstractNodeFormatter(); + case 19: return new Utf8Json.Formatters.Poco.RootNodeFormatter(); + case 20: return new Utf8Json.Formatters.Utf8Json.JsonFormatterAttributeFormatter(); + case 21: return new Utf8Json.Formatters.Utf8Json.SerializationConstructorAttributeFormatter(); + case 22: return new Utf8Json.Formatters.Utf8Json.FormatterNotRegisteredExceptionFormatter(); + case 23: return new Utf8Json.Formatters.Utf8Json.JsonParsingExceptionFormatter(); + case 24: return new Utf8Json.Formatters.Utf8Json.Resolvers.DynamicCompositeResolverFormatter(); + case 25: return new Utf8Json.Formatters.Poco.UnityNodeFormatter(); + default: return null; + } + } + } +} + +#pragma warning disable 168 +#pragma warning restore 414 +#pragma warning restore 618 +#pragma warning restore 612 + +#pragma warning disable 618 +#pragma warning disable 612 +#pragma warning disable 414 +#pragma warning disable 219 +#pragma warning disable 168 + +namespace Utf8Json.Formatters.Game.SDKs.PocoSDK +{ + using System; + using Utf8Json; + + + public sealed class NodeParamsFormatter : global::Utf8Json.IJsonFormatter + { + readonly global::Utf8Json.Internal.AutomataDictionary ____keyMapping; + readonly byte[][] ____stringByteKeys; + + public NodeParamsFormatter() + { + this.____keyMapping = new global::Utf8Json.Internal.AutomataDictionary() + { + { JsonWriter.GetEncodedPropertyNameWithoutQuotation("transform"), 0}, + { JsonWriter.GetEncodedPropertyNameWithoutQuotation("name"), 1}, + { JsonWriter.GetEncodedPropertyNameWithoutQuotation("gameObject"), 2}, + { JsonWriter.GetEncodedPropertyNameWithoutQuotation("image"), 3}, + { JsonWriter.GetEncodedPropertyNameWithoutQuotation("text"), 4}, + { JsonWriter.GetEncodedPropertyNameWithoutQuotation("collider"), 5}, + { JsonWriter.GetEncodedPropertyNameWithoutQuotation("button"), 6}, + { JsonWriter.GetEncodedPropertyNameWithoutQuotation("rawImage"), 7}, + { JsonWriter.GetEncodedPropertyNameWithoutQuotation("rectTransform"), 8}, + { JsonWriter.GetEncodedPropertyNameWithoutQuotation("spriteRenderer"), 9}, + { JsonWriter.GetEncodedPropertyNameWithoutQuotation("layer"), 10}, + { JsonWriter.GetEncodedPropertyNameWithoutQuotation("canvas"), 11}, + { JsonWriter.GetEncodedPropertyNameWithoutQuotation("rootCanvas"), 12}, + { JsonWriter.GetEncodedPropertyNameWithoutQuotation("rootCanvasRectTransform"), 13}, + { JsonWriter.GetEncodedPropertyNameWithoutQuotation("type"), 14}, + }; + + this.____stringByteKeys = new byte[][] + { + JsonWriter.GetEncodedPropertyNameWithBeginObject("transform"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("name"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("gameObject"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("image"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("text"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("collider"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("button"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("rawImage"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("rectTransform"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("spriteRenderer"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("layer"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("canvas"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("rootCanvas"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("rootCanvasRectTransform"), + JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("type"), + + }; + } + + public void Serialize(ref JsonWriter writer, global::Game.SDKs.PocoSDK.NodeParams value, global::Utf8Json.IJsonFormatterResolver formatterResolver) + { + if (value == null) + { + writer.WriteNull(); + return; + } + + + writer.WriteRaw(this.____stringByteKeys[0]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.transform, formatterResolver); + writer.WriteRaw(this.____stringByteKeys[1]); + writer.WriteString(value.name); + writer.WriteRaw(this.____stringByteKeys[2]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.gameObject, formatterResolver); + writer.WriteRaw(this.____stringByteKeys[3]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.image, formatterResolver); + writer.WriteRaw(this.____stringByteKeys[4]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.text, formatterResolver); + writer.WriteRaw(this.____stringByteKeys[5]); + formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.collider, formatterResolver); + writer.WriteRaw(this.____stringByteKeys[6]); + formatterResolver.GetFormatterWithVerify