Browse Source

Update Svelto.Utility

tags/Rel1
sebas77 6 years ago
parent
commit
bc9ac7be0f
20 changed files with 904 additions and 443 deletions
  1. +1
    -1
      DataStructures/CircularBufferIndexer.cs
  2. +1
    -1
      DataStructures/LockFreeQueue.cs
  3. +0
    -0
      DataStructures/PriorityQueue/HeapPriorityQueue.cs
  4. +0
    -0
      DataStructures/PriorityQueue/IPriorityQueue.cs
  5. +0
    -0
      DataStructures/PriorityQueue/PriorityQueueNode.cs
  6. +1
    -1
      ECS/Dispatcher/DispatcherOnSet.cs
  7. +3
    -0
      ECS/EntityDescriptor.cs
  8. +148
    -0
      Utilities/Console.cs
  9. +99
    -0
      Utilities/FastConcatUtility.cs
  10. +14
    -0
      Utilities/ILogger.cs
  11. +120
    -0
      Utilities/Murmur3.cs
  12. +0
    -261
      Utilities/Print.cs
  13. +24
    -0
      Utilities/SimpleLogger.cs
  14. +26
    -0
      Utilities/SlowLoggerUnity.cs
  15. +0
    -143
      Utilities/WeakActionStruct.cs
  16. +0
    -36
      Utilities/WeakEvent.cs
  17. +47
    -0
      WeakEvents/SafeEvent.cs
  18. +104
    -0
      WeakEvents/WeakAction.cs
  19. +153
    -0
      WeakEvents/WeakActionStruct.cs
  20. +163
    -0
      WeakEvents/WeakEvent.cs

+ 1
- 1
DataStructures/CircularBufferIndexer.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;



+ 1
- 1
DataStructures/LockFreeQueue.cs View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading;

//from unify wiki


DataStructures/Priority Queue/HeapPriorityQueue.cs → DataStructures/PriorityQueue/HeapPriorityQueue.cs View File


DataStructures/Priority Queue/IPriorityQueue.cs → DataStructures/PriorityQueue/IPriorityQueue.cs View File


DataStructures/Priority Queue/PriorityQueueNode.cs → DataStructures/PriorityQueue/PriorityQueueNode.cs View File


+ 1
- 1
ECS/Dispatcher/DispatcherOnSet.cs View File

@@ -1,4 +1,4 @@
using BetterWeakEvents;
using Svelto.WeakEvents;

namespace Svelto.ECS
{


+ 3
- 0
ECS/EntityDescriptor.cs View File

@@ -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
{


+ 148
- 0
Utilities/Console.cs View File

@@ -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
}
}
}

+ 99
- 0
Utilities/FastConcatUtility.cs View File

@@ -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
}

+ 14
- 0
Utilities/ILogger.cs View File

@@ -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);
}
}

+ 120
- 0
Utilities/Murmur3.cs View File

@@ -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;
}
}
}

+ 0
- 261
Utilities/Print.cs View File

@@ -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
}
}
}

+ 24
- 0
Utilities/SimpleLogger.cs View File

@@ -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;
}
}
}
}

+ 26
- 0
Utilities/SlowLoggerUnity.cs View File

@@ -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

+ 0
- 143
Utilities/WeakActionStruct.cs View File

@@ -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;
}


}

+ 0
- 36
Utilities/WeakEvent.cs View File

@@ -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>>();
}
}

+ 47
- 0
WeakEvents/SafeEvent.cs View File

@@ -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);
}
}
}
}
}


+ 104
- 0
WeakEvents/WeakAction.cs View File

@@ -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");
}
}
}

+ 153
- 0
WeakEvents/WeakActionStruct.cs View File

@@ -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);
}
}
}

+ 163
- 0
WeakEvents/WeakEvent.cs View File

@@ -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>>();
}
}

Loading…
Cancel
Save