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 {
21 	U clz(U)(U u) @safe @nogc pure nothrow
22     if (is(Unqual!U == uint) ||
23         is(Unqual!U == size_t))
24 	{
25 		pragma(inline, true);
26 		enum U max = 8 * U.sizeof - 1;
27 		return max - bsr(u);
28 	}
29 
30 	static if (isX86)
31 	{
32 		uint clz(U)(U u) @safe @nogc pure nothrow
33         if (is(Unqual!U == ulong))
34 		{
35 			pragma(inline, true);
36 			uint hi = u >> 32;
37 			return hi ? 31 - bsr(hi) : 63 - bsr(cast(uint)u);
38 		}
39 	}
40 }
41 else version (GNU)
42 {
43 	import gcc.builtins;
44 	alias clz = __builtin_clz;
45 	static if (isX86)
46 	{
47 		@safe @nogc pure nothrow uint
48 		clz(ulong u)
49 		{
50 			uint hi = u >> 32;
51 			return hi ? __builtin_clz(hi) : 32 + __builtin_clz(cast(uint)u);
52 		}
53 	}
54 	else alias clz = __builtin_clzl;
55 }
56 else version (LDC)
57 {
58 	U clz(U)(U u) @safe @nogc pure nothrow
59     if (is(Unqual!U == uint) || is(Unqual!U == size_t))
60 	{
61 		pragma(inline, true);
62 		import ldc.intrinsics;
63 		return llvm_ctlz(u, false);
64 	}
65 
66 	static if (isX86)
67 	{
68 		uint clz(U)(U u) @safe @nogc pure nothrow
69         if (is(Unqual!U == ulong))
70 		{
71 			pragma(inline, true);
72 			import ldc.intrinsics;
73 			return cast(uint)llvm_ctlz(u, false);
74 		}
75 	}
76 }
77 
78 version (X86_64)
79 {
80 	private enum isAMD64 = true;
81 	private enum isX86   = false;
82 }
83 else version (X86)
84 {
85 	private enum isAMD64 = false;
86 	private enum isX86   = true;
87 }
88 
89 version (X86_64)
90 	private enum hasSSE2 = true;
91 else
92 	private enum hasSSE2 = false;
93 
94 static import core.bitop;
95 
96 alias bsr = core.bitop.bsr;
97 alias bsf = core.bitop.bsf;
98 
99 @safe pure nothrow @nogc unittest
100 {
101 	assert(clz(uint(0x01234567)) == 7);
102 	assert(clz(ulong(0x0123456701234567)) == 7);
103 	assert(clz(ulong(0x0000000001234567)) == 7+32);
104 	assert(bsr(uint(0x01234567)) == 24);
105 	assert(bsr(ulong(0x0123456701234567)) == 24+32);
106 	assert(bsr(ulong(0x0000000001234567)) == 24);
107 	assert(bsf(uint(0x76543210)) == 4);
108 	assert(bsf(ulong(0x7654321076543210)) == 4);
109 	assert(bsf(ulong(0x7654321000000000)) == 4+32);
110 }
111