This library "ConstExpressionForUnity" is a compile-time computation library.
With ConstExpression, you can find a constant computation process at compile-time and embed only the result of the computation in your code.
By using it, you can implement high-load processes such as hash computation and de Brownian sequence computation at zero cost.
Also included in the library is StaticExpression, a runtime pre-computation function.
With StaticExpression, the constant computation process is performed statically.
| Environment | Version |
|---|---|
| Unity | 6000.0.51f1 |
| .Net | 4.x, Standard 2.1 |
using Katuusagi.ConstExpressionForUnity;
public static class MyConstExpression
{
[ConstExpression]
public static int Add(int l, int r)
{
return l + r;
}
[StaticExpression]
public static int Add2(int l, int r)
{
return l + r;
}
}using UnityEngine;
public static class Test
{
public static void Run()
{
Debug.Log(MyConstExpression.Add(100, 200));
Debug.Log(MyConstExpression.Add2(100, 200));
}
}using Katuusagi.ConstExpressionForUnity.Generated;
using UnityEngine;
public static class Test
{
public static void Run()
{
Debug.Log((object)300);
Debug.Log((object)$$StaticTable.$0);
}
}Thus, unnecessary run-time computation can be omitted and only the results of the computation can be embedded in the code.
Test Code.
Multiple prime number calculations by Sieve of Eratosthenes.
| Process | Processing Time |
|---|---|
| CalcPrime_ConstExpression | 0.0138 ms |
| CalcPrime_StaticExpression | 0.0201 ms |
| CalcPrime_Raw | 17.98335 ms |
Since the computation itself disappears and only the result of the computation is returned, the cost is almost negligible.
Refer to ILPostProcessorCommon v2.4.1 for installation.
- Open [Window > Package Manager].
- click [+ > Add package from git url...].
- Type
https://github.com/Katsuya100/ConstExpressionForUnity.git?path=packagesand click [Add].
The above method may not work well in environments where git is not installed.
Download the appropriate version of com.katuusagi.constexpressionforunity.tgz from Releases, and then [Package Manager > + > Add package from tarball...] Use [Package Manager > + > Add package from tarball...] to install the package.
Download the appropriate version of Katuusagi.ConstExpressionForUnity.unitypackage from Releases and Import it into your project from [Assets > Import Package > Custom Package].
- in any folder in the Project Browser, select [right click > Create > Folder].
- Set a name for the folder (e.g. ConstExpressionEntry).
- select [right click > Create > Assembly Definition Reference] on the folder of 2.
- Set an asset name (e.g.
ConstExpressionEntry.asmref). - Click on the asset of 4. and set
ConstExpressionEntrytoAssembly Definitionin Inspector.
Implement the script as follows under the folder of the assembly for ConstExpression.
using Katuusagi.ConstExpressionForUnity;
public static class MyConstExpression
{
[ConstExpression]
public static int Add(int l, int r)
{
return l + r;
}
}Functions with the ConstExpression attribute are subject to compile-time constant computations.
There are several restrictions to performing compile-time constant computations.
Only functions with the ConstExpression attribute are subject to compile-time constant computations.
The ConstExpression attribute can only be attached to static functions.
The ConstExpression attribute may only be attached to functions with the following argument/return types.
| string | char | sbyte | byte |
| short | ushort | int | uint |
| long | ulong | float | double |
| bool | enum | null | struct - No reference type instances as members |
| ReadOnlyArray<string> | ReadOnlyArray<char> | ReadOnlyArray<sbyte> | ReadOnlyArray<byte> |
| ReadOnlyArray<short> | ReadOnlyArray<ushort> | ReadOnlyArray<int> | ReadOnlyArray<uint> |
| ReadOnlyArray<long> | ReadOnlyArray<ulong> | ReadOnlyArray<float> | ReadOnlyArray<double> |
| ReadOnlyArray<bool> | ReadOnlyArray<enum> | ReadOnlyArray<null> | ReadOnlyArray<struct> - No reference type instances as members |
| ReadOnlyArray<ReadOnlyArray<...>> |
Also, to perform compile-time constant computations, the value assigned to the argument must be a constant.
Failure to assign a constant will result in a warning.
// OK
MyConstExpression.Add(100, 200);
// OK
const int l = 100;
const int r = 200;
MyConstExpression.Add(l, r);
// NG
int l = 100;
int r = 200;
MyConstExpression.Add(l, r);
// NG
readonly int l = 100;
readonly int r = 200;
MyConstExpression.Add(l, r);Because struct and ReadOnlyArray cannot be literalized, the return value is held as a static readonly variable.
If passed as an argument, it must be taken from the return value of the ConstExpression method.
// OK
MyConstExpression.Add(MyConstExpression.MakeVector2(10, 20), MyConstExpression.MakeVector2(30, 40));
// NG
MyConstExpression.Add(new Vector2(10, 20), new Vector2(30, 40));Setting the ConstExpression attribute to CalculationFailedWarning=false will prevent the warning from occurring when assigning a non-constant value to an argument.
[ConstExpression(CalculationFailedWarning = false)]
public static int Add(int l, int r)
{
return l + r;
}
// No warning occurs.
int l = 100;
int r = 200;
MyConstExpression.Add(l, r);
You can disable ConstExpression with the following notation.
[assembly:IgnoreConstExpression]
This attribute can also be type or method specific.
Implement the script as follows.
using Katuusagi.ConstExpressionForUnity;
public static class MyStaticExpression
{
[StaticExpression]
public static int Add(int l, int r)
{
return l + r;
}
}Functions with the StaticExpression attribute are subject to runtime constant pre-computations.
There are several limitations to performing runtime constant pre-computations.
Only functions with the StaticExpression attribute are subject to runtime constant pre-computations
The StaticExpression attribute can only be attached to static functions.
The StaticExpression attribute can only be attached to functions with the following argument/return types.
Unlike ConstExpression, reflection types can be used.
| string | char | sbyte | byte |
| short | ushort | int | uint |
| long | ulong | float | double |
| bool | enum | null | struct - No reference type instances as members |
| delegate - Only static public members |
AppDomain | Assembly | Type |
| MemberInfo | Type/TypeInfo | ConstructorInfo | FieldInfo |
| PropertyInfo | MethodInfo | MethodBase | EventInfo |
| ReadOnlyArray<string> | ReadOnlyArray<char> | ReadOnlyArray<sbyte> | ReadOnlyArray<byte> |
| ReadOnlyArray<short> | ReadOnlyArray<ushort> | ReadOnlyArray<int> | ReadOnlyArray<uint> |
| ReadOnlyArray<long> | ReadOnlyArray<ulong> | ReadOnlyArray<float> | ReadOnlyArray<double> |
| ReadOnlyArray<bool> | ReadOnlyArray<enum> | ReadOnlyArray<null> | ReadOnlyArray<struct> - No reference type instances as members |
| ReadOnlyArray<delegate> - Only static public members |
ReadOnlyArray<AppDomain> | ReadOnlyArray<Assembly> | ReadOnlyArray<Type> |
| ReadOnlyArray<MemberInfo> | ReadOnlyArray<TypeInfo> | ReadOnlyArray<ConstructorInfo> | ReadOnlyArray<FieldInfo> |
| ReadOnlyArray<PropertyInfo> | ReadOnlyArray<MethodInfo> | ReadOnlyArray<MethodBase> | ReadOnlyArray<EventInfo> |
| ReadOnlyArray<ReadOnlyArray<...>> |
Also, to perform runtime constant pre-computations, the value assigned to the argument must be a constant.
Failure to assign a constant will result in a warning.
// OK
MyStaticExpression.Add(100, 200);
// OK
const int l = 100;
const int r = 200;
MyStaticExpression.Add(l, r);
// NG
int l = 100;
int r = 200;
MyStaticExpression.Add(l, r);
// NG
readonly int l = 100;
readonly int r = 200;
MyStaticExpression.Add(l, r);Type arguments can also be used, but the type must be unambiguous.
Setting a GenericParameter to a type argument will result in a warning.
// OK
MyStaticExpression.Add<int>(100, 200);
// NG
MyStaticExpression.Add<T>(100, 200);Because struct and ReadOnlyArray cannot be literalized, the return value is held as a static readonly variable. If passed as an argument, it must be taken from the return value of ConstExpression or StaticExpression.
// OK
MyStaticExpression.Add(MyStaticExpression.MakeVector2(10, 20), MyStaticExpression.MakeVector2(30, 40));
// NG
MyStaticExpression.Add(new Vector2(10, 20), new Vector2(30, 40));Setting the ConstExpression attribute to CalculationFailedWarning=false will prevent the warning from occurring when assigning a non-constant value to an argument.
[StaticExpression(CalculationFailedWarning = false)]
public static int Add(int l, int r)
{
return l + r;
}
// No warning occurs.
MyStaticExpression.Add(l, r);
You can disable StaticExpression with the following notation.
[assembly:IgnoreStaticExpression]
This attribute can also be type or method specific.
ReadOnlyArray is an immutable array prepared as a return constant for ConstExpression.
It inherits from IReadOnlyList and can be implicitly cast to ReadOnlySpan.
Implicit casts from arrays are also possible.
// OK
ReadOnlyArray<byte> binary = new byte[] { 0xDE, 0xAD, 0xBE, 0xEF };
// OK
ReadOnlySpan<byte> spanBinary = binary;
// OK
IReadOnlyList<byte> listBinary = binary;
// NG
byte[] bytes = binary;