1 /// Arbitrary indexable SIMD optimized vector implementation. 2 module tern.legacy.vector; 3 4 import core.simd; 5 6 /// Arbitrary vector implementation, allows any length vector less than or equal to 256 bits and can be interacted with as an array. 7 public struct Vector(T, size_t LENGTH) 8 if (isIntegral!T || isFloatingPoint!T) 9 { 10 enum is256 = LENGTH * T.sizeof > 16; 11 static if (is256) 12 { 13 static if (T.sizeof % 8 == 0) 14 T[4] data; 15 else static if (T.sizeof % 4 == 0) 16 T[8] data; 17 else static if (T.sizeof % 2 == 0) 18 T[16] data; 19 else 20 T[32] data; 21 } 22 else 23 { 24 static if (T.sizeof % 8 == 0) 25 T[2] data; 26 else static if (T.sizeof % 4 == 0) 27 T[4] data; 28 else static if (T.sizeof % 2 == 0) 29 T[8] data; 30 else 31 T[16] data; 32 } 33 alias data this; 34 35 public: 36 final: 37 static if (T.sizeof == 1) 38 alias P = mixin(T.stringof~"16"); 39 else static if (T.sizeof == 2) 40 alias P = mixin(T.stringof~"8"); 41 else static if (T.sizeof == 4) 42 alias P = mixin(T.stringof~"4"); 43 else static if (T.sizeof == 8) 44 alias P = mixin(T.stringof~"2"); 45 46 this(A)(A ahs) 47 { 48 this = ahs; 49 } 50 51 auto opAssign(A)(A ahs) 52 { 53 foreach (i, u; ahs) 54 data[i] = cast(T)u; 55 return this; 56 } 57 58 auto opBinary(string op, R)(const R rhs) const 59 { 60 static if (is256) 61 { 62 mixin("Vector!T vec = this; 63 (cast(P*)&vec)[0] "~op~"= cast(T)rhs; 64 (cast(P*)&vec)[1] "~op~"= cast(T)rhs; 65 return vec;"); 66 } 67 else 68 { 69 mixin("Vector!T vec = this; 70 (cast(P*)&vec)[0] "~op~"= cast(T)rhs; 71 return vec;"); 72 } 73 } 74 75 auto opBinary(string op, R)(const R rhs) const shared 76 { 77 static if (is256) 78 { 79 mixin("Vector!T vec = this; 80 (cast(P*)&vec)[0] "~op~"= cast(T)rhs; 81 (cast(P*)&vec)[1] "~op~"= cast(T)rhs; 82 return vec;"); 83 } 84 else 85 { 86 mixin("Vector!T vec = this; 87 (cast(P*)&vec)[0] "~op~"= cast(T)rhs; 88 return vec;"); 89 } 90 } 91 92 auto opBinaryRight(string op, L)(const L lhs) const 93 { 94 static if (is256) 95 { 96 mixin("Vector!T vec = this; 97 cast(T)lhs "~op~"= (cast(P*)&vec)[0]; 98 cast(T)lhs "~op~"= (cast(P*)&vec)[1]; 99 return vec;"); 100 } 101 else 102 { 103 mixin("Vector!T vec = this; 104 cast(T)lhs "~op~"= (cast(P*)&vec)[0]; 105 return vec;"); 106 } 107 } 108 109 auto opBinaryRight(string op, L)(const L lhs) const shared 110 { 111 static if (is256) 112 { 113 mixin("Vector!T vec = this; 114 cast(T)lhs "~op~"= (cast(P*)&vec)[0]; 115 cast(T)lhs "~op~"= (cast(P*)&vec)[1]; 116 return vec;"); 117 } 118 else 119 { 120 mixin("Vector!T vec = this; 121 cast(T)lhs "~op~"= (cast(P*)&vec)[0]; 122 return vec;"); 123 } 124 } 125 126 auto opOpAssign(string op, A)(A ahs) 127 { 128 static if (is256) 129 { 130 mixin("(cast(P*)&this)[0] "~op~"= cast(T)ahs; 131 (cast(P*)&this)[1] "~op~"= (cast(P*)&this)[1];"); 132 } 133 else 134 { 135 mixin("(cast(P*)&this)[0] "~op~"= cast(T)ahs;"); 136 } 137 return this; 138 } 139 140 auto opOpAssign(string op, A)(A ahs) shared 141 { 142 static if (is256) 143 { 144 mixin("(cast(P*)&this)[0] "~op~"= cast(T)ahs; 145 (cast(P*)&this)[1] "~op~"= (cast(P*)&this)[1];"); 146 } 147 else 148 { 149 mixin("(cast(P*)&this)[0] "~op~"= cast(T)ahs;"); 150 } 151 return this; 152 } 153 154 auto opEquals(A)(A ahs) const 155 { 156 return (*cast(T*)&data) == ahs; 157 } 158 159 auto opEquals(A)(A ahs) const shared 160 { 161 return (*cast(T*)&data) == ahs; 162 } 163 164 size_t opDollar() const 165 { 166 return length; 167 } 168 169 size_t opDollar() const shared 170 { 171 return length; 172 } 173 174 string toString() const 175 { 176 return (*cast(T*)&data).to!string; 177 } 178 179 string toString() const shared 180 { 181 return (*cast(T*)&data).to!string; 182 } 183 }