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