template ExpressionOperators(size_t spec, size_t rs, size_t cs)
enum stringMixin =
format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
static if(is(typeof({enum _unused_ = this.rows;}))) static assert(rows != 0);
static if(is(typeof({enum _unused_ = this.cols;}))) static assert(cols != 0);
alias at = opIndex;
} ~ (rs == 1 ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
alias cols length;
alias length opDollar;
auto ref opIndex(size_t i) inout
in{
assert(i < this.cols);
}
body{
return this[0, i];
}
static if(is(typeof({this[0, 0] = this[0, 0];})))
{
auto ref opIndexAssign(S)(S value, size_t i)
if(is(typeof(this[0, i] = value)))
in{
assert(i < this.cols);
}
body{
return this[0, i] = value;
}
auto ref opIndexOpAssign(string op, S)(S value, size_t i)
if(is(typeof(mixin("this[0, i] " ~ op ~ "= value"))))
in{
assert(i < this.cols);
}
body{
return mixin("this[0, i] " ~ op ~ "= value");
}
}
} : (cs == 1 ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
alias rows length;
alias length opDollar;
auto ref opIndex(size_t i) inout
in{
assert(i < this.rows);
}
body{
return this[i, 0];
}
static if(is(typeof({this[0, 0] = this[0, 0];})))
{
auto ref opIndexAssign(S)(S value, size_t i)
if(is(typeof(this[i, 0] = value)))
in{
assert(i < this.rows);
}
body{
return this[0, i] = value;
}
auto ref opIndexOpAssign(string op, S)(S value, size_t i)
if(is(typeof(mixin("this[i, 0] " ~ op ~ "= value"))))
in{
assert(i < this.rows);
}
body{
return mixin("this[i, 0] " ~ op ~ "= value");
}
}
} : "")) ~ (rs == 1 && cs == 1 ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto det() const @property
{
return this[0, 0];
}
alias det this;
auto ref opAssign(S)(S value)
if(is(typeof(this[0, 0] = value)))
{
return this[0, 0] = value;
}
auto ref opOpAssign(S)(S value)
if(is(typeof(mixin("this[0, 0] " ~ op ~ "= value"))))
{
return mixin("this[0, 0] " ~ op ~ "= value");
}
} : "") ~ (spec & ETOSpec.opEquals ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
bool opEquals(Rhs)(auto ref const Rhs mat) const
if(isMatrix!Rhs || isAbstractMatrix!Rhs)
{
static assert(isValidOperator!(Unqual!(typeof(this)), "+", Rhs));
static if(isAbstractMatrix!Rhs)
{
auto result = Rhs.inferSize(this.rows, this.cols);
if(!result.isValid)
return false;
}
else
{
if(this.rows != mat.rows)
return false;
if(this.cols != mat.cols)
return false;
}
foreach(i; 0 .. this.rows)
foreach(j; 0 .. this.cols)
if(this[i, j] != mat.at(i, j))
return false;
return true;
}
} : "") ~ (spec & ETOSpec.toString ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
@property
void toString(scope void delegate(const(char)[]) sink, string formatString) const @system
{
sink.formattedWrite(formatString, this.toRange);
}
} : "") ~ (spec & ETOSpec.opAssign ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
void opAssign(M)(M m)
if((isMatrix!M || isAbstractMatrix!M) && is(typeof(this[0, 0] = m.at(0, 0))))
in{
static if(isAbstractMatrix!M)
assert(m.inferSize(this.rows, this.cols).isValid);
else
{
assert(m.rows == this.rows);
assert(m.cols == this.cols);
}
}
body{
static assert(isValidOperator!(typeof(this), "=", M));
foreach(i; 0 .. this.rows)
foreach(j; 0 .. this.cols)
this[i, j] = m.at(i, j);
}
} : "") ~ (spec & ETOSpec.matrixAddMatrix ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto opBinary(string op : "+", Rhs)(auto ref Rhs mat) const
if(isMatrix!Rhs || isAbstractMatrix!Rhs)
in{
static if(isAbstractMatrix!Rhs)
assert(mat.inferSize(this.rows, this.cols).isValid);
else
{
assert(mat.rows == this.rows);
assert(mat.cols == this.cols);
}
}
body{
static assert(isValidOperator!(typeof(this), op, Rhs));
return matrixExpression!"+"(this, mat);
}
} : "") ~ (spec & ETOSpec.matrixSubMatrix ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto opBinary(string op : "-", Rhs)(auto ref Rhs mat) const
if(isMatrix!Rhs || isAbstractMatrix!Rhs)
in{
static if(isAbstractMatrix!Rhs)
assert(mat.inferSize(this.rows, this.cols).isValid);
else
{
assert(mat.rows == this.rows);
assert(mat.cols == this.cols);
}
}
body{
static assert(isValidOperator!(typeof(this), op, Rhs));
return matrixExpression!"-"(this, mat);
}
} : "") ~ (spec & ETOSpec.matrixMulMatrix ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto opBinary(string op : "*", Rhs)(auto ref Rhs mat) const
if(isMatrix!Rhs || isAbstractMatrix!Rhs)
in{
static if(isAbstractMatrix!Rhs)
assert(mat.inferSize(this.cols, wild).isValid);
else
assert(mat.rows == this.cols);
}
body{
static assert(isValidOperator!(typeof(this), op, Rhs));
return matrixExpression!"*"(this, mat);
}
} : "") ~ (spec & ETOSpec.matrixAddScalar ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto opBinary(string op : "+", S)(S s) const
if(isNotVectorOrMatrix!S)
{
static assert(isValidOperator!(typeof(this), op, S));
return matrixExpression!"+"(this, s);
}
} : "") ~ (spec & ETOSpec.scalarAddMatrix ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto opBinaryRight(string op : "+", S)(S s) const
if(isNotVectorOrMatrix!S)
{
static assert(isValidOperator!(S, op, typeof(this)));
return matrixExpression!"+"(s, this);
}
} : "") ~ (spec & ETOSpec.matrixSubScalar ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto opBinary(string op : "-", S)(S s) const
if(isNotVectorOrMatrix!S)
{
static assert(isValidOperator!(typeof(this), op, S));
return matrixExpression!"-"(this, s);
}
} : "") ~ (spec & ETOSpec.scalarSubMatrix ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto opBinaryRight(string op : "-", S)(S s) const
if(isNotVectorOrMatrix!S)
{
static assert(isValidOperator!(S, op, typeof(this)));
return matrixExpression!"-"(s, this);
}
} : "") ~ (spec & ETOSpec.matrixMulScalar ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto opBinary(string op : "*", S)(S s) const
if(isNotVectorOrMatrix!S)
{
static assert(isValidOperator!(typeof(this), op, S));
return matrixExpression!"*"(this, s);
}
} : "") ~ (spec & ETOSpec.scalarMulMatrix ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto opBinaryRight(string op : "*", S)(S s) const
if(isNotVectorOrMatrix!S)
{
static assert(isValidOperator!(S, op, typeof(this)));
return matrixExpression!"*"(s, this);
}
} : "") ~ (spec & ETOSpec.matrixDivScalar ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto opBinary(string op : "/", S)(S s) const
if(isNotVectorOrMatrix!S)
{
static assert(isValidOperator!(typeof(this), op, S));
return matrixExpression!"/"(this, s);
}
} : "") ~ (spec & ETOSpec.scalarDivMatrix ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto opBinaryRight(string op : "/", S)(S s) const
if(isNotVectorOrMatrix!S)
{
static assert(isValidOperator!(S, op, typeof(this)));
return matrixExpression!"/"(s, this);
}
} : "") ~ (spec & ETOSpec.addScalar ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
void opOpAssign(string op : "+", S)(S scalar)
if(is(typeof(this[0, 0] += scalar)))
{
foreach(r; 0 .. rows)
foreach(c; 0 .. cols)
this[r, c] += scalar;
}
} : "") ~ (spec & ETOSpec.subScalar ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
void opOpAssign(string op : "-", S)(S scalar)
if(is(typeof(this[0, 0] -= scalar)))
{
foreach(r; 0 .. rows)
foreach(c; 0 .. cols)
this[r, c] -= scalar;
}
} : "") ~ (spec & ETOSpec.mulScalar ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
void opOpAssign(string op : "*", S)(S scalar)
if(is(typeof(this[0, 0] *= scalar)))
{
foreach(r; 0 .. rows)
foreach(c; 0 .. cols)
this[r, c] *= scalar;
}
} : "") ~ (spec & ETOSpec.divScalar ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
void opOpAssign(string op : "/", S)(S scalar)
if(is(typeof(this[0, 0] /= scalar)))
{
foreach(r; 0 .. rows)
foreach(c; 0 .. cols)
this[r, c] /= scalar;
}
} : "") ~ ((spec & ETOSpec.swizzle) && (rs == 1 || cs == 1) ? (rs * cs >= 1 ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto ref a() inout @property { return this[0]; }
alias x = a;
alias r = a;
alias re = a;
} : "") ~ (rs * cs >= 2 ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto ref b() inout @property { return this[1]; }
alias y = b;
alias im = b;
alias i = b;
} : "") ~ (rs * cs >= 3 ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto ref c() inout @property { return this[2]; }
alias z = c;
alias j = c;
} : "") ~ (rs * cs >= 4 ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto ref d() inout @property { return this[3]; }
alias k = d;
alias w = d;
} : "") ~ (rs * cs >= 5 ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto ref e() inout @property { return this[4]; }
} : "") ~ (rs * cs >= 6 ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto ref f() inout @property { return this[5]; }
} : "") ~ (rs * cs >= 7 ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto ref g() inout @property { return this[6]; }
} : "") ~ (rs * cs >= 8 ? format(`#line %s "%s"`, __LINE__ + 2, __FILE__) ~ q{
auto ref h() inout @property { return this[7]; }
} : "") : "");