@@ -1,4 +1,4 @@ | |||
using System; | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
@@ -1,4 +1,4 @@ | |||
using System.Collections.Generic; | |||
using System.Collections.Generic; | |||
using System.Threading; | |||
//from unify wiki | |||
@@ -1,4 +1,4 @@ | |||
using BetterWeakEvents; | |||
using Svelto.WeakEvents; | |||
namespace Svelto.ECS | |||
{ | |||
@@ -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 | |||
{ | |||
@@ -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<Exception, object, string, string> 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); | |||
} | |||
/// <summary> | |||
/// Use this function if you don't want the message to be batched | |||
/// </summary> | |||
/// <param name="txt"></param> | |||
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 | |||
} | |||
} | |||
} |
@@ -0,0 +1,99 @@ | |||
using System.Text; | |||
public static class FastConcatUtility | |||
{ | |||
static readonly StringBuilder _stringBuilder = new StringBuilder(256); | |||
public static string FastConcat<T>(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 | |||
} |
@@ -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); | |||
} | |||
} |
@@ -0,0 +1,120 @@ | |||
using System; | |||
using System.IO; | |||
/// <summary> | |||
/// Murmur hash. | |||
/// | |||
/// Creates an evenly destributed uint hash from a string. | |||
/// Very fast and fairly unique | |||
/// </summary> | |||
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; | |||
} | |||
} | |||
} |
@@ -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<T>(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); | |||
} | |||
/// <summary> | |||
/// Use this function if you don't want the message to be batched | |||
/// </summary> | |||
/// <param name="txt"></param> | |||
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 | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} | |||
} |
@@ -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 |
@@ -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<T1, T2> : IEquatable<WeakAction<T1, T2>> | |||
{ | |||
public WeakAction(Action<T1, T2> 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<T1, T2> other) | |||
{ | |||
return (Method.Equals(other.Method)); | |||
} | |||
public void Release() | |||
{ | |||
ObjectRef.Free(); | |||
} | |||
readonly GCHandle ObjectRef; | |||
readonly MethodInfo Method; | |||
} | |||
public struct WeakAction<T> : IEquatable<WeakAction<T>> | |||
{ | |||
public WeakAction(Action<T> 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<T> other) | |||
{ | |||
return (Method.Equals(other.Method)); | |||
} | |||
public void Release() | |||
{ | |||
ObjectRef.Free(); | |||
} | |||
readonly GCHandle ObjectRef; | |||
readonly MethodInfo Method; | |||
} | |||
public struct WeakAction : IEquatable<WeakAction> | |||
{ | |||
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; | |||
} | |||
} |
@@ -1,36 +0,0 @@ | |||
using Svelto.DataStructures; | |||
using System; | |||
using System.Collections.Generic; | |||
namespace BetterWeakEvents | |||
{ | |||
public class WeakEvent<T1, T2> | |||
{ | |||
public static WeakEvent<T1, T2> operator+(WeakEvent<T1, T2> c1, Action<T1, T2> x) | |||
{ | |||
c1._subscribers.Add(new WeakAction<T1, T2>(x)); | |||
return c1; | |||
} | |||
public static WeakEvent<T1, T2> operator-(WeakEvent<T1, T2> c1, Action<T1, T2> x) | |||
{ | |||
c1._subscribers.UnorderedRemove(new WeakAction<T1, T2>(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<WeakAction<T1, T2>> _subscribers = new FasterList<WeakAction<T1, T2>>(); | |||
} | |||
} |
@@ -0,0 +1,47 @@ | |||
using System; | |||
public static class SafeEvent | |||
{ | |||
public static void SafeRaise<T>(this Action<T> onEvent, T val) | |||
{ | |||
if (onEvent != null) | |||
{ | |||
var length = onEvent.GetInvocationList().Length; | |||
for (int index = 0; index < length; index++) | |||
{ | |||
Action<T> handler = (Action<T>) 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); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
@@ -0,0 +1,104 @@ | |||
using System; | |||
using System.Reflection; | |||
using System.Runtime.CompilerServices; | |||
namespace Svelto.WeakEvents | |||
{ | |||
public class WeakAction<T1, T2> : WeakAction | |||
{ | |||
public WeakAction(Action<T1, T2> 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<T> : WeakActionBase | |||
{ | |||
public WeakAction(Action<T> 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<object> 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<object>(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"); | |||
} | |||
} | |||
} |
@@ -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<T1, T2> : IEquatable<WeakActionStruct<T1, T2>>, IDisposable | |||
{ | |||
public WeakActionStruct(Action<T1, T2> 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<T1, T2> 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<T> : IEquatable<WeakActionStruct<T>>, IDisposable | |||
{ | |||
public WeakActionStruct(Action<T> 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<T> 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<WeakActionStruct>, 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); | |||
} | |||
} | |||
} |
@@ -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<WeakActionStruct> | |||
_subscribers = new FasterList<WeakActionStruct>(); | |||
} | |||
public class WeakEvent<T1> | |||
{ | |||
public static WeakEvent<T1> operator+(WeakEvent<T1> c1, Action<T1> x) | |||
{ | |||
if (c1 == null) c1 = new WeakEvent<T1>(); | |||
c1._subscribers.Add(new WeakActionStruct<T1>(x)); | |||
return c1; | |||
} | |||
public static WeakEvent<T1> operator-(WeakEvent<T1> c1, Action<T1> 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<WeakActionStruct<T1>> | |||
_subscribers = new FasterList<WeakActionStruct<T1>>(); | |||
} | |||
public class WeakEvent<T1, T2> | |||
{ | |||
public static WeakEvent<T1, T2> operator+(WeakEvent<T1, T2> c1, Action<T1, T2> x) | |||
{ | |||
if (c1 == null) c1 = new WeakEvent<T1, T2>(); | |||
c1._subscribers.Add(new WeakActionStruct<T1, T2>(x)); | |||
return c1; | |||
} | |||
public static WeakEvent<T1, T2> operator-(WeakEvent<T1, T2> c1, Action<T1, T2> 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<WeakActionStruct<T1, T2>> | |||
_subscribers = new FasterList<WeakActionStruct<T1, T2>>(); | |||
} | |||
} |