1 /** Count leading zeros.
2  */
3 module nxt.clz;
4 
5 import std.traits : Unqual;
6 
7 /*******************************************************************************
8  *
9  * Count leading zeroes.
10  *
11  * Params:
12  *   u = the unsigned value to scan
13  *
14  * Returns:
15  *   The number of leading zero bits before the first one bit. If `u` is `0`,
16  *   the result is undefined.
17  *
18  **************************************/
19 version (DigitalMars) {
20 	pragma(inline, true)
21 	U clz(U)(U u) @safe @nogc pure nothrow
22 	if (is(Unqual!U == uint) ||
23 		is(Unqual!U == size_t))
24 		=> (cast(U)(8 * U.sizeof - 1)) - bsr(u);
25 
26 	static if (isX86) {
27 		pragma(inline, true)
28 		uint clz(U)(U u) @safe @nogc pure nothrow
29 		if (is(Unqual!U == ulong)) {
30 			uint hi = u >> 32;
31 			return hi ? 31 - bsr(hi) : 63 - bsr(cast(uint)u);
32 		}
33 	}
34 }
35 else version (GNU) {
36 	import gcc.builtins;
37 	alias clz = __builtin_clz;
38 	static if (isX86) {
39 		@safe @nogc pure nothrow uint
40 		clz(ulong u) {
41 			uint hi = u >> 32;
42 			return hi ? __builtin_clz(hi) : 32 + __builtin_clz(cast(uint)u);
43 		}
44 	}
45 	else alias clz = __builtin_clzl;
46 }
47 else version (LDC) {
48 	import ldc.intrinsics;
49 	pragma(inline, true)
50 	U clz(U)(U u) @safe @nogc pure nothrow
51 	if (is(Unqual!U == uint) || is(Unqual!U == size_t))
52 		=> llvm_ctlz(u, false);
53 
54 	static if (isX86) {
55 		pragma(inline, true)
56 		uint clz(U)(U u) @safe @nogc pure nothrow
57 		if (is(Unqual!U == ulong))
58 			=> cast(uint)llvm_ctlz(u, false);
59 	}
60 }
61 
62 version (X86_64) {
63 	private enum isAMD64 = true;
64 	private enum isX86   = false;
65 }
66 else version (X86) {
67 	private enum isAMD64 = false;
68 	private enum isX86   = true;
69 }
70 
71 version (X86_64)
72 	private enum hasSSE2 = true;
73 else
74 	private enum hasSSE2 = false;
75 
76 static import core.bitop;
77 
78 alias bsr = core.bitop.bsr;
79 alias bsf = core.bitop.bsf;
80 
81 pure nothrow @safe @nogc unittest {
82 	assert(clz(uint(0x01234567)) == 7);
83 	assert(clz(ulong(0x0123456701234567)) == 7);
84 	assert(clz(ulong(0x0000000001234567)) == 7+32);
85 	assert(bsr(uint(0x01234567)) == 24);
86 	assert(bsr(ulong(0x0123456701234567)) == 24+32);
87 	assert(bsr(ulong(0x0000000001234567)) == 24);
88 	assert(bsf(uint(0x76543210)) == 4);
89 	assert(bsf(ulong(0x7654321076543210)) == 4);
90 	assert(bsf(ulong(0x7654321000000000)) == 4+32);
91 }