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 }