Code/Util/Math/BinaryOperator.cs
namespace Nodebox.Util.Math;
public abstract class BinaryOperator {
public static Dictionary<Type, BinaryOperator> LazyStore { get; set; } = [];
public static T Get<T>() where T : BinaryOperator, new() {
if (LazyStore.TryGetValue(typeof(T), out var op)) {
return (T)op;
}
var instance = new T();
LazyStore[typeof(T)] = instance;
return instance;
}
public Dictionary<(Type, Type), Func<object, object, object>> Lookup;
public BinaryOperator() {
Lookup = GenerateLookup();
}
public virtual Dictionary<(Type, Type), Func<object, object, object>> GenerateLookup() {
var lookup = BaseLookup;
var seq = TypeLibrary.GetMethodsWithAttribute<ModifierAttribute>().OrderBy(x => x.Method.GetCustomAttribute<OrderAttribute>()?.Value ?? 0);
foreach (var (func, attr) in seq) {
func.Invoke(null, [attr.Type, lookup]);
}
return lookup;
}
public abstract Dictionary<(Type, Type), Func<object, object, object>> BaseLookup { get; }
public object Apply(object a, object b) => Lookup[(a.GetType(), b.GetType())](a, b);
public bool IsValid<TSelf, TOther>() => Lookup.ContainsKey((typeof(TSelf), typeof(TOther)));
public bool IsValid(Type a, Type b) => Lookup.ContainsKey((a, b));
public bool IsValid(object a, object b) => IsValid(a.GetType(), b.GetType());
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class ModifierAttribute(Type type) : Attribute {
public Type Type { get; set; } = type;
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class ModifierAttribute<T> : ModifierAttribute {
public ModifierAttribute() : base(typeof(T)) { }
}
}
public static class BinaryOperatorExtensions {
extension<T>(T binaryOperator) where T : BinaryOperator, new() {
public static T Global => BinaryOperator.Get<T>();
}
}