1 module libd.util.maths;
2 
3 import libd.meta.traits;
4 
5 T alignTo(alias Boundary, T)(T value) pure
6 {
7     static if(isPowerOfTwo(Boundary))
8         return (value + (Boundary * (value % Boundary > 0))) & ~(Boundary-1);
9     else static assert(false, "TODO");
10 }
11 ///
12 @("alignTo")
13 unittest
14 {
15     assert(alignTo!16(0) == 0);
16     assert(alignTo!16(16) == 16);
17     assert(alignTo!16(8) == 16);
18     assert(alignTo!16(31) == 32);
19 }
20 
21 bool isPowerOfTwo(T)(T value)
22 {
23     return (value != 0) && (value & (value - 1)) == 0;
24 }
25 ///
26 @("isPowerOfTwo")
27 unittest
28 {
29     assert(2.isPowerOfTwo);
30     assert(4.isPowerOfTwo);
31     assert(128.isPowerOfTwo);
32     assert(!3.isPowerOfTwo);
33 }
34 
35 UnsignedOf!NumT abs(NumT)(NumT value)
36 {
37     static if(__traits(isIntegral, NumT))
38         return cast(typeof(return))(value * ((value > 0) - (value < 0)));
39     else static assert(false, "Don't know how to abs type '"~NumT.stringof~"'");
40 }
41 ///
42 @("abs")
43 unittest
44 {
45     assert(0.abs == 0);
46     assert(1.abs == 1);
47     assert((-1).abs == 1);
48     assert((-128).abs!byte == 128);
49 }
50 
51 // https://stackoverflow.com/a/11398748
52 private const uint[32] tab32 = [
53      0,  9,  1, 10, 13, 21,  2, 29,
54     11, 14, 16, 18, 22, 25,  3, 30,
55      8, 12, 20, 28, 15, 17, 24,  7,
56     19, 27, 23,  6, 26,  5,  4, 31];
57 private uint log2_32 (uint value) @safe @nogc nothrow pure
58 {
59     value |= value >> 1;
60     value |= value >> 2;
61     value |= value >> 4;
62     value |= value >> 8;
63     value |= value >> 16;
64     return tab32[cast(uint)(value*0x07C4ACDD) >> 27];
65 }
66 private const uint[64] tab64 = [
67     63,  0, 58,  1, 59, 47, 53,  2,
68     60, 39, 48, 27, 54, 33, 42,  3,
69     61, 51, 37, 40, 49, 18, 28, 20,
70     55, 30, 34, 11, 43, 14, 22,  4,
71     62, 57, 46, 52, 38, 26, 32, 41,
72     50, 36, 17, 19, 29, 10, 13, 21,
73     56, 45, 25, 31, 35, 16,  9, 12,
74     44, 24, 15,  8, 23,  7,  6,  5];
75 private uint log2_64 (ulong value) @safe @nogc nothrow pure
76 {
77     value |= value >> 1;
78     value |= value >> 2;
79     value |= value >> 4;
80     value |= value >> 8;
81     value |= value >> 16;
82     value |= value >> 32;
83     return tab64[(cast(ulong)((value - (value >> 1))*0x07EDD5E59A4E28C2)) >> 58];
84 }
85 
86 uint log2(T)(const T value)
87 {
88     alias VT = typeof(value);
89     static if(is(VT == const int) || is(VT == const uint))
90         return log2_32(value);
91     else static if(is(VT == const long) || is(VT == const ulong))
92         return log2_64(value);
93     else
94         static assert(false, "Don't know how to log2 type: "~T.stringof);
95 }
96 
97 IntT ceilToInt(IntT)(double value)
98 {
99     const isNegative = value < 0;
100     const isWhole = value % 1 == 0;
101     return cast(IntT)value + (
102         (1 * (-1 * isNegative)) * !isWhole
103     );
104 }