using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; #nullable enable using System.Collections.Concurrent; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; namespace MemoryPack { public static class MemoryPackWriterOptionalStatePool { static readonly ConcurrentQueue queue = new ConcurrentQueue(); public static MemoryPackWriterOptionalState Rent(MemoryPackSerializerOptions? options) { if (!queue.TryDequeue(out var state)) { state = new MemoryPackWriterOptionalState(); } state.Init(options); return state; } internal static void Return(MemoryPackWriterOptionalState state) { state.Reset(); queue.Enqueue(state); } } public sealed class MemoryPackWriterOptionalState : IDisposable { internal static readonly MemoryPackWriterOptionalState NullState = new MemoryPackWriterOptionalState(true); uint nextId; readonly Dictionary objectToRef; public MemoryPackSerializerOptions Options { get; private set; } internal MemoryPackWriterOptionalState() { objectToRef = new Dictionary(ReferenceEqualityComparer.Instance); Options = null!; nextId = 0; } MemoryPackWriterOptionalState(bool _) { objectToRef = null!; Options = MemoryPackSerializerOptions.Default; nextId = 0; } internal void Init(MemoryPackSerializerOptions? options) { Options = options ?? MemoryPackSerializerOptions.Default; } public void Reset() { objectToRef.Clear(); Options = null!; nextId = 0; } public (bool existsReference, uint id) GetOrAddReference(object value) { #if NET7_0_OR_GREATER ref var id = ref CollectionsMarshal.GetValueRefOrAddDefault(objectToRef, value, out var exists); if (exists) { return (true, id); } else { id = nextId++; return (false, id); } #else if (objectToRef.TryGetValue(value, out var id)) { return (true, id); } else { id = nextId++; objectToRef.Add(value, id); return (false, id); } #endif } void IDisposable.Dispose() { MemoryPackWriterOptionalStatePool.Return(this); } // ReferenceEqualityComparer is exsits in .NET 6 but NetStandard 2.1 does not. sealed class ReferenceEqualityComparer : IEqualityComparer { ReferenceEqualityComparer() { } public static ReferenceEqualityComparer Instance { get; } = new ReferenceEqualityComparer(); public new bool Equals(object? x, object? y) => ReferenceEquals(x, y); public int GetHashCode(object obj) { return RuntimeHelpers.GetHashCode(obj); } } } }