Arithmetic Operations on Generic class in Unity Juste Tools
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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