1 /*******************************************************************************
2  * 
3  * Helper functions that serve general purposes.
4  * 
5  * Authors:
6  *   $(LINK2 mailto:Marco.Leise@gmx.de, Marco Leise)
7  * 
8  * Copyright:
9  *   © 2015 $(LINK2 mailto:Marco.Leise@gmx.de, Marco Leise)
10  * 
11  * License:
12  *   $(LINK2 http://www.gnu.org/licenses/gpl-3.0, GNU General Public License 3.0)
13  * 
14  **************************************/
15 module fast.helpers;
16 
17 import std.traits;
18 
19 
20 /+
21  ╔══════════════════════════════════════════════════════════════════════════════
22  ║ ⚑ Meta programming
23  ╚══════════════════════════════════════════════════════════════════════════════
24  +/
25 
26 version (Posix)
27 	enum isPosix = true;
28 else
29 	enum isPosix = false;
30 
31 version (X86_64) {
32 	enum isAMD64 = true;
33 	enum isX86   = false;
34 } else version (X86) {
35 	enum isAMD64 = false;
36 	enum isX86   = true;
37 }
38 
39 version (LDC) {
40 	enum isLDC = true;
41 	enum isGDC = false;
42 	enum isDMD = false;
43 } else version (GNU) {
44 	enum isLDC = false;
45 	enum isGDC = true;
46 	enum isDMD = false;
47 } else version (DigitalMars) {
48 	enum isLDC = false;
49 	enum isGDC = false;
50 	enum isDMD = true;
51 }
52 
53 
54 static if (__VERSION__ < 2067)
55 {
56 	import std.typetuple;
57 
58 	//Required for FieldNameTuple
59 	private enum NameOf(alias T) = T.stringof;
60 
61 	/**
62 	 * Get as an expression tuple the names of the fields of a struct, class, or
63 	 * union. This consists of the fields that take up memory space, excluding the
64 	 * hidden fields like the virtual function table pointer or a context pointer
65 	 * for nested types. If $(D T) isn't a struct, class, or union returns an
66 	 * expression tuple with an empty string.
67 	 */
68 	template FieldNameTuple(T)
69 	{
70 		static if (is(T == struct) || is(T == union))
71 			alias FieldNameTuple = staticMap!(NameOf, T.tupleof[0 .. $ - isNested!T]);
72 		else static if (is(T == class))
73 			alias FieldNameTuple = staticMap!(NameOf, T.tupleof);
74 		else
75 			alias FieldNameTuple = TypeTuple!"";
76 	}
77 }
78 
79 
80 /**
81  * For any integral type, returns the unsigned type of the same bit-width.
82  */
83 template UnsignedOf(I) if (isIntegral!I)
84 {
85 	static if (isUnsigned!I)
86 		alias UnsignedOf = I;
87 	else static if (is(I == long))
88 		alias UnsignedOf = ulong;
89 	else static if (is(I == int))
90 		alias UnsignedOf = uint;
91 	else static if (is(I == short))
92 		alias UnsignedOf = ushort;
93 	else static if (is(I == byte))
94 		alias UnsignedOf = ubyte;
95 	else static assert (0, "Not implemented");
96 }
97 
98 
99 version (DigitalMars)
100 {
101 	enum noinline;
102 	enum forceinline;
103 	enum sse4;
104 }
105 else version (GNU)
106 {
107 	import gcc.attribute;
108 	enum noinline    = gcc.attribute.attribute("noinline");
109 	enum forceinline = gcc.attribute.attribute("forceinline");
110 	enum sse4        = gcc.attribute.attribute("target", "sse4");
111 }
112 else version (LDC)
113 {
114 	import ldc.attribute;
115 	enum noinline    = ldc.attribute.attribute("noinline");
116 	enum forceinline = ldc.attribute.attribute("alwaysinline");
117 	enum sse4;
118 }
119 
120 
121 version (X86_64)
122 	enum hasSSE2 = true;
123 else
124 	enum hasSSE2 = false;
125 
126 
127 version (assert)
128 	enum isRelease = false;
129 else
130 	enum isRelease = true;
131 
132 
133 /**
134  * Generates a mixin string for repeating code. It can be used to unroll variadic arguments.
135  * A format string is instantiated a certain number times with an incrementing parameter.
136  * The results are then concatenated using an optional joiner.
137  *
138  * Params:
139  *   length = Number of elements you want to join. It is passed into format() as an incrementing number from [0 .. count$(RPAREN).
140  *   fmt = The format string to apply on each instanciation. Use %1d$ to refer to the current index multiple times when necessary.
141  *   joiner = Optional string that will be placed between instances. It could be a space or an arithmetic operation.
142  *
143  * Returns:
144  *   The combined elements as a mixin string.
145  *
146  * See_Also:
147  *   $(LINK2 http://forum.dlang.org/thread/vqfvihyezbmwcjkmpzin@forum.dlang.org, A simple way to do compile time loop unrolling)
148  */
149 enum ctfeJoin(size_t length)(in string fmt, in string joiner = null)
150 {
151 	import std.range : iota;
152 	import std.string : format;
153 	import std.algorithm : map;
154 	
155 	// BUG: Cannot use, join(), as it "cannot access the nested function 'ctfeJoin'".
156 	string result;
157 	foreach (inst; map!(i => format(fmt, i))(iota(length))) {
158 		if (result && joiner) result ~= joiner;
159 		result ~= inst;
160 	}
161 	return result;
162 }
163 
164 
165 enum getUDA(alias sym, T)()
166 {
167 	foreach (uda; __traits(getAttributes, sym))
168 		static if (is(typeof(uda) == T))
169 			return uda;
170 	return T.init;
171 }
172 
173 
174 /+
175  ╔══════════════════════════════════════════════════════════════════════════════
176  ║ ⚑ Bit operations
177  ╚══════════════════════════════════════════════════════════════════════════════
178  +/
179 
180 /*******************************************************************************
181  * 
182  * Count leading zeroes.
183  *
184  * Params:
185  *   u = the unsigned value to scan
186  *
187  * Returns:
188  *   The number of leading zero bits before the first one bit. If `u` is `0`,
189  *   the result is undefined.
190  *
191  **************************************/
192 version (DigitalMars)
193 {
194 	pragma(inline, true) @safe @nogc pure nothrow
195 	ubyte clz(U)(U u) if (is(U == uint) || is(U == ulong))
196 	{
197 		import core.bitop;
198 		enum max = 8 * U.sizeof - 1;
199 		static if (isX86 && is(U == ulong))
200 		{
201 			uint a = u >> 32;
202 			return cast(ubyte) (max - (a ? 32 + bsr(a) : bsr(cast(uint) u)));
203 		}
204 		else return cast(ubyte) (max - bsr(u));
205 	}
206 }
207 else version (GNU)
208 {
209 	import gcc.builtins;
210 	alias clz = __builtin_clz;
211 	version (X86_64)
212 	{
213 		@safe @nogc pure nothrow
214 		ubyte clz(ulong u)
215 		{
216 			return cast(ubyte) __builtin_clzl(u);
217 		}
218 	}
219 	else
220 	{
221 		@safe @nogc pure nothrow
222 		ubyte clz(ulong u)
223 		{
224 			uint a = u >> 32;
225 			return cast(ubyte) (a ? __builtin_clzl(a) : 32 + __builtin_clzl(cast(uint) u));
226 		}
227 	}
228 }
229 else version (LDC)
230 {
231 	@safe @nogc pure nothrow
232 	ubyte clz(U)(U u) if (is(U == uint) || is(U == ulong))
233 	{
234 		import ldc.intrinsics;
235 		return cast(ubyte) llvm_ctlz(u, false);
236 	}
237 }
238 
239 
240 version (X86)
241 {
242 	@safe @nogc pure nothrow
243 	int bsr(ulong u)
244 	{
245 		import core.bitop;
246 		uint a = u >> 32;
247 		return a ? 32 + core.bitop.bsr(a) : core.bitop.bsr(cast(uint) u);
248 	}
249 
250 
251 	@safe @nogc pure nothrow
252 	int bsf(ulong u)
253 	{
254 		import core.bitop;
255 		uint a = cast(uint) u;
256 		return a ? core.bitop.bsf(a) : 32 + core.bitop.bsf(u >> 32);
257 	}
258 }
259 
260 
261 /+
262  ╔══════════════════════════════════════════════════════════════════════════════
263  ║ ⚑ 
264  ╚══════════════════════════════════════════════════════════════════════════════
265  +/
266 
267 pure nothrow @nogc
268 {
269 	/**
270 	 * Aligns a pointer to the closest multiple of $(D pot) (a power of two),
271 	 * which is equal to or larger than $(D value).
272 	 */
273 	T* alignPtrNext(T)(scope T* ptr, in size_t pot)
274 	in { assert(pot > 0 && pot.isPowerOf2); }
275 	body { return cast(T*) ((cast(size_t) ptr + (pot - 1)) & -pot); }
276 	unittest { assert(alignPtrNext(cast(void*) 65, 64) == cast(void*) 128); }
277 }
278 
279 
280 @nogc @safe pure nothrow
281 {
282 	/// Returns whether the (positive) argument is an integral power of two.
283 	@property bool isPowerOf2(in size_t n)
284 	in { assert(n > 0); }
285 	body { return (n & n - 1) == 0; }
286 
287 	version (LDC) {
288 		import core.simd;
289 		pragma(LDC_intrinsic, "llvm.x86.sse2.pmovmskb.128")
290 			uint moveMask(ubyte16);
291 	} else version (GNU) {
292 		import gcc.builtins;
293 		alias moveMask = __builtin_ia32_pmovmskb128;
294 	}
295 	
296 	template SIMDFromScalar(V, alias scalar)
297 	{
298 		// This wrapper is needed for optimal performance with LDC and
299 		// doesn't hurt GDC's inlining.
300 		V SIMDFromScalar() {
301 			enum V asVectorEnum = scalar;
302 			return asVectorEnum;
303 		}
304 	}
305 
306 
307 	template SIMDFromString(string str) if (str.length <= 16)
308 	{
309 		import core.simd, std.algorithm, std.range, std.string;
310 
311 		private enum data = chain(str.representation, 0.repeat(16 - str.length)).array;
312 
313 		static if (!isDMD)
314 			immutable ubyte16 SIMDFromString = data;
315 		else static if (isX86)
316 			align(16) static __gshared ubyte[16] SIMDFromString = data;
317 		else
318 			static __gshared ubyte16 SIMDFromString = data;
319 	}
320 
321 
322 	version (unittest) void main() {}
323 }