Skip to content

Instantly share code, notes, and snippets.

@MartinNowak
Last active December 15, 2015 23:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save MartinNowak/5338859 to your computer and use it in GitHub Desktop.
Save MartinNowak/5338859 to your computer and use it in GitHub Desktop.
pure:
nothrow:
// T[] = T[] op T[]
void arrayOp(string op, T)(T[] res, in T[] a, in T[] b)
in
{
assert(res.length == a.length);
assert(res.length == b.length);
}
body
{
arrayOpTmpl!(T).impl!op(res, a, b);
}
// T[] = T[] op T
void arrayOp(string op, T)(T[] res, in T[] a, in T b)
in { assert(res.length == a.length); }
body
{
arrayOpTmpl!(T).impl!op(res, a, b);
}
// T[] = T op T[]
void arrayOp(string op, T)(T[] res, in T a, in T[] b)
in { assert(res.length == b.length); }
body
{
// less template instantiations for commutative ops
static if (op == "+" || op == "*")
arrayOpTmpl!(T).impl!op(res, b, a);
else
arrayOpTmpl!(T).impl!op(res, a, b);
}
private template arrayOpTmpl(T, size_t regsz = 16)
{
enum N = regsz / T.sizeof;
alias __vector(T[N]) vec;
static bool sameAlignment(in ref T[] a, in ref T[] b)
{
return (cast(size_t)a.ptr & regsz - 1) == (cast(size_t)b.ptr & regsz - 1);
}
static bool sameAlignment(in ref T[] a, in T b)
{
return true;
}
static inout(vec)* loopVar(ref inout(T[]) a, size_t pos)
{
return cast(inout(vec)*)(a.ptr + pos);
}
static const(vec) loopVar(in T a, size_t pos)
{
vec res = void;
version (DigitalMars) // Bugzilla 7509
res.array = a;
else
res = a;
return res;
}
void impl(string op, TA, TB)(T[] res, in TA a, in TB b)
{
enum ai = is(TA == const(T)[]) ? "a[i]" : "a";
enum bi = is(TB == const(T)[]) ? "b[i]" : "b";
size_t pos;
if (sameAlignment(res, a) &&
sameAlignment(res, b))
{
pos = (-cast(size_t)res.ptr & regsz - 1) / T.sizeof;
foreach (i; 0 .. pos)
res[i] = cast(T)mixin(ai~op~bi);
if (auto nvec = res.length / N)
{
auto vres = loopVar(res, pos);
auto va = loopVar(a, pos);
auto vb = loopVar(b, pos);
pos += nvec * N;
foreach (i; 0 .. nvec)
vres[i] = mixin("v"~ai~op~"v"~bi);
}
}
foreach (i; pos .. res.length)
res[i] = cast(T)mixin(ai~op~bi);
}
}
template TT(T...) { alias T TT; }
unittest
{
static void check(string op, TA, TB, T, size_t N)(in TA a, in TB b, in T[N] exp)
{
T[N] res;
arrayOp!op(res, a, b);
if (res != exp)
{
debug
{
import std.stdio;
writeln(T.stringof);
writeln("expected: ", a, op, b, " == ", exp);
writeln("actual: ", res);
}
assert(0);
}
}
static void test(T, string op, size_t N = 16)(T a, T b, T exp)
{
T[N] va = a, vb = b, vexp = exp;
check!op(va, vb, vexp);
check!op(va, b, vexp);
check!op(a, vb, vexp);
}
alias TT!(ubyte, ushort, uint, ulong) UINTS;
alias TT!(byte, short, int, long) INTS;
alias TT!(float, double) FLOATS;
foreach (T; TT!(UINTS, INTS, FLOATS))
{
test!(T, "+")(1, 2, 3);
test!(T, "-")(3, 2, 1);
}
foreach (T; TT!(INTS, FLOATS))
{
test!(T, "-")(1, 2, -1);
}
foreach (T; TT!(FLOATS))
{
test!(T, "*")(2, 3, 6);
test!(T, "/")(8, 4, 2);
}
// TODO
version (none)
{
foreach (T; TT!(INTS, UINTS))
{
test!(T, "*")(2, 3, 6);
test!(T, "/")(8, 4, 2);
}
}
}
void main()
{
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment