mirror of https://github.com/SixLabors/ImageSharp
Browse Source
Former-commit-id: 1bc110efc169542f998698c406473969ff03432a Former-commit-id: 0a96341575e95754884d20aff07d2f31f4265576 Former-commit-id: 404c8605fcc6a522e96b5812d647a89337ce65ccpull/1/head
12 changed files with 1344 additions and 45 deletions
@ -0,0 +1,58 @@ |
|||
namespace GenericImage.Helpers |
|||
{ |
|||
interface INullOp<T> |
|||
{ |
|||
bool HasValue(T value); |
|||
bool AddIfNotNull(ref T accumulator, T value); |
|||
} |
|||
sealed class StructNullOp<T> |
|||
: INullOp<T>, INullOp<T?> |
|||
where T : struct |
|||
{ |
|||
public bool HasValue(T value) |
|||
{ |
|||
return true; |
|||
} |
|||
public bool AddIfNotNull(ref T accumulator, T value) |
|||
{ |
|||
accumulator = Operator<T>.Add(accumulator, value); |
|||
return true; |
|||
} |
|||
public bool HasValue(T? value) |
|||
{ |
|||
return value.HasValue; |
|||
} |
|||
public bool AddIfNotNull(ref T? accumulator, T? value) |
|||
{ |
|||
if (value.HasValue) |
|||
{ |
|||
accumulator = accumulator.HasValue ? |
|||
Operator<T>.Add( |
|||
accumulator.GetValueOrDefault(), |
|||
value.GetValueOrDefault()) |
|||
: value; |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
} |
|||
sealed class ClassNullOp<T> |
|||
: INullOp<T> |
|||
where T : class |
|||
{ |
|||
public bool HasValue(T value) |
|||
{ |
|||
return value != null; |
|||
} |
|||
public bool AddIfNotNull(ref T accumulator, T value) |
|||
{ |
|||
if (value != null) |
|||
{ |
|||
accumulator = accumulator == null ? |
|||
value : Operator<T>.Add(accumulator, value); |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,100 @@ |
|||
namespace GenericImage.Helpers |
|||
{ |
|||
using System; |
|||
using System.Linq.Expressions; |
|||
|
|||
/// <summary>
|
|||
/// General purpose Expression utilities
|
|||
/// </summary>
|
|||
public static class ExpressionUtil |
|||
{ |
|||
/// <summary>
|
|||
/// Create a function delegate representing a unary operation
|
|||
/// </summary>
|
|||
/// <typeparam name="TArg1">The parameter type</typeparam>
|
|||
/// <typeparam name="TResult">The return type</typeparam>
|
|||
/// <param name="body">Body factory</param>
|
|||
/// <returns>Compiled function delegate</returns>
|
|||
public static Func<TArg1, TResult> CreateExpression<TArg1, TResult>( |
|||
Func<Expression, UnaryExpression> body) |
|||
{ |
|||
ParameterExpression inp = Expression.Parameter(typeof(TArg1), "inp"); |
|||
try |
|||
{ |
|||
return Expression.Lambda<Func<TArg1, TResult>>(body(inp), inp).Compile(); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
string msg = ex.Message; // avoid capture of ex itself
|
|||
return delegate { throw new InvalidOperationException(msg); }; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create a function delegate representing a binary operation
|
|||
/// </summary>
|
|||
/// <typeparam name="TArg1">The first parameter type</typeparam>
|
|||
/// <typeparam name="TArg2">The second parameter type</typeparam>
|
|||
/// <typeparam name="TResult">The return type</typeparam>
|
|||
/// <param name="body">Body factory</param>
|
|||
/// <returns>Compiled function delegate</returns>
|
|||
public static Func<TArg1, TArg2, TResult> CreateExpression<TArg1, TArg2, TResult>( |
|||
Func<Expression, Expression, BinaryExpression> body) |
|||
{ |
|||
return CreateExpression<TArg1, TArg2, TResult>(body, false); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create a function delegate representing a binary operation
|
|||
/// </summary>
|
|||
/// <param name="castArgsToResultOnFailure">
|
|||
/// If no matching operation is possible, attempt to convert
|
|||
/// TArg1 and TArg2 to TResult for a match? For example, there is no
|
|||
/// "decimal operator /(decimal, int)", but by converting TArg2 (int) to
|
|||
/// TResult (decimal) a match is found.
|
|||
/// </param>
|
|||
/// <typeparam name="TArg1">The first parameter type</typeparam>
|
|||
/// <typeparam name="TArg2">The second parameter type</typeparam>
|
|||
/// <typeparam name="TResult">The return type</typeparam>
|
|||
/// <param name="body">Body factory</param>
|
|||
/// <returns>Compiled function delegate</returns>
|
|||
public static Func<TArg1, TArg2, TResult> CreateExpression<TArg1, TArg2, TResult>( |
|||
Func<Expression, Expression, BinaryExpression> body, bool castArgsToResultOnFailure) |
|||
{ |
|||
ParameterExpression lhs = Expression.Parameter(typeof(TArg1), "lhs"); |
|||
ParameterExpression rhs = Expression.Parameter(typeof(TArg2), "rhs"); |
|||
try |
|||
{ |
|||
try |
|||
{ |
|||
return Expression.Lambda<Func<TArg1, TArg2, TResult>>(body(lhs, rhs), lhs, rhs).Compile(); |
|||
} |
|||
catch (InvalidOperationException) |
|||
{ |
|||
// If we show retry and the args aren't already "TValue, TValue, TValue"...
|
|||
// convert both lhs and rhs to TResult (as appropriate)
|
|||
if (castArgsToResultOnFailure && !(typeof(TArg1) == typeof(TResult) && typeof(TArg2) == typeof(TResult))) |
|||
{ |
|||
Expression castLhs = typeof(TArg1) == typeof(TResult) |
|||
? lhs |
|||
: (Expression)Expression.Convert(lhs, typeof(TResult)); |
|||
|
|||
Expression castRhs = typeof(TArg2) == typeof(TResult) |
|||
? rhs |
|||
: (Expression)Expression.Convert(rhs, typeof(TResult)); |
|||
|
|||
return Expression.Lambda<Func<TArg1, TArg2, TResult>>( |
|||
body(castLhs, castRhs), lhs, rhs).Compile(); |
|||
} |
|||
|
|||
throw; |
|||
} |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
string msg = ex.Message; // avoid capture of ex itself
|
|||
return delegate { throw new InvalidOperationException(msg); }; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,479 @@ |
|||
namespace GenericImage.Helpers |
|||
{ |
|||
using System; |
|||
using System.Linq.Expressions; |
|||
using System.Reflection; |
|||
|
|||
/// <summary>
|
|||
/// The Operator class provides easy access to the standard operators
|
|||
/// (addition, etc) for generic types, using type inference to simplify
|
|||
/// usage.
|
|||
/// </summary>
|
|||
public static class Operator |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Indicates if the supplied value is non-null,
|
|||
/// for reference-types or Nullable<T>
|
|||
/// </summary>
|
|||
/// <returns>True for non-null values, else false</returns>
|
|||
public static bool HasValue<T>(T value) |
|||
{ |
|||
|
|||
return Operator<T>.NullOp.HasValue(value); |
|||
|
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Increments the accumulator only
|
|||
/// if the value is non-null. If the accumulator
|
|||
/// is null, then the accumulator is given the new
|
|||
/// value; otherwise the accumulator and value
|
|||
/// are added.
|
|||
/// </summary>
|
|||
/// <param name="accumulator">The current total to be incremented (can be null)</param>
|
|||
/// <param name="value">The value to be tested and added to the accumulator</param>
|
|||
/// <returns>True if the value is non-null, else false - i.e.
|
|||
/// "has the accumulator been updated?"</returns>
|
|||
public static bool AddIfNotNull<T>(ref T accumulator, T value) |
|||
{ |
|||
return Operator<T>.NullOp.AddIfNotNull(ref accumulator, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Evaluates unary negation (-) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T Negate<T>(T value) |
|||
{ |
|||
return Operator<T>.Negate(value); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates bitwise not (~) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T Not<T>(T value) |
|||
{ |
|||
return Operator<T>.Not(value); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates bitwise or (|) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T Or<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.Or(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates bitwise and (&) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T And<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.And(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates bitwise xor (^) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T Xor<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.Xor(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Performs a conversion between the given types; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide a suitable cast, or for
|
|||
/// Nullable<TInner> if TInner does not provide this cast.
|
|||
/// </summary>
|
|||
public static TTo Convert<TFrom, TTo>(TFrom value) |
|||
{ |
|||
return Operator<TFrom, TTo>.Convert(value); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary addition (+) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T Add<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.Add(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary addition (+) for the given type(s); this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static TArg1 AddAlternative<TArg1, TArg2>(TArg1 value1, TArg2 value2) |
|||
{ |
|||
return Operator<TArg2, TArg1>.Add(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary subtraction (-) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T Subtract<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.Subtract(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary subtraction(-) for the given type(s); this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static TArg1 SubtractAlternative<TArg1, TArg2>(TArg1 value1, TArg2 value2) |
|||
{ |
|||
return Operator<TArg2, TArg1>.Subtract(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary multiplication (*) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T Multiply<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.Multiply(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary multiplication (*) for the given type(s); this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static TArg1 MultiplyAlternative<TArg1, TArg2>(TArg1 value1, TArg2 value2) |
|||
{ |
|||
return Operator<TArg2, TArg1>.Multiply(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary division (/) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T Divide<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.Divide(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary division (/) for the given type(s); this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static TArg1 DivideAlternative<TArg1, TArg2>(TArg1 value1, TArg2 value2) |
|||
{ |
|||
return Operator<TArg2, TArg1>.Divide(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary equality (==) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static bool Equal<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.Equal(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary inequality (!=) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static bool NotEqual<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.NotEqual(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary greater-than (>) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static bool GreaterThan<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.GreaterThan(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary less-than (<) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static bool LessThan<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.LessThan(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary greater-than-on-eqauls (>=) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static bool GreaterThanOrEqual<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.GreaterThanOrEqual(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary less-than-or-equal (<=) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static bool LessThanOrEqual<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.LessThanOrEqual(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates integer division (/) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary><remarks>
|
|||
/// This operation is particularly useful for computing averages and
|
|||
/// similar aggregates.
|
|||
/// </remarks>
|
|||
public static T DivideInt32<T>(T value, int divisor) |
|||
{ |
|||
return Operator<int, T>.Divide(value, divisor); |
|||
} |
|||
} |
|||
/// <summary>
|
|||
/// Provides standard operators (such as addition) that operate over operands of
|
|||
/// different types. For operators, the return type is assumed to match the first
|
|||
/// operand.
|
|||
/// </summary>
|
|||
/// <seealso cref="Operator<T>"/>
|
|||
/// <seealso cref="Operator"/>
|
|||
public static class Operator<TValue, TResult> |
|||
{ |
|||
private static readonly Func<TValue, TResult> convert; |
|||
/// <summary>
|
|||
/// Returns a delegate to convert a value between two types; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide a suitable cast, or for
|
|||
/// Nullable<TInner> if TInner does not provide this cast.
|
|||
/// </summary>
|
|||
public static Func<TValue, TResult> Convert => convert; |
|||
|
|||
static Operator() |
|||
{ |
|||
convert = ExpressionUtil.CreateExpression<TValue, TResult>(body => Expression.Convert(body, typeof(TResult))); |
|||
add = ExpressionUtil.CreateExpression<TResult, TValue, TResult>(Expression.Add, true); |
|||
subtract = ExpressionUtil.CreateExpression<TResult, TValue, TResult>(Expression.Subtract, true); |
|||
multiply = ExpressionUtil.CreateExpression<TResult, TValue, TResult>(Expression.Multiply, true); |
|||
divide = ExpressionUtil.CreateExpression<TResult, TValue, TResult>(Expression.Divide, true); |
|||
} |
|||
|
|||
private static readonly Func<TResult, TValue, TResult> add, subtract, multiply, divide; |
|||
|
|||
private static readonly Func<TResult, float, TResult> multiplyF, divideF; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary addition (+) for the given types; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<TResult, TValue, TResult> Add => add; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary subtraction (-) for the given types; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<TResult, TValue, TResult> Subtract => subtract; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary multiplication (*) for the given types; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<TResult, TValue, TResult> Multiply => multiply; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary division (/) for the given types; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<TResult, TValue, TResult> Divide => divide; |
|||
|
|||
public static Func<TResult, float, TResult> MultiplyF => multiplyF; |
|||
|
|||
public static Func<TResult, float, TResult> DivideF => divideF; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Provides standard operators (such as addition) over a single type
|
|||
/// </summary>
|
|||
/// <seealso cref="Operator"/>
|
|||
/// <seealso cref="Operator<TValue,TResult>"/>
|
|||
public static class Operator<T> |
|||
{ |
|||
static readonly INullOp<T> nullOp; |
|||
internal static INullOp<T> NullOp => nullOp; |
|||
|
|||
static readonly T zero; |
|||
/// <summary>
|
|||
/// Returns the zero value for value-types (even full Nullable<TInner>) - or null for reference types
|
|||
/// </summary>
|
|||
public static T Zero => zero; |
|||
|
|||
static readonly Func<T, T> negate, not; |
|||
static readonly Func<T, T, T> or, and, xor; |
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate unary negation (-) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T> Negate => negate; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate bitwise not (~) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T> Not => not; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate bitwise or (|) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, T> Or => or; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate bitwise and (&) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, T> And => and; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate bitwise xor (^) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, T> Xor => xor; |
|||
|
|||
static readonly Func<T, T, T> add, subtract, multiply, divide; |
|||
|
|||
static readonly Func<T, float, T> multiplyF, divideF; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary addition (+) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, T> Add => add; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary subtraction (-) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, T> Subtract => subtract; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary multiplication (*) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, T> Multiply => multiply; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary division (/) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, T> Divide => divide; |
|||
|
|||
public static Func<T, float, T> MultiplyF => multiplyF; |
|||
|
|||
public static Func<T, float, T> DivideF => divideF; |
|||
|
|||
static readonly Func<T, T, bool> equal, notEqual, greaterThan, lessThan, greaterThanOrEqual, lessThanOrEqual; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary equality (==) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, bool> Equal => equal; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary inequality (!=) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, bool> NotEqual => notEqual; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary greater-then (>) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, bool> GreaterThan => greaterThan; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary less-than (<) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, bool> LessThan => lessThan; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary greater-than-or-equal (>=) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, bool> GreaterThanOrEqual => greaterThanOrEqual; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary less-than-or-equal (<=) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, bool> LessThanOrEqual => lessThanOrEqual; |
|||
|
|||
static Operator() |
|||
{ |
|||
add = ExpressionUtil.CreateExpression<T, T, T>(Expression.Add); |
|||
subtract = ExpressionUtil.CreateExpression<T, T, T>(Expression.Subtract); |
|||
divide = ExpressionUtil.CreateExpression<T, T, T>(Expression.Divide); |
|||
multiply = ExpressionUtil.CreateExpression<T, T, T>(Expression.Multiply); |
|||
multiplyF = ExpressionUtil.CreateExpression<T, float, T>(Expression.Multiply); |
|||
divideF = ExpressionUtil.CreateExpression<T, float, T>(Expression.Multiply); |
|||
|
|||
greaterThan = ExpressionUtil.CreateExpression<T, T, bool>(Expression.GreaterThan); |
|||
greaterThanOrEqual = ExpressionUtil.CreateExpression<T, T, bool>(Expression.GreaterThanOrEqual); |
|||
lessThan = ExpressionUtil.CreateExpression<T, T, bool>(Expression.LessThan); |
|||
lessThanOrEqual = ExpressionUtil.CreateExpression<T, T, bool>(Expression.LessThanOrEqual); |
|||
equal = ExpressionUtil.CreateExpression<T, T, bool>(Expression.Equal); |
|||
notEqual = ExpressionUtil.CreateExpression<T, T, bool>(Expression.NotEqual); |
|||
|
|||
negate = ExpressionUtil.CreateExpression<T, T>(Expression.Negate); |
|||
and = ExpressionUtil.CreateExpression<T, T, T>(Expression.And); |
|||
or = ExpressionUtil.CreateExpression<T, T, T>(Expression.Or); |
|||
not = ExpressionUtil.CreateExpression<T, T>(Expression.Not); |
|||
xor = ExpressionUtil.CreateExpression<T, T, T>(Expression.ExclusiveOr); |
|||
|
|||
Type typeT = typeof(T); |
|||
if (typeT.GetTypeInfo().IsValueType && typeT.GetTypeInfo().IsGenericType && (typeT.GetGenericTypeDefinition() == typeof(Nullable<>))) |
|||
{ |
|||
// get the *inner* zero (not a null Nullable<TValue>, but default(TValue))
|
|||
Type nullType = typeT.GetTypeInfo().GenericTypeArguments[0]; |
|||
zero = (T)Activator.CreateInstance(nullType); |
|||
nullOp = (INullOp<T>)Activator.CreateInstance( |
|||
typeof(StructNullOp<>).MakeGenericType(nullType)); |
|||
} |
|||
else |
|||
{ |
|||
zero = default(T); |
|||
if (typeT.GetTypeInfo().IsValueType) |
|||
{ |
|||
nullOp = (INullOp<T>)Activator.CreateInstance( |
|||
typeof(StructNullOp<>).MakeGenericType(typeT)); |
|||
} |
|||
else |
|||
{ |
|||
nullOp = (INullOp<T>)Activator.CreateInstance( |
|||
typeof(ClassNullOp<>).MakeGenericType(typeT)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,52 +1,85 @@ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
using GenericImage.Helpers; |
|||
using GenericImage.PackedVectors; |
|||
|
|||
namespace GenericImage.PackedVectors |
|||
{ |
|||
public struct Bgra<TDepth> : IColor4<TDepth> |
|||
public struct Bgra<TDepth> : IColor<TDepth> |
|||
where TDepth : struct |
|||
{ |
|||
public TDepth X { get; set; } |
|||
|
|||
public TDepth Y { get; set; } |
|||
private static readonly TDepth[] Components = new TDepth[4]; |
|||
|
|||
public TDepth Z { get; set; } |
|||
|
|||
public TDepth W { get; set; } |
|||
public TDepth[] Values => Components; |
|||
|
|||
public void Add<TColor>(TColor value) where TColor : IColor<TDepth> |
|||
{ |
|||
throw new NotImplementedException(); |
|||
for (int i = 0; i < value.Values.Length; i++) |
|||
{ |
|||
this.Values[i] = Operator<TDepth>.Add(this.Values[i], value.Values[i]); |
|||
} |
|||
} |
|||
|
|||
public void Multiply<TColor>(TColor value) where TColor : IColor<TDepth> |
|||
{ |
|||
throw new NotImplementedException(); |
|||
for (int i = 0; i < value.Values.Length; i++) |
|||
{ |
|||
this.Values[i] = Operator<TDepth>.Multiply(this.Values[i], value.Values[i]); |
|||
} |
|||
} |
|||
|
|||
public void Multiply<TColor>(float value) where TColor : IColor<TDepth> |
|||
{ |
|||
throw new NotImplementedException(); |
|||
for (int i = 0; i < this.Values.Length; i++) |
|||
{ |
|||
this.Values[i] = Operator<TDepth>.MultiplyF(this.Values[i], value); |
|||
} |
|||
} |
|||
|
|||
public void Divide<TColor>(TColor value) where TColor : IColor<TDepth> |
|||
{ |
|||
throw new NotImplementedException(); |
|||
for (int i = 0; i < value.Values.Length; i++) |
|||
{ |
|||
this.Values[i] = Operator<TDepth>.Divide(this.Values[i], value.Values[i]); |
|||
} |
|||
} |
|||
|
|||
public void PackVector(Vector4 vector) |
|||
public void Divide<TColor>(float value) where TColor : IColor<TDepth> |
|||
{ |
|||
throw new NotImplementedException(); |
|||
for (int i = 0; i < this.Values.Length; i++) |
|||
{ |
|||
this.Values[i] = Operator<TDepth>.DivideF(this.Values[i], value); |
|||
} |
|||
} |
|||
|
|||
public Vector4 ToVector() |
|||
public byte[] ToBytes() |
|||
{ |
|||
throw new NotImplementedException(); |
|||
if (typeof(TDepth) == typeof(byte)) |
|||
{ |
|||
return new[] |
|||
{ |
|||
(byte)(object)this.Values[0], |
|||
(byte)(object)this.Values[1], |
|||
(byte)(object)this.Values[2], |
|||
(byte)(object)this.Values[3] |
|||
}; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
public byte[] ToBytes() |
|||
public void FromBytes(byte[] bytes) |
|||
{ |
|||
throw new System.NotImplementedException(); |
|||
if (bytes.Length != 4) |
|||
{ |
|||
throw new ArgumentOutOfRangeException(nameof(bytes)); |
|||
} |
|||
|
|||
for (int i = 0; i < bytes.Length; i++) |
|||
{ |
|||
this.Values[i] = (TDepth)(object)bytes[i]; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,58 @@ |
|||
namespace ImageProcessorCore.Helpers |
|||
{ |
|||
interface INullOp<T> |
|||
{ |
|||
bool HasValue(T value); |
|||
bool AddIfNotNull(ref T accumulator, T value); |
|||
} |
|||
sealed class StructNullOp<T> |
|||
: INullOp<T>, INullOp<T?> |
|||
where T : struct |
|||
{ |
|||
public bool HasValue(T value) |
|||
{ |
|||
return true; |
|||
} |
|||
public bool AddIfNotNull(ref T accumulator, T value) |
|||
{ |
|||
accumulator = Operator<T>.Add(accumulator, value); |
|||
return true; |
|||
} |
|||
public bool HasValue(T? value) |
|||
{ |
|||
return value.HasValue; |
|||
} |
|||
public bool AddIfNotNull(ref T? accumulator, T? value) |
|||
{ |
|||
if (value.HasValue) |
|||
{ |
|||
accumulator = accumulator.HasValue ? |
|||
Operator<T>.Add( |
|||
accumulator.GetValueOrDefault(), |
|||
value.GetValueOrDefault()) |
|||
: value; |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
} |
|||
sealed class ClassNullOp<T> |
|||
: INullOp<T> |
|||
where T : class |
|||
{ |
|||
public bool HasValue(T value) |
|||
{ |
|||
return value != null; |
|||
} |
|||
public bool AddIfNotNull(ref T accumulator, T value) |
|||
{ |
|||
if (value != null) |
|||
{ |
|||
accumulator = accumulator == null ? |
|||
value : Operator<T>.Add(accumulator, value); |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,100 @@ |
|||
namespace ImageProcessorCore.Helpers |
|||
{ |
|||
using System; |
|||
using System.Linq.Expressions; |
|||
|
|||
/// <summary>
|
|||
/// General purpose Expression utilities
|
|||
/// </summary>
|
|||
public static class ExpressionUtil |
|||
{ |
|||
/// <summary>
|
|||
/// Create a function delegate representing a unary operation
|
|||
/// </summary>
|
|||
/// <typeparam name="TArg1">The parameter type</typeparam>
|
|||
/// <typeparam name="TResult">The return type</typeparam>
|
|||
/// <param name="body">Body factory</param>
|
|||
/// <returns>Compiled function delegate</returns>
|
|||
public static Func<TArg1, TResult> CreateExpression<TArg1, TResult>( |
|||
Func<Expression, UnaryExpression> body) |
|||
{ |
|||
ParameterExpression inp = Expression.Parameter(typeof(TArg1), "inp"); |
|||
try |
|||
{ |
|||
return Expression.Lambda<Func<TArg1, TResult>>(body(inp), inp).Compile(); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
string msg = ex.Message; // avoid capture of ex itself
|
|||
return delegate { throw new InvalidOperationException(msg); }; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create a function delegate representing a binary operation
|
|||
/// </summary>
|
|||
/// <typeparam name="TArg1">The first parameter type</typeparam>
|
|||
/// <typeparam name="TArg2">The second parameter type</typeparam>
|
|||
/// <typeparam name="TResult">The return type</typeparam>
|
|||
/// <param name="body">Body factory</param>
|
|||
/// <returns>Compiled function delegate</returns>
|
|||
public static Func<TArg1, TArg2, TResult> CreateExpression<TArg1, TArg2, TResult>( |
|||
Func<Expression, Expression, BinaryExpression> body) |
|||
{ |
|||
return CreateExpression<TArg1, TArg2, TResult>(body, false); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create a function delegate representing a binary operation
|
|||
/// </summary>
|
|||
/// <param name="castArgsToResultOnFailure">
|
|||
/// If no matching operation is possible, attempt to convert
|
|||
/// TArg1 and TArg2 to TResult for a match? For example, there is no
|
|||
/// "decimal operator /(decimal, int)", but by converting TArg2 (int) to
|
|||
/// TResult (decimal) a match is found.
|
|||
/// </param>
|
|||
/// <typeparam name="TArg1">The first parameter type</typeparam>
|
|||
/// <typeparam name="TArg2">The second parameter type</typeparam>
|
|||
/// <typeparam name="TResult">The return type</typeparam>
|
|||
/// <param name="body">Body factory</param>
|
|||
/// <returns>Compiled function delegate</returns>
|
|||
public static Func<TArg1, TArg2, TResult> CreateExpression<TArg1, TArg2, TResult>( |
|||
Func<Expression, Expression, BinaryExpression> body, bool castArgsToResultOnFailure) |
|||
{ |
|||
ParameterExpression lhs = Expression.Parameter(typeof(TArg1), "lhs"); |
|||
ParameterExpression rhs = Expression.Parameter(typeof(TArg2), "rhs"); |
|||
try |
|||
{ |
|||
try |
|||
{ |
|||
return Expression.Lambda<Func<TArg1, TArg2, TResult>>(body(lhs, rhs), lhs, rhs).Compile(); |
|||
} |
|||
catch (InvalidOperationException) |
|||
{ |
|||
// If we show retry and the args aren't already "TValue, TValue, TValue"...
|
|||
// convert both lhs and rhs to TResult (as appropriate)
|
|||
if (castArgsToResultOnFailure && !(typeof(TArg1) == typeof(TResult) && typeof(TArg2) == typeof(TResult))) |
|||
{ |
|||
Expression castLhs = typeof(TArg1) == typeof(TResult) |
|||
? lhs |
|||
: (Expression)Expression.Convert(lhs, typeof(TResult)); |
|||
|
|||
Expression castRhs = typeof(TArg2) == typeof(TResult) |
|||
? rhs |
|||
: (Expression)Expression.Convert(rhs, typeof(TResult)); |
|||
|
|||
return Expression.Lambda<Func<TArg1, TArg2, TResult>>( |
|||
body(castLhs, castRhs), lhs, rhs).Compile(); |
|||
} |
|||
|
|||
throw; |
|||
} |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
string msg = ex.Message; // avoid capture of ex itself
|
|||
return delegate { throw new InvalidOperationException(msg); }; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,464 @@ |
|||
namespace ImageProcessorCore.Helpers |
|||
{ |
|||
using System; |
|||
using System.Linq.Expressions; |
|||
using System.Reflection; |
|||
|
|||
/// <summary>
|
|||
/// The Operator class provides easy access to the standard operators
|
|||
/// (addition, etc) for generic types, using type inference to simplify
|
|||
/// usage.
|
|||
/// </summary>
|
|||
public static class Operator |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Indicates if the supplied value is non-null,
|
|||
/// for reference-types or Nullable<T>
|
|||
/// </summary>
|
|||
/// <returns>True for non-null values, else false</returns>
|
|||
public static bool HasValue<T>(T value) |
|||
{ |
|||
|
|||
return Operator<T>.NullOp.HasValue(value); |
|||
|
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Increments the accumulator only
|
|||
/// if the value is non-null. If the accumulator
|
|||
/// is null, then the accumulator is given the new
|
|||
/// value; otherwise the accumulator and value
|
|||
/// are added.
|
|||
/// </summary>
|
|||
/// <param name="accumulator">The current total to be incremented (can be null)</param>
|
|||
/// <param name="value">The value to be tested and added to the accumulator</param>
|
|||
/// <returns>True if the value is non-null, else false - i.e.
|
|||
/// "has the accumulator been updated?"</returns>
|
|||
public static bool AddIfNotNull<T>(ref T accumulator, T value) |
|||
{ |
|||
return Operator<T>.NullOp.AddIfNotNull(ref accumulator, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Evaluates unary negation (-) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T Negate<T>(T value) |
|||
{ |
|||
return Operator<T>.Negate(value); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates bitwise not (~) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T Not<T>(T value) |
|||
{ |
|||
return Operator<T>.Not(value); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates bitwise or (|) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T Or<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.Or(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates bitwise and (&) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T And<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.And(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates bitwise xor (^) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T Xor<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.Xor(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Performs a conversion between the given types; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide a suitable cast, or for
|
|||
/// Nullable<TInner> if TInner does not provide this cast.
|
|||
/// </summary>
|
|||
public static TTo Convert<TFrom, TTo>(TFrom value) |
|||
{ |
|||
return Operator<TFrom, TTo>.Convert(value); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary addition (+) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T Add<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.Add(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary addition (+) for the given type(s); this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static TArg1 AddAlternative<TArg1, TArg2>(TArg1 value1, TArg2 value2) |
|||
{ |
|||
return Operator<TArg2, TArg1>.Add(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary subtraction (-) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T Subtract<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.Subtract(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary subtraction(-) for the given type(s); this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static TArg1 SubtractAlternative<TArg1, TArg2>(TArg1 value1, TArg2 value2) |
|||
{ |
|||
return Operator<TArg2, TArg1>.Subtract(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary multiplication (*) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T Multiply<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.Multiply(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary multiplication (*) for the given type(s); this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static TArg1 MultiplyAlternative<TArg1, TArg2>(TArg1 value1, TArg2 value2) |
|||
{ |
|||
return Operator<TArg2, TArg1>.Multiply(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary division (/) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static T Divide<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.Divide(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary division (/) for the given type(s); this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static TArg1 DivideAlternative<TArg1, TArg2>(TArg1 value1, TArg2 value2) |
|||
{ |
|||
return Operator<TArg2, TArg1>.Divide(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary equality (==) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static bool Equal<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.Equal(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary inequality (!=) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static bool NotEqual<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.NotEqual(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary greater-than (>) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static bool GreaterThan<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.GreaterThan(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary less-than (<) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static bool LessThan<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.LessThan(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary greater-than-on-eqauls (>=) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static bool GreaterThanOrEqual<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.GreaterThanOrEqual(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates binary less-than-or-equal (<=) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static bool LessThanOrEqual<T>(T value1, T value2) |
|||
{ |
|||
return Operator<T>.LessThanOrEqual(value1, value2); |
|||
} |
|||
/// <summary>
|
|||
/// Evaluates integer division (/) for the given type; this will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary><remarks>
|
|||
/// This operation is particularly useful for computing averages and
|
|||
/// similar aggregates.
|
|||
/// </remarks>
|
|||
public static T DivideInt32<T>(T value, int divisor) |
|||
{ |
|||
return Operator<int, T>.Divide(value, divisor); |
|||
} |
|||
} |
|||
/// <summary>
|
|||
/// Provides standard operators (such as addition) that operate over operands of
|
|||
/// different types. For operators, the return type is assumed to match the first
|
|||
/// operand.
|
|||
/// </summary>
|
|||
/// <seealso cref="Operator<T>"/>
|
|||
/// <seealso cref="Operator"/>
|
|||
public static class Operator<TValue, TResult> |
|||
{ |
|||
private static readonly Func<TValue, TResult> convert; |
|||
/// <summary>
|
|||
/// Returns a delegate to convert a value between two types; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide a suitable cast, or for
|
|||
/// Nullable<TInner> if TInner does not provide this cast.
|
|||
/// </summary>
|
|||
public static Func<TValue, TResult> Convert => convert; |
|||
|
|||
static Operator() |
|||
{ |
|||
convert = ExpressionUtil.CreateExpression<TValue, TResult>(body => Expression.Convert(body, typeof(TResult))); |
|||
add = ExpressionUtil.CreateExpression<TResult, TValue, TResult>(Expression.Add, true); |
|||
subtract = ExpressionUtil.CreateExpression<TResult, TValue, TResult>(Expression.Subtract, true); |
|||
multiply = ExpressionUtil.CreateExpression<TResult, TValue, TResult>(Expression.Multiply, true); |
|||
divide = ExpressionUtil.CreateExpression<TResult, TValue, TResult>(Expression.Divide, true); |
|||
} |
|||
|
|||
private static readonly Func<TResult, TValue, TResult> add, subtract, multiply, divide; |
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary addition (+) for the given types; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<TResult, TValue, TResult> Add => add; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary subtraction (-) for the given types; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<TResult, TValue, TResult> Subtract => subtract; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary multiplication (*) for the given types; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<TResult, TValue, TResult> Multiply => multiply; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary division (/) for the given types; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<TResult, TValue, TResult> Divide => divide; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Provides standard operators (such as addition) over a single type
|
|||
/// </summary>
|
|||
/// <seealso cref="Operator"/>
|
|||
/// <seealso cref="Operator<TValue,TResult>"/>
|
|||
public static class Operator<T> |
|||
{ |
|||
static readonly INullOp<T> nullOp; |
|||
internal static INullOp<T> NullOp => nullOp; |
|||
|
|||
static readonly T zero; |
|||
/// <summary>
|
|||
/// Returns the zero value for value-types (even full Nullable<TInner>) - or null for reference types
|
|||
/// </summary>
|
|||
public static T Zero => zero; |
|||
|
|||
static readonly Func<T, T> negate, not; |
|||
static readonly Func<T, T, T> or, and, xor; |
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate unary negation (-) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T> Negate => negate; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate bitwise not (~) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T> Not => not; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate bitwise or (|) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, T> Or => or; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate bitwise and (&) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, T> And => and; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate bitwise xor (^) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, T> Xor => xor; |
|||
|
|||
static readonly Func<T, T, T> add, subtract, multiply, divide; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary addition (+) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, T> Add => add; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary subtraction (-) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, T> Subtract => subtract; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary multiplication (*) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, T> Multiply => multiply; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary division (/) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, T> Divide => divide; |
|||
|
|||
static readonly Func<T, T, bool> equal, notEqual, greaterThan, lessThan, greaterThanOrEqual, lessThanOrEqual; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary equality (==) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, bool> Equal => equal; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary inequality (!=) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, bool> NotEqual => notEqual; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary greater-then (>) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, bool> GreaterThan => greaterThan; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary less-than (<) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, bool> LessThan => lessThan; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary greater-than-or-equal (>=) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, bool> GreaterThanOrEqual => greaterThanOrEqual; |
|||
|
|||
/// <summary>
|
|||
/// Returns a delegate to evaluate binary less-than-or-equal (<=) for the given type; this delegate will throw
|
|||
/// an InvalidOperationException if the type T does not provide this operator, or for
|
|||
/// Nullable<TInner> if TInner does not provide this operator.
|
|||
/// </summary>
|
|||
public static Func<T, T, bool> LessThanOrEqual => lessThanOrEqual; |
|||
|
|||
static Operator() |
|||
{ |
|||
add = ExpressionUtil.CreateExpression<T, T, T>(Expression.Add); |
|||
subtract = ExpressionUtil.CreateExpression<T, T, T>(Expression.Subtract); |
|||
divide = ExpressionUtil.CreateExpression<T, T, T>(Expression.Divide); |
|||
multiply = ExpressionUtil.CreateExpression<T, T, T>(Expression.Multiply); |
|||
|
|||
greaterThan = ExpressionUtil.CreateExpression<T, T, bool>(Expression.GreaterThan); |
|||
greaterThanOrEqual = ExpressionUtil.CreateExpression<T, T, bool>(Expression.GreaterThanOrEqual); |
|||
lessThan = ExpressionUtil.CreateExpression<T, T, bool>(Expression.LessThan); |
|||
lessThanOrEqual = ExpressionUtil.CreateExpression<T, T, bool>(Expression.LessThanOrEqual); |
|||
equal = ExpressionUtil.CreateExpression<T, T, bool>(Expression.Equal); |
|||
notEqual = ExpressionUtil.CreateExpression<T, T, bool>(Expression.NotEqual); |
|||
|
|||
negate = ExpressionUtil.CreateExpression<T, T>(Expression.Negate); |
|||
and = ExpressionUtil.CreateExpression<T, T, T>(Expression.And); |
|||
or = ExpressionUtil.CreateExpression<T, T, T>(Expression.Or); |
|||
not = ExpressionUtil.CreateExpression<T, T>(Expression.Not); |
|||
xor = ExpressionUtil.CreateExpression<T, T, T>(Expression.ExclusiveOr); |
|||
|
|||
Type typeT = typeof(T); |
|||
if (typeT.GetTypeInfo().IsValueType && typeT.GetTypeInfo().IsGenericType && (typeT.GetGenericTypeDefinition() == typeof(Nullable<>))) |
|||
{ |
|||
// get the *inner* zero (not a null Nullable<TValue>, but default(TValue))
|
|||
Type nullType = typeT.GetTypeInfo().GenericTypeArguments[0]; |
|||
zero = (T)Activator.CreateInstance(nullType); |
|||
nullOp = (INullOp<T>)Activator.CreateInstance( |
|||
typeof(StructNullOp<>).MakeGenericType(nullType)); |
|||
} |
|||
else |
|||
{ |
|||
zero = default(T); |
|||
if (typeT.GetTypeInfo().IsValueType) |
|||
{ |
|||
nullOp = (INullOp<T>)Activator.CreateInstance( |
|||
typeof(StructNullOp<>).MakeGenericType(typeT)); |
|||
} |
|||
else |
|||
{ |
|||
nullOp = (INullOp<T>)Activator.CreateInstance( |
|||
typeof(ClassNullOp<>).MakeGenericType(typeT)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue