1 /** 2 Compatibility shim to allow code written against the latest `core.bitop` 3 module to compile with older versions of D. 4 5 Copyright: Copyright Thomas Stuart Bockman 2015 6 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 7 Authors: Thomas Stuart Bockman 8 **/ 9 module future.bitop; 10 public import core.bitop; 11 12 static if (__VERSION__ < 2071) 13 { 14 @safe: pure: nothrow: @nogc: 15 16 private union Split64 17 { 18 ulong u64; 19 struct 20 { 21 version(LittleEndian) 22 { 23 uint lo; 24 uint hi; 25 } 26 else 27 { 28 uint hi; 29 uint lo; 30 } 31 } 32 } 33 private auto split64(ulong x) 34 { 35 if (__ctfe) 36 { 37 Split64 ret = void; 38 ret.lo = cast(uint)x; 39 ret.hi = cast(uint)(x >>> 32); 40 return ret; 41 } 42 else 43 return Split64(x); 44 } 45 46 int bsf(size_t v) 47 { 48 return core.bitop.bsf(v); 49 } 50 static if (size_t.sizeof == uint.sizeof) 51 { 52 int bsf(ulong v) pure 53 { 54 const sv = split64(v); 55 return (sv.lo == 0)? 56 bsf(sv.hi) + 32 : 57 bsf(sv.lo); 58 } 59 } 60 else 61 static assert(size_t.sizeof == ulong.sizeof); 62 63 int bsr(size_t v) 64 { 65 return core.bitop.bsr(v); 66 } 67 static if (size_t.sizeof == uint.sizeof) 68 { 69 int bsr(ulong v) 70 { 71 const sv = split64(v); 72 return (sv.hi == 0)? 73 bsr(sv.lo) : 74 bsr(sv.hi) + 32; 75 } 76 } else 77 static assert(size_t.sizeof == ulong.sizeof); 78 79 int popcnt(uint x) 80 { 81 // Select the fastest method depending on the compiler and CPU architecture 82 version(LDC) 83 { 84 return _popcnt(x); 85 } 86 else 87 { 88 version(DigitalMars) 89 { 90 static if (is(typeof(_popcnt(uint.max)))) 91 { 92 import core.cpuid; 93 if (!__ctfe && hasPopcnt) 94 return _popcnt(x); 95 } 96 } 97 98 return soft_popcnt!uint(x); 99 } 100 } 101 int popcnt(ulong x) 102 { 103 // Select the fastest method depending on the compiler and CPU architecture 104 version(LDC) 105 return _popcnt(x); 106 else 107 { 108 import core.cpuid; 109 110 static if (size_t.sizeof == uint.sizeof) 111 { 112 const sx = split64(x); 113 version(DigitalMars) 114 { 115 static if (is(typeof(_popcnt(uint.max)))) 116 { 117 if (!__ctfe && hasPopcnt) 118 return _popcnt(sx.lo) + _popcnt(sx.hi); 119 } 120 } 121 122 return soft_popcnt!uint(sx.lo) + soft_popcnt!uint(sx.hi); 123 } 124 else static if (size_t.sizeof == ulong.sizeof) 125 { 126 version(DigitalMars) 127 { 128 static if (is(typeof(_popcnt(ulong.max)))) 129 { 130 if (!__ctfe && hasPopcnt) 131 return _popcnt(x); 132 } 133 } 134 135 return soft_popcnt!ulong(x); 136 } else 137 static assert(false); 138 } 139 } 140 141 private int soft_popcnt(N)(N x) pure 142 if (is(N == uint) || is(N == ulong)) 143 { 144 // Avoid branches, and the potential for cache misses which 145 // could be incurred with a table lookup. 146 147 // We need to mask alternate bits to prevent the 148 // sum from overflowing. 149 // add neighbouring bits. Each bit is 0 or 1. 150 enum mask1 = cast(N) 0x5555_5555_5555_5555L; 151 x = x - ((x>>1) & mask1); 152 // now each two bits of x is a number 00,01 or 10. 153 // now add neighbouring pairs 154 enum mask2a = cast(N) 0xCCCC_CCCC_CCCC_CCCCL; 155 enum mask2b = cast(N) 0x3333_3333_3333_3333L; 156 x = ((x & mask2a)>>2) + (x & mask2b); 157 // now each nibble holds 0000-0100. Adding them won't 158 // overflow any more, so we don't need to mask any more 159 160 enum mask4 = cast(N) 0x0F0F_0F0F_0F0F_0F0FL; 161 x = (x + (x >> 4)) & mask4; 162 163 enum shiftbits = is(N == uint)? 24 : 56; 164 enum maskMul = cast(N) 0x0101_0101_0101_0101L; 165 x = (x * maskMul) >> shiftbits; 166 167 return cast(int) x; 168 } 169 }