From bc9ac7be0f11b255da660ca9240dc933aa021024 Mon Sep 17 00:00:00 2001 From: sebas77 Date: Mon, 6 Nov 2017 15:47:45 +0000 Subject: [PATCH] Update Svelto.Utility --- DataStructures/CircularBufferIndexer.cs | 2 +- DataStructures/LockFreeQueue.cs | 2 +- .../HeapPriorityQueue.cs | 0 .../IPriorityQueue.cs | 0 .../PriorityQueueNode.cs | 0 ECS/Dispatcher/DispatcherOnSet.cs | 2 +- ECS/EntityDescriptor.cs | 3 + Utilities/Console.cs | 148 ++++++++++ Utilities/FastConcatUtility.cs | 99 +++++++ Utilities/ILogger.cs | 14 + Utilities/Murmur3.cs | 120 ++++++++ Utilities/Print.cs | 261 ------------------ Utilities/SimpleLogger.cs | 24 ++ Utilities/SlowLoggerUnity.cs | 26 ++ Utilities/WeakActionStruct.cs | 143 ---------- Utilities/WeakEvent.cs | 36 --- WeakEvents/SafeEvent.cs | 47 ++++ WeakEvents/WeakAction.cs | 104 +++++++ WeakEvents/WeakActionStruct.cs | 153 ++++++++++ WeakEvents/WeakEvent.cs | 163 +++++++++++ 20 files changed, 904 insertions(+), 443 deletions(-) rename DataStructures/{Priority Queue => PriorityQueue}/HeapPriorityQueue.cs (100%) rename DataStructures/{Priority Queue => PriorityQueue}/IPriorityQueue.cs (100%) rename DataStructures/{Priority Queue => PriorityQueue}/PriorityQueueNode.cs (100%) create mode 100644 Utilities/Console.cs create mode 100644 Utilities/FastConcatUtility.cs create mode 100644 Utilities/ILogger.cs create mode 100644 Utilities/Murmur3.cs delete mode 100644 Utilities/Print.cs create mode 100644 Utilities/SimpleLogger.cs create mode 100644 Utilities/SlowLoggerUnity.cs delete mode 100644 Utilities/WeakActionStruct.cs delete mode 100644 Utilities/WeakEvent.cs create mode 100644 WeakEvents/SafeEvent.cs create mode 100644 WeakEvents/WeakAction.cs create mode 100644 WeakEvents/WeakActionStruct.cs create mode 100644 WeakEvents/WeakEvent.cs diff --git a/DataStructures/CircularBufferIndexer.cs b/DataStructures/CircularBufferIndexer.cs index a01d8ba..6d86441 100644 --- a/DataStructures/CircularBufferIndexer.cs +++ b/DataStructures/CircularBufferIndexer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; diff --git a/DataStructures/LockFreeQueue.cs b/DataStructures/LockFreeQueue.cs index 01ae6e5..4c55f39 100644 --- a/DataStructures/LockFreeQueue.cs +++ b/DataStructures/LockFreeQueue.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading; //from unify wiki diff --git a/DataStructures/Priority Queue/HeapPriorityQueue.cs b/DataStructures/PriorityQueue/HeapPriorityQueue.cs similarity index 100% rename from DataStructures/Priority Queue/HeapPriorityQueue.cs rename to DataStructures/PriorityQueue/HeapPriorityQueue.cs diff --git a/DataStructures/Priority Queue/IPriorityQueue.cs b/DataStructures/PriorityQueue/IPriorityQueue.cs similarity index 100% rename from DataStructures/Priority Queue/IPriorityQueue.cs rename to DataStructures/PriorityQueue/IPriorityQueue.cs diff --git a/DataStructures/Priority Queue/PriorityQueueNode.cs b/DataStructures/PriorityQueue/PriorityQueueNode.cs similarity index 100% rename from DataStructures/Priority Queue/PriorityQueueNode.cs rename to DataStructures/PriorityQueue/PriorityQueueNode.cs diff --git a/ECS/Dispatcher/DispatcherOnSet.cs b/ECS/Dispatcher/DispatcherOnSet.cs index 2c9f069..9d7de6e 100644 --- a/ECS/Dispatcher/DispatcherOnSet.cs +++ b/ECS/Dispatcher/DispatcherOnSet.cs @@ -1,4 +1,4 @@ -using BetterWeakEvents; +using Svelto.WeakEvents; namespace Svelto.ECS { diff --git a/ECS/EntityDescriptor.cs b/ECS/EntityDescriptor.cs index fc9b030..cf459b2 100644 --- a/ECS/EntityDescriptor.cs +++ b/ECS/EntityDescriptor.cs @@ -2,6 +2,9 @@ using System; using System.Collections.Generic; using System.Reflection; using Svelto.DataStructures; +#if NETFX_CORE +using BindingFlags = System.Reflection.BindingFlags; +#endif namespace Svelto.ECS { diff --git a/Utilities/Console.cs b/Utilities/Console.cs new file mode 100644 index 0000000..db80a6c --- /dev/null +++ b/Utilities/Console.cs @@ -0,0 +1,148 @@ +using System; +using System.Diagnostics; +using System.Text; + +namespace Utility +{ + public static class Console + { + static StringBuilder _stringBuilder = new StringBuilder(256); +#if UNITY_5_3_OR_NEWER || UNITY_5 + public static ILogger logger = new SlowLoggerUnity(); +#else + public static ILogger logger = new SimpleLogger(); +#endif + public static volatile bool BatchLog = false; + + //Hack, have to find the right solution + public static Action onException; + + static Console() + { + onException = (e, obj, message, stack) => + { + UnityEngine.Debug.LogException(e, (UnityEngine.Object)obj); + }; + } + + public static void Log(string txt) + { + logger.Log(txt); + } + + public static void LogError(string txt) + { + string toPrint; + + lock (_stringBuilder) + { + _stringBuilder.Length = 0; + _stringBuilder.Append("-!!!!!!-> "); + _stringBuilder.Append(txt); + + toPrint = _stringBuilder.ToString(); + } + + logger.Log(toPrint, null, LogType.Error); + } + + public static void LogError(string txt, string stack) + { + string toPrint; + + lock (_stringBuilder) + { + _stringBuilder.Length = 0; + _stringBuilder.Append("-!!!!!!-> "); + _stringBuilder.Append(txt); + + toPrint = _stringBuilder.ToString(); + } + + logger.Log(toPrint, stack, LogType.Error); + } + + public static void LogException(Exception e) + { + LogException(e, null); + } + + public static void LogException(Exception e, UnityEngine.Object obj) + { + string toPrint; + string stackTrace; + + lock (_stringBuilder) + { + _stringBuilder.Length = 0; + _stringBuilder.Append("-!!!!!!-> ").Append(e.Message); + + stackTrace = e.StackTrace; + + if (e.InnerException != null) + { + e = e.InnerException; + + _stringBuilder.Append(" Inner Message: ").Append(e.Message).Append(" Inner Stacktrace:") + .Append(e.StackTrace); + + stackTrace = e.StackTrace; + } + + toPrint = _stringBuilder.ToString(); + } + + onException(e, obj, toPrint, stackTrace); + } + + public static void LogWarning(string txt) + { + string toPrint; + + lock (_stringBuilder) + { + _stringBuilder.Length = 0; + _stringBuilder.Append("------> "); + _stringBuilder.Append(txt); + + toPrint = _stringBuilder.ToString(); + } + + logger.Log(toPrint, null, LogType.Warning); + } + + /// + /// Use this function if you don't want the message to be batched + /// + /// + public static void SystemLog(string txt) + { + string toPrint; + + lock (_stringBuilder) + { +#if NETFX_CORE + string currentTimeString = DateTime.UtcNow.ToString("dd/mm/yy hh:ii:ss"); + string processTimeString = (DateTime.UtcNow - ProcessDiagnosticInfo.GetForCurrentProcess().ProcessStartTime.DateTime).ToString(); +#else + string currentTimeString = DateTime.UtcNow.ToLongTimeString(); //ensure includes seconds + string processTimeString = (DateTime.Now - Process.GetCurrentProcess().StartTime).ToString(); +#endif + + _stringBuilder.Length = 0; + _stringBuilder.Append("[").Append(currentTimeString); + _stringBuilder.Append("][").Append(processTimeString); + _stringBuilder.Length = _stringBuilder.Length - 3; //remove some precision that we don't need + _stringBuilder.Append("] ").AppendLine(txt); + + toPrint = _stringBuilder.ToString(); + } + +#if !UNITY_EDITOR && !NETFX_CORE + System.Console.WriteLine(toPrint); +#else + UnityEngine.Debug.Log(toPrint); +#endif + } + } +} \ No newline at end of file diff --git a/Utilities/FastConcatUtility.cs b/Utilities/FastConcatUtility.cs new file mode 100644 index 0000000..db83efa --- /dev/null +++ b/Utilities/FastConcatUtility.cs @@ -0,0 +1,99 @@ +using System.Text; + +public static class FastConcatUtility +{ + static readonly StringBuilder _stringBuilder = new StringBuilder(256); + + public static string FastConcat(this string str1, T str2) + { + lock (_stringBuilder) + { + _stringBuilder.Length = 0; + + _stringBuilder.Append(str1); + _stringBuilder.Append(str2); + + return _stringBuilder.ToString(); + } + } + + public static string FastConcat(this string str1, string str2, string str3) + { + lock (_stringBuilder) + { + _stringBuilder.Length = 0; + + _stringBuilder.Append(str1); + _stringBuilder.Append(str2); + _stringBuilder.Append(str3); + + return _stringBuilder.ToString(); + } + } + + public static string FastConcat(this string str1, string str2, string str3, string str4) + { + lock (_stringBuilder) + { + _stringBuilder.Length = 0; + + _stringBuilder.Append(str1); + _stringBuilder.Append(str2); + _stringBuilder.Append(str3); + _stringBuilder.Append(str4); + + + return _stringBuilder.ToString(); + } + } + + public static string FastConcat(this string str1, string str2, string str3, string str4, string str5) + { + lock (_stringBuilder) + { + _stringBuilder.Length = 0; + + _stringBuilder.Append(str1); + _stringBuilder.Append(str2); + _stringBuilder.Append(str3); + _stringBuilder.Append(str4); + _stringBuilder.Append(str5); + + return _stringBuilder.ToString(); + } + } + + public static string FastJoin(this string[] str) + { + lock (_stringBuilder) + { + _stringBuilder.Length = 0; + + for (int i = 0; i < str.Length; i++) + _stringBuilder.Append(str[i]); + + return _stringBuilder.ToString(); + } + } + + public static string FastJoin(this string[] str, string str1) + { + lock (_stringBuilder) + { + _stringBuilder.Length = 0; + + for (int i = 0; i < str.Length; i++) + _stringBuilder.Append(str[i]); + + _stringBuilder.Append(str1); + + return _stringBuilder.ToString(); + } + } +} + +namespace Utility +{ +#if UNITY_5 || UNITY_5_3_OR_NEWER +#endif +} diff --git a/Utilities/ILogger.cs b/Utilities/ILogger.cs new file mode 100644 index 0000000..20eaa23 --- /dev/null +++ b/Utilities/ILogger.cs @@ -0,0 +1,14 @@ +namespace Utility +{ + public enum LogType + { + Log, + Exception, + Warning, + Error + } + public interface ILogger + { + void Log (string txt, string stack = null, LogType type = LogType.Log); + } +} \ No newline at end of file diff --git a/Utilities/Murmur3.cs b/Utilities/Murmur3.cs new file mode 100644 index 0000000..6e83e68 --- /dev/null +++ b/Utilities/Murmur3.cs @@ -0,0 +1,120 @@ +using System; +using System.IO; + +/// +/// Murmur hash. +/// +/// Creates an evenly destributed uint hash from a string. +/// Very fast and fairly unique +/// + +public class Murmur3 +{ + static public uint MurmurHash3_x86_32(byte[] data, uint length, uint seed) + { + uint nblocks = length >> 2; + + uint h1 = seed; + + const uint c1 = 0xcc9e2d51; + const uint c2 = 0x1b873593; + + //---------- + // body + + int i = 0 ; + + for (uint j = nblocks; j > 0 ; --j) + { + uint k1l = BitConverter.ToUInt32(data, i); + + k1l *= c1; + k1l = rotl32(k1l, 15); + k1l *= c2; + + h1 ^= k1l; + h1 = rotl32(h1, 13); + h1 = h1 * 5 + 0xe6546b64; + + i+=4; + } + + //---------- + // tail + + nblocks <<= 2; + + uint k1 = 0; + + uint tailLength = length & 3; + + if (tailLength == 3) + k1 ^= (uint)data[2 + nblocks] << 16; + if (tailLength >= 2) + k1 ^= (uint)data[1 + nblocks] << 8; + if (tailLength >= 1) + { + k1 ^= data[nblocks]; + k1 *= c1; k1 = rotl32(k1, 15); k1 *= c2; h1 ^= k1; + } + + //---------- + // finalization + + h1 ^= length; + + h1 = fmix32(h1); + + return h1; + } + + static uint fmix32(uint h) + { + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + + return h; + } + + static uint rotl32(uint x, byte r) + { + return (x << r) | (x >> (32 - r)); + } + + static public bool VerificationTest() + { + byte[] key = new byte[256]; + byte[] hashes = new byte[1024]; + + for (uint i = 0; i < 256; i++) + { + key[i] = (byte)i; + + uint result = MurmurHash3_x86_32(key, i, 256 - i); + + Buffer.BlockCopy(BitConverter.GetBytes(result), 0, hashes, (int)i * 4, 4); + } + + // Then hash the result array + + uint finalr = MurmurHash3_x86_32(hashes, 1024, 0); + + uint verification = 0xB0F57EE3; + + //---------- + + if (verification != finalr) + { + return false; + } + else + { + System.Diagnostics.Debug.WriteLine("works"); + + return true; + } + } +} diff --git a/Utilities/Print.cs b/Utilities/Print.cs deleted file mode 100644 index 07e21f4..0000000 --- a/Utilities/Print.cs +++ /dev/null @@ -1,261 +0,0 @@ -using System; -using System.Diagnostics; -using System.Text; - -public static class FastConcatUtility -{ - static readonly StringBuilder _stringBuilder = new StringBuilder(256); - - public static string FastConcat(this string str1, T str2) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - _stringBuilder.Append(str1); - _stringBuilder.Append(str2); - - return _stringBuilder.ToString(); - } - } - - public static string FastConcat(this string str1, string str2, string str3) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - _stringBuilder.Append(str1); - _stringBuilder.Append(str2); - _stringBuilder.Append(str3); - - return _stringBuilder.ToString(); - } - } - - public static string FastConcat(this string str1, string str2, string str3, string str4) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - _stringBuilder.Append(str1); - _stringBuilder.Append(str2); - _stringBuilder.Append(str3); - _stringBuilder.Append(str4); - - - return _stringBuilder.ToString(); - } - } - - public static string FastConcat(this string str1, string str2, string str3, string str4, string str5) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - _stringBuilder.Append(str1); - _stringBuilder.Append(str2); - _stringBuilder.Append(str3); - _stringBuilder.Append(str4); - _stringBuilder.Append(str5); - - return _stringBuilder.ToString(); - } - } - - public static string FastJoin(this string[] str) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - for (int i = 0; i < str.Length; i++) - _stringBuilder.Append(str[i]); - - return _stringBuilder.ToString(); - } - } - - public static string FastJoin(this string[] str, string str1) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - for (int i = 0; i < str.Length; i++) - _stringBuilder.Append(str[i]); - - _stringBuilder.Append(str1); - - return _stringBuilder.ToString(); - } - } -} - -namespace Utility -{ - public interface ILogger - { - void Log (string txt, string stack = null, LogType type = LogType.Log); - } -#if UNITY_5 || UNITY_5_3_OR_NEWER - public class SlowLoggerUnity : ILogger - { - public void Log(string txt, string stack = null, LogType type = LogType.Log) - { - switch (type) - { - case LogType.Log: - UnityEngine.Debug.Log(stack != null ? txt.FastConcat(stack) : txt); - break; - case LogType.Exception: - UnityEngine.Debug.LogError("Log of exceptions not supported"); - break; - case LogType.Warning: - UnityEngine.Debug.LogWarning(stack != null ? txt.FastConcat(stack) : txt); - break; - case LogType.Error: - UnityEngine.Debug.LogError(stack != null ? txt.FastConcat(stack) : txt); - break; - } - } - } -#endif - public class SimpleLogger : ILogger - { - public void Log(string txt, string stack = null, LogType type = LogType.Log) - { - switch (type) - { - case LogType.Log: - Console.SystemLog(stack != null ? txt.FastConcat(stack) : txt); - break; - case LogType.Exception: - Console.SystemLog("Log of exceptions not supported"); - break; - case LogType.Warning: - Console.SystemLog(stack != null ? txt.FastConcat(stack) : txt); - break; - case LogType.Error: - Console.SystemLog(stack != null ? txt.FastConcat(stack) : txt); - break; - } - } - } - - public enum LogType - { - Log, - Exception, - Warning, - Error - } - - public static class Console - { - static StringBuilder _stringBuilder = new StringBuilder(256); -#if UNITY_5 || UNITY_5_3_OR_NEWER - public static ILogger logger = new SlowLoggerUnity(); -#else - public static ILogger logger = new SimpleLogger(); -#endif - public static volatile bool BatchLog = false; - - public static void Log(string txt) - { - logger.Log(txt); - } - - public static void LogError(string txt) - { - string toPrint; - - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - _stringBuilder.Append("-!!!!!!-> "); - _stringBuilder.Append(txt); - - toPrint = _stringBuilder.ToString(); - } - - logger.Log(toPrint, null, LogType.Error); - } - - public static void LogError(string txt, string stack) - { - string toPrint; - - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - _stringBuilder.Append("-!!!!!!-> "); - _stringBuilder.Append(txt); - - toPrint = _stringBuilder.ToString(); - } - - logger.Log(toPrint, stack, LogType.Error); - } - public static void LogException(Exception e) - { -#if UNITY_5 || UNITY_5_3_OR_NEWER - LogException(e, null); -#endif - } -#if UNITY_5 || UNITY_5_3_OR_NEWER - public static void LogException(Exception e, UnityEngine.Object obj) - { - UnityEngine.Debug.LogException(e, obj); - } -#endif - public static void LogWarning(string txt) - { - string toPrint; - - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - _stringBuilder.Append("------> "); - _stringBuilder.Append(txt); - - toPrint = _stringBuilder.ToString(); - } - - logger.Log(toPrint, null, LogType.Warning); - } - - /// - /// Use this function if you don't want the message to be batched - /// - /// - public static void SystemLog(string txt) - { -#if !NETFX_CORE - string toPrint; - - lock (_stringBuilder) - { - string currentTimeString = DateTime.UtcNow.ToLongTimeString(); //ensure includes seconds - string processTimeString = (DateTime.UtcNow - Process.GetCurrentProcess().StartTime).ToString(); - - _stringBuilder.Length = 0; - _stringBuilder.Append("[").Append(currentTimeString); - _stringBuilder.Append("][").Append(processTimeString); - _stringBuilder.Length = _stringBuilder.Length - 3; //remove some precision that we don't need - _stringBuilder.Append("] ").AppendLine(txt); - - toPrint = _stringBuilder.ToString(); - } - -#if !UNITY_EDITOR - System.Console.WriteLine(toPrint); -#else - UnityEngine.Debug.Log(toPrint); -#endif -#endif - } - } -} diff --git a/Utilities/SimpleLogger.cs b/Utilities/SimpleLogger.cs new file mode 100644 index 0000000..454e1dc --- /dev/null +++ b/Utilities/SimpleLogger.cs @@ -0,0 +1,24 @@ +namespace Utility +{ + public class SimpleLogger : ILogger + { + public void Log(string txt, string stack = null, LogType type = LogType.Log) + { + switch (type) + { + case LogType.Log: + Console.SystemLog(stack != null ? txt.FastConcat(stack) : txt); + break; + case LogType.Exception: + Console.SystemLog("Log of exceptions not supported"); + break; + case LogType.Warning: + Console.SystemLog(stack != null ? txt.FastConcat(stack) : txt); + break; + case LogType.Error: + Console.SystemLog(stack != null ? txt.FastConcat(stack) : txt); + break; + } + } + } +} \ No newline at end of file diff --git a/Utilities/SlowLoggerUnity.cs b/Utilities/SlowLoggerUnity.cs new file mode 100644 index 0000000..6d5a33d --- /dev/null +++ b/Utilities/SlowLoggerUnity.cs @@ -0,0 +1,26 @@ +#if UNITY_5_3_OR_NEWER || UNITY_5 +namespace Utility +{ + public class SlowLoggerUnity : ILogger + { + public void Log(string txt, string stack = null, LogType type = LogType.Log) + { + switch (type) + { + case LogType.Log: + UnityEngine.Debug.Log(stack != null ? txt.FastConcat(stack) : txt); + break; + case LogType.Exception: + UnityEngine.Debug.LogError("Log of exceptions not supported"); + break; + case LogType.Warning: + UnityEngine.Debug.LogWarning(stack != null ? txt.FastConcat(stack) : txt); + break; + case LogType.Error: + UnityEngine.Debug.LogError(stack != null ? txt.FastConcat(stack) : txt); + break; + } + } + } +} +#endif \ No newline at end of file diff --git a/Utilities/WeakActionStruct.cs b/Utilities/WeakActionStruct.cs deleted file mode 100644 index 318027b..0000000 --- a/Utilities/WeakActionStruct.cs +++ /dev/null @@ -1,143 +0,0 @@ -using System; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -//careful, you must handle the destruction of the GCHandles! - -namespace BetterWeakEvents -{ - public struct WeakAction : IEquatable> - { - public WeakAction(Action listener) - { - ObjectRef = GCHandle.Alloc(listener.Target, GCHandleType.Weak); -#if NETFX_CORE - Method = listener.GetMethodInfo(); - var attributes = (CompilerGeneratedAttribute[])Method.GetType().GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false); - if(attributes.Length != 0) - throw new ArgumentException("Cannot create weak event to anonymous method with closure."); -#else - Method = listener.Method; - - if (Method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0) - throw new ArgumentException("Cannot create weak event to anonymous method with closure."); -#endif - } - - public bool Invoke(T1 data1, T2 data2) - { - if (ObjectRef.IsAllocated && ObjectRef.Target != null) - { - Method.Invoke(ObjectRef.Target, new object[] { data1, data2 }); - return true; - } - - Release(); - return false; - } - - public bool Equals(WeakAction other) - { - return (Method.Equals(other.Method)); - } - - public void Release() - { - ObjectRef.Free(); - } - - readonly GCHandle ObjectRef; - readonly MethodInfo Method; - } - - public struct WeakAction : IEquatable> - { - public WeakAction(Action listener) - { - ObjectRef = GCHandle.Alloc(listener.Target, GCHandleType.Weak); -#if NETFX_CORE - Method = listener.GetMethodInfo(); - var attributes = (CompilerGeneratedAttribute[])Method.GetType().GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false); - if(attributes.Length != 0) - throw new ArgumentException("Cannot create weak event to anonymous method with closure."); -#else - Method = listener.Method; - - if (Method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0) - throw new ArgumentException("Cannot create weak event to anonymous method with closure."); -#endif - } - - public bool Invoke(T data) - { - if (ObjectRef.IsAllocated && ObjectRef.Target != null) - { - Method.Invoke(ObjectRef.Target, new object[] { data }); - return true; - } - - Release(); - return false; - } - - public bool Equals(WeakAction other) - { - return (Method.Equals(other.Method)); - } - - public void Release() - { - ObjectRef.Free(); - } - - readonly GCHandle ObjectRef; - readonly MethodInfo Method; - } - - public struct WeakAction : IEquatable - { - public WeakAction(Action listener) - { - ObjectRef = GCHandle.Alloc(listener.Target, GCHandleType.Weak); -#if NETFX_CORE - Method = listener.GetMethodInfo(); - var attributes = (CompilerGeneratedAttribute[])Method.GetType().GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false); - if(attributes.Length != 0) - throw new ArgumentException("Cannot create weak event to anonymous method with closure."); -#else - Method = listener.Method; - - if (Method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0) - throw new ArgumentException("Cannot create weak event to anonymous method with closure."); -#endif - } - - public bool Invoke() - { - if (ObjectRef.IsAllocated && ObjectRef.Target != null) - { - Method.Invoke(ObjectRef.Target, null); - return true; - } - - Release(); - return false; - } - - public bool Equals(WeakAction other) - { - return (Method.Equals(other.Method)); - } - - public void Release() - { - ObjectRef.Free(); - } - - readonly GCHandle ObjectRef; - readonly MethodInfo Method; - } - - -} \ No newline at end of file diff --git a/Utilities/WeakEvent.cs b/Utilities/WeakEvent.cs deleted file mode 100644 index 91aa235..0000000 --- a/Utilities/WeakEvent.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Svelto.DataStructures; -using System; -using System.Collections.Generic; - -namespace BetterWeakEvents -{ - public class WeakEvent - { - public static WeakEvent operator+(WeakEvent c1, Action x) - { - c1._subscribers.Add(new WeakAction(x)); - return c1; - } - - public static WeakEvent operator-(WeakEvent c1, Action x) - { - c1._subscribers.UnorderedRemove(new WeakAction(x)); - return c1; - } - - public void Invoke(T1 arg1, T2 arg2) - { - for (int i = 0; i < _subscribers.Count; i++) - if (_subscribers[i].Invoke(arg1, arg2) == false) - _subscribers.UnorderedRemoveAt(i--); - } - - ~WeakEvent() - { - for (int i = 0; i < _subscribers.Count; i++) - _subscribers[i].Release(); - } - - protected FasterList> _subscribers = new FasterList>(); - } -} diff --git a/WeakEvents/SafeEvent.cs b/WeakEvents/SafeEvent.cs new file mode 100644 index 0000000..846e58c --- /dev/null +++ b/WeakEvents/SafeEvent.cs @@ -0,0 +1,47 @@ +using System; + +public static class SafeEvent +{ + public static void SafeRaise(this Action onEvent, T val) + { + if (onEvent != null) + { + var length = onEvent.GetInvocationList().Length; + for (int index = 0; index < length; index++) + { + Action handler = (Action) onEvent.GetInvocationList()[index]; + + try + { + if (handler != null) handler.Invoke(val); + } + catch (Exception e) + { + Utility.Console.LogException(e); + } + } + } + } + + public static void SafeRaise(this Action onEvent) + { + if (onEvent != null) + { + var length = onEvent.GetInvocationList().Length; + for (int index = 0; index < length; index++) + { + Action handler = (Action)onEvent.GetInvocationList()[index]; + + try + { + if (handler != null) handler.Invoke(); + } + catch (Exception e) + { + Utility.Console.LogException(e); + } + } + } + } +} + diff --git a/WeakEvents/WeakAction.cs b/WeakEvents/WeakAction.cs new file mode 100644 index 0000000..2889e70 --- /dev/null +++ b/WeakEvents/WeakAction.cs @@ -0,0 +1,104 @@ +using System; +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace Svelto.WeakEvents +{ + public class WeakAction : WeakAction + { + public WeakAction(Action listener) +#if NETFX_CORE + : base(listener.Target, listener.GetMethodInfo()) +#else + : base(listener.Target, listener.Method) +#endif + {} + + public void Invoke(T1 data1, T2 data2) + { + _data[0] = data1; + _data[1] = data2; + + Invoke_Internal(_data); + } + + readonly object[] _data = new object[2]; + } + + public class WeakAction : WeakActionBase + { + public WeakAction(Action listener) +#if NETFX_CORE + : base(listener.Target, listener.GetMethodInfo()) +#else + : base(listener.Target, listener.Method) +#endif + {} + + public void Invoke(T data) + { + _data[0] = data; + + Invoke_Internal(_data); + } + + readonly object[] _data = new object[1]; + } + + public class WeakAction : WeakActionBase + { + public WeakAction(Action listener) : base(listener) + {} + + public WeakAction(object listener, MethodInfo method) : base(listener, method) + {} + + public void Invoke() + { + Invoke_Internal(null); + } + } + + public abstract class WeakActionBase + { + protected readonly DataStructures.WeakReference ObjectRef; + protected readonly MethodInfo Method; + + public bool IsValid + { + get { return ObjectRef.IsValid; } + } + + protected WeakActionBase(Action listener) +#if NETFX_CORE + : this(listener.Target, listener.GetMethodInfo()) +#else + : this(listener.Target, listener.Method) +#endif + {} + + protected WeakActionBase(object listener, MethodInfo method) + { + ObjectRef = new DataStructures.WeakReference(listener); + + Method = method; + +#if NETFX_CORE + var attributes = (CompilerGeneratedAttribute[])method.GetType().GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false); + if (attributes.Length != 0) + throw new ArgumentException("Cannot create weak event to anonymous method with closure."); +#else + if (method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0) + throw new ArgumentException("Cannot create weak event to anonymous method with closure."); +#endif + } + + protected void Invoke_Internal(object[] data) + { + if (ObjectRef.IsValid) + Method.Invoke(ObjectRef.Target, data); + else + Utility.Console.LogWarning("Target of weak action has been garbage collected"); + } + } +} \ No newline at end of file diff --git a/WeakEvents/WeakActionStruct.cs b/WeakEvents/WeakActionStruct.cs new file mode 100644 index 0000000..d3b37a9 --- /dev/null +++ b/WeakEvents/WeakActionStruct.cs @@ -0,0 +1,153 @@ +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +//careful, you must handle the destruction of the GCHandles! +namespace Svelto.WeakEvents +{ + public struct WeakActionStruct : IEquatable>, IDisposable + { + public WeakActionStruct(Action listener) + { + WeakActionStructUtility.Init(listener.Target, listener.Method, out _objectRef, out _method); + } + + public bool Invoke(object[] args) + { + return WeakActionStructUtility.Invoke(ref _objectRef, _method, args); + } + + public bool Equals(WeakActionStruct other) + { + return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, + other._objectRef.Target, other._method); + } + + public void Dispose() + { + _objectRef.Free(); + } + + public bool IsMatch(object otherObject, MethodInfo otherMethod) + { + return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, + otherObject, otherMethod); + } + + GCHandle _objectRef; + readonly MethodInfo _method; + } + + public struct WeakActionStruct : IEquatable>, IDisposable + { + public WeakActionStruct(Action listener) + { + WeakActionStructUtility.Init(listener.Target, listener.Method, + out _objectRef, out _method); + } + + public bool Invoke(object[] args) + { + return WeakActionStructUtility.Invoke(ref _objectRef, _method, args); + } + + public bool Equals(WeakActionStruct other) + { + return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, + other._objectRef.Target, other._method); + } + + public void Dispose() + { + _objectRef.Free(); + } + + public bool IsMatch(object otherObject, MethodInfo otherMethod) + { + return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, + otherObject, otherMethod); + } + + GCHandle _objectRef; + readonly MethodInfo _method; + } + + public struct WeakActionStruct : IEquatable, IDisposable + { + public WeakActionStruct(Action listener) + { + WeakActionStructUtility.Init(listener.Target, listener.Method, out _objectRef, out _method); + } + + public bool Invoke() + { + return WeakActionStructUtility.Invoke(ref _objectRef, _method, null); + } + + public bool Equals(WeakActionStruct other) + { + return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, + other._objectRef.Target, other._method); + } + + public void Dispose() + { + _objectRef.Free(); + } + + public bool IsMatch(object otherObject, MethodInfo otherMethod) + { + return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, + otherObject, otherMethod); + } + + GCHandle _objectRef; + readonly MethodInfo _method; + } + + static class WeakActionStructUtility + { + internal static void Init(object target, MethodInfo method, + out GCHandle objectRef, out MethodInfo methodOut) + { + objectRef = GCHandle.Alloc(target, GCHandleType.Weak); + methodOut = method; + +#if DEBUG && !PROFILER +#if NETFX_CORE + Method = listener.GetMethodInfo(); + var attributes = (CompilerGeneratedAttribute[])Method.GetType().GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false); + if(attributes.Length != 0) + throw new ArgumentException("Cannot create weak event to anonymous method with closure."); +#else + if (method.DeclaringType.GetCustomAttributes(typeof (CompilerGeneratedAttribute), false).Length != 0) + throw new ArgumentException("Cannot create weak event to anonymous method with closure."); +#endif +#endif + } + + public static bool Invoke(ref GCHandle objectRef, MethodInfo method, object[] args) + { + if (objectRef.IsAllocated && objectRef.Target != null) + { + method.Invoke(objectRef.Target, args); + return true; + } + + Dispose(ref objectRef); + return false; + } + + public static void Dispose(ref GCHandle objectRef) + { + objectRef.Free(); + } + + public static bool IsMatch(object objectRef, MethodInfo method, + object _objectRef, MethodInfo _method) + { + return _method.Equals(method) && objectRef.Equals(_objectRef); + } + } +} \ No newline at end of file diff --git a/WeakEvents/WeakEvent.cs b/WeakEvents/WeakEvent.cs new file mode 100644 index 0000000..84a8b53 --- /dev/null +++ b/WeakEvents/WeakEvent.cs @@ -0,0 +1,163 @@ +using Svelto.DataStructures; +using System; +using System.Reflection; + +namespace Svelto.WeakEvents +{ + public class WeakEvent + { + public static WeakEvent operator+(WeakEvent c1, Action x) + { + if (c1 == null) c1 = new WeakEvent(); + c1._subscribers.Add(new WeakActionStruct(x)); + + return c1; + } + + public static WeakEvent operator-(WeakEvent c1, Action x) + { + DesignByContract.Check.Require(x != null); + c1.Remove(x.Target, x.Method); + + return c1; + } + + public void Invoke() + { + for (int i = 0; i < _subscribers.Count; i++) + if (_subscribers[i].Invoke() == false) + _subscribers.UnorderedRemoveAt(i--); + } + + void Remove(object thisObject, MethodInfo thisMethod) + { + for (int i = 0; i < _subscribers.Count; ++i) + { + var otherObject = _subscribers[i]; + + if (otherObject.IsMatch(thisObject, thisMethod)) + { + _subscribers.UnorderedRemoveAt(i); + break; + } + } + } + + ~WeakEvent() + { + for (int i = 0; i < _subscribers.Count; i++) + _subscribers[i].Dispose(); + } + + readonly FasterList + _subscribers = new FasterList(); + } + + public class WeakEvent + { + public static WeakEvent operator+(WeakEvent c1, Action x) + { + if (c1 == null) c1 = new WeakEvent(); + c1._subscribers.Add(new WeakActionStruct(x)); + + return c1; + } + + public static WeakEvent operator-(WeakEvent c1, Action x) + { + DesignByContract.Check.Require(x != null); + c1.Remove(x.Target, x.Method); + + return c1; + } + + public void Invoke(T1 arg1) + { + args[0] = arg1; + + for (int i = 0; i < _subscribers.Count; i++) + if (_subscribers[i].Invoke(args) == false) + _subscribers.UnorderedRemoveAt(i--); + } + + void Remove(object thisObject, MethodInfo thisMethod) + { + for (int i = 0; i < _subscribers.Count; ++i) + { + var otherObject = _subscribers[i]; + + if (otherObject.IsMatch(thisObject, thisMethod)) + { + _subscribers.UnorderedRemoveAt(i); + break; + } + } + } + + ~WeakEvent() + { + for (int i = 0; i < _subscribers.Count; i++) + _subscribers[i].Dispose(); + } + + readonly object[] args = new object[1]; + + readonly FasterList> + _subscribers = new FasterList>(); + } + + public class WeakEvent + { + public static WeakEvent operator+(WeakEvent c1, Action x) + { + if (c1 == null) c1 = new WeakEvent(); + c1._subscribers.Add(new WeakActionStruct(x)); + + return c1; + } + + public static WeakEvent operator-(WeakEvent c1, Action x) + { + DesignByContract.Check.Require(x != null); + c1.Remove(x.Target, x.Method); + + return c1; + } + + public void Invoke(T1 arg1, T2 arg2) + { + args[0] = arg1; + args[1] = arg2; + + for (int i = 0; i < _subscribers.Count; i++) + if (_subscribers[i].Invoke(args) == false) + _subscribers.UnorderedRemoveAt(i--); + } + + void Remove(object thisObject, MethodInfo thisMethod) + { + for (int i = 0; i < _subscribers.Count; ++i) + { + var otherObject = _subscribers[i]; + + if (otherObject.IsMatch(thisObject, thisMethod)) + { + _subscribers.UnorderedRemoveAt(i); + + break; + } + } + } + + ~WeakEvent() + { + for (int i = 0; i < _subscribers.Count; i++) + _subscribers[i].Dispose(); + } + + readonly object[] args = new object[2]; + + readonly FasterList> + _subscribers = new FasterList>(); + } +}