From ee7765dfe8a82f5843d09cd12cd464e93adb4f4e Mon Sep 17 00:00:00 2001 From: Michael Lamers Date: Sat, 21 Jul 2018 18:17:06 +0200 Subject: [PATCH] ObjectTagger for creating unique object ids --- src/net/Qml.Net/Internal/ObjectTagger.cs | 106 +++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/net/Qml.Net/Internal/ObjectTagger.cs diff --git a/src/net/Qml.Net/Internal/ObjectTagger.cs b/src/net/Qml.Net/Internal/ObjectTagger.cs new file mode 100644 index 00000000..ad33e1d9 --- /dev/null +++ b/src/net/Qml.Net/Internal/ObjectTagger.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Qml.Net.Internal +{ + public class ObjectId : IDisposable + { + public ObjectId() + : this(0) + { + } + + private ObjectId(ulong id) + { + Id = id; + } + + public ulong Id { get; private set; } + + public static implicit operator ulong(ObjectId oId) + { + return oId.Id; + } + + public static ObjectId CreateNew() + { + return new ObjectId(TakeNextFreeId()); + } + + #region Id management + + private static ulong NextId = 1; + private static HashSet UsedIds = new HashSet(); + + private static ulong TakeNextFreeId() + { + ulong nextId = NextId; + UsedIds.Add(nextId); + NextId = CalculateNextFreeId(nextId); + return nextId; + } + + private static ulong CalculateNextFreeId(ulong nextId) + { + bool firstPass = true; + while (UsedIds.Contains(nextId)) + { + if(nextId == ulong.MaxValue) + { + if(!firstPass) + { + throw new Exception("Too many object ids in use!"); + } + nextId = 1; + firstPass = false; + } + else + { + nextId++; + } + } + return nextId; + } + + private static void FreeId(ulong id) + { + UsedIds.Remove(id); + } + + public void Dispose() + { + FreeId(Id); + } + + #endregion + } + + public static class ObjectTagger + { + private static readonly ConditionalWeakTable ObjectIdRefs = new ConditionalWeakTable(); + + public static ulong GetOrCreateTag(this object obj) + { + var result = GetTag(obj); + if(result.HasValue) + { + return result.Value; + } + var newObjId = ObjectId.CreateNew(); + ObjectIdRefs.Add(obj, newObjId); + return newObjId; + } + + public static ulong? GetTag(this object obj) + { + if (ObjectIdRefs.TryGetValue(obj, out var objId)) + { + return objId; + } + return null; + } + } +}