Skip to content

Instantly share code, notes, and snippets.

@Slyp05
Last active March 18, 2021 20:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Slyp05/0bb9cad63d0e83381566b1d67b3a312f to your computer and use it in GitHub Desktop.
Save Slyp05/0bb9cad63d0e83381566b1d67b3a312f to your computer and use it in GitHub Desktop.
Arithmetic Operations on Generic class in Unity Juste Tools
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Benchmark : MonoBehaviour
{
public int loopCount = 10000000;
[ContextMenu("Benchmark int")]
void BenchmarkInt()
{
float time = default;
Dictionary<string, float> results = new Dictionary<string, float>();
var intAdder = new GenericAdd<int>(new IntCalculator());
// Cast
time = Time.realtimeSinceStartup;
for (int i = 0; i < loopCount; i++)
intAdder.Add_Cast(4, 2);
results["Cast"] = Time.realtimeSinceStartup - time;
// Dynamic
time = Time.realtimeSinceStartup;
for (int i = 0; i < loopCount; i++)
intAdder.Add_Dynamic(4, 2);
results["Dynamic"] = Time.realtimeSinceStartup - time;
// Expression
time = Time.realtimeSinceStartup;
for (int i = 0; i < loopCount; i++)
intAdder.Add_Expression(4, 2);
results["Expression"] = Time.realtimeSinceStartup - time;
// Calculator
time = Time.realtimeSinceStartup;
for (int i = 0; i < loopCount; i++)
intAdder.Add_Calculator(4, 2);
results["Calculator"] = Time.realtimeSinceStartup - time;
// Show results:
float slowest = float.MinValue;
foreach (float t in results.Values)
slowest = Mathf.Max(t, slowest);
float fastest = float.MaxValue;
foreach (float t in results.Values)
fastest = Mathf.Min(t, fastest);
foreach (KeyValuePair<string, float> res in results)
Debug.Log($"{res.Key}: {res.Value} | {res.Value / fastest} | {res.Value / slowest}");
}
[ContextMenu("Benchmark Vector2")]
void BenchmarkVector2()
{
float time = default;
Dictionary<string, float> results = new Dictionary<string, float>();
var vector2Adder = new GenericAdd<Vector2>(new Vector2Calculator());
// Cast
time = Time.realtimeSinceStartup;
for (int i = 0; i < loopCount; i++)
vector2Adder.Add_Cast(new Vector2(4, 4), new Vector2(2, 2));
results["Cast"] = Time.realtimeSinceStartup - time;
// Reflection
time = Time.realtimeSinceStartup;
for (int i = 0; i < loopCount; i++)
vector2Adder.Add_Reflection(new Vector2(4, 4), new Vector2(2, 2));
results["Reflection"] = Time.realtimeSinceStartup - time;
// Dynamic
time = Time.realtimeSinceStartup;
for (int i = 0; i < loopCount; i++)
vector2Adder.Add_Dynamic(new Vector2(4, 4), new Vector2(2, 2));
results["Dynamic"] = Time.realtimeSinceStartup - time;
// Expression
time = Time.realtimeSinceStartup;
for (int i = 0; i < loopCount; i++)
vector2Adder.Add_Expression(new Vector2(4, 4), new Vector2(2, 2));
results["Expression"] = Time.realtimeSinceStartup - time;
// Calculator
time = Time.realtimeSinceStartup;
for (int i = 0; i < loopCount; i++)
vector2Adder.Add_Calculator(new Vector2(4, 4), new Vector2(2, 2));
results["Calculator"] = Time.realtimeSinceStartup - time;
// Show results:
float slowest = float.MinValue;
foreach (float t in results.Values)
slowest = Mathf.Max(t, slowest);
float fastest = float.MaxValue;
foreach (float t in results.Values)
fastest = Mathf.Min(t, fastest);
foreach (KeyValuePair<string, float> res in results)
Debug.Log($"{res.Key}: {res.Value} | {res.Value / fastest} | {res.Value / slowest}");
}
void OnValidate()
{
if (loopCount < 1)
loopCount = 1;
}
}
using UnityEngine;
public abstract class Calculator<T>
{
public abstract T Add(T a, T b);
}
public class IntCalculator : Calculator<int>
{
public override int Add(int a, int b)
{
return a + b;
}
}
public class Vector2Calculator : Calculator<Vector2>
{
public override Vector2 Add(Vector2 a, Vector2 b)
{
return a + b;
}
}
using UnityEngine;
using System;
using System.Linq.Expressions;
using System.Reflection;
public class GenericAdd<T>
{
/*
public T Add_Invalid(T a, T b)
{
return a + b;
}
*/
public T Add_Cast(T a, T b)
{
if (a is byte byteA && b is byte byteB)
return (T)(object)(byteA + byteB);
if (a is sbyte sbyteA && b is sbyte sbyteB)
return (T)(object)(sbyteA + sbyteB);
if (a is char charA && b is char charB)
return (T)(object)(charA + charB);
if (a is decimal decimalA && b is decimal decimalB)
return (T)(object)(decimalA + decimalB);
if (a is double doubleA && b is double doubleB)
return (T)(object)(doubleA + doubleB);
if (a is float floatA && b is float floatB)
return (T)(object)(floatA + floatB);
if (a is int intA && b is int intB)
return (T)(object)(intA + intB);
if (a is uint uintA && b is uint uintB)
return (T)(object)(uintA + uintB);
if (a is long longA && b is long longB)
return (T)(object)(longA + longB);
if (a is ulong ulongA && b is ulong ulongB)
return (T)(object)(ulongA + ulongB);
if (a is short shortA && b is short shortB)
return (T)(object)(shortA + shortB);
if (a is ushort ushortA && b is ushort ushortB)
return (T)(object)(ushortA + ushortB);
if (a is Vector2 Vector2A && b is Vector2 Vector2B)
return (T)(object)(Vector2A + Vector2B);
if (a is Vector3 Vector3A && b is Vector3 Vector3B)
return (T)(object)(Vector3A + Vector3B);
if (a is Vector4 Vector4A && b is Vector4 Vector4B)
return (T)(object)(Vector4A + Vector4B);
throw new Exception();
}
MethodInfo reflectionAddMethodInfo;
public T Add_Reflection(T a, T b)
{
return (T)reflectionAddMethodInfo.Invoke(null, new object[] { a, b });
}
public T Add_Dynamic(T a, T b)
{
dynamic dA = a;
dynamic dB = b;
return dA + dB;
}
Func<T, T, T> expressionAddLambda;
public T Add_Expression(T a, T b)
{
return expressionAddLambda(a, b);
}
Calculator<T> calculator;
public T Add_Calculator(T a, T b)
{
return calculator.Add(a, b);
}
public GenericAdd()
{
// create reflection method info
reflectionAddMethodInfo = typeof(T).GetMethod("op_Addition", BindingFlags.Static | BindingFlags.Public);
// create expression lambda
ParameterExpression exprParamA = Expression.Parameter(typeof(T));
ParameterExpression exprParamB = Expression.Parameter(typeof(T));
BinaryExpression addOperation = Expression.Add(exprParamA, exprParamB);
Expression<Func<T, T, T>> lambda = Expression.Lambda<Func<T, T, T>>(addOperation, exprParamA, exprParamB);
expressionAddLambda = lambda.Compile();
}
public GenericAdd(Calculator<T> calculator) : this()
{
this.calculator = calculator;
}
}
using UnityEngine;
public class Test : MonoBehaviour
{
[ContextMenu("Test Cast")]
void TestCast()
{
var intAdder = new GenericAdd<int>();
Debug.Log(intAdder.Add_Cast(4, 2));
var vector2Adder = new GenericAdd<Vector2>();
Debug.Log(vector2Adder.Add_Cast(new Vector2(4, 4), new Vector2(2, 2)));
}
[ContextMenu("Test Reflection")]
void TestReflection()
{
var intAdder = new GenericAdd<int>();
Debug.Log(intAdder.Add_Reflection(4, 2));
var vector2Adder = new GenericAdd<Vector2>();
Debug.Log(vector2Adder.Add_Reflection(new Vector2(4, 4), new Vector2(2, 2)));
}
[ContextMenu("Test Dynamic")]
void TestDynamic()
{
var intAdder = new GenericAdd<int>();
Debug.Log(intAdder.Add_Dynamic(4, 2));
var vector2Adder = new GenericAdd<Vector2>();
Debug.Log(vector2Adder.Add_Dynamic(new Vector2(4, 4), new Vector2(2, 2)));
}
[ContextMenu("Test Expression")]
void TestExpression()
{
var intAdder = new GenericAdd<int>();
Debug.Log(intAdder.Add_Expression(4, 2));
var vector2Adder = new GenericAdd<Vector2>();
Debug.Log(vector2Adder.Add_Expression(new Vector2(4, 4), new Vector2(2, 2)));
}
[ContextMenu("Test Calculator")]
void TestCalculator()
{
var intAdder = new GenericAdd<int>(new IntCalculator());
Debug.Log(intAdder.Add_Calculator(4, 2));
var vector2Adder = new GenericAdd<Vector2>(new Vector2Calculator());
Debug.Log(vector2Adder.Add_Calculator(new Vector2(4, 4), new Vector2(2, 2)));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment