1 /**
2  * Number stuff
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <vladimir@thecybershadow.net>
12  */
13 
14 module ae.utils.math;
15 
16 typeof(Ta+Tb+Tc) bound(Ta, Tb, Tc)(Ta a, Tb b, Tc c) { return a<b?b:a>c?c:a; }
17 bool between(T)(T point, T a, T b) { return a <= point && point <= b; } /// Assumes points are sorted (was there a faster way?)
18 auto sqr(T)(T x) { return x*x; }
19 
20 void sort2(T)(ref T x, ref T y) { if (x > y) { T z=x; x=y; y=z; } }
21 
22 T itpl(T, U)(T low, T high, U r, U rLow, U rHigh)
23 {
24 	import std.traits : Signed;
25 	return cast(T)(low + (cast(Signed!T)high-cast(Signed!T)low) * (cast(Signed!U)r - cast(Signed!U)rLow) / (cast(Signed!U)rHigh - cast(Signed!U)rLow));
26 }
27 
28 byte sign(T)(T x) { return x<0 ? -1 : x>0 ? 1 : 0; }
29 
30 int compare(T)(T a, T b)
31 {
32 	return a<b ? -1 : a>b ? 1 : 0;
33 }
34 
35 auto op(string OP, T...)(T args)
36 {
37 	auto result = args[0];
38 	foreach (arg; args[1..$])
39 		mixin("result" ~ OP ~ "=arg;");
40 	return result;
41 }
42 
43 auto sum(T...)(T args) { return op!"+"(args); }
44 auto average(T...)(T args) { return sum(args) / args.length; }
45 
46 template unary(char op)
47 {
48 	T unary(T)(T value)
49 	{
50 		// Silence DMD 2.078.0 warning about integer promotion rules
51 		// https://dlang.org/changelog/2.078.0.html#fix16997
52 		static if ((op == '-' || op == '+' || op == '~') && is(T : int))
53 			alias CastT = int;
54 		else
55 			alias CastT = T;
56 		return mixin(`cast(T)` ~ op ~ `cast(CastT)value`);
57 	}
58 }
59 
60 /// Like the ~ operator, but without int-promotion.
61 alias flipBits = unary!'~';
62 
63 unittest
64 {
65 	ubyte b = 0x80;
66 	auto b2 = b.flipBits;
67 	assert(b2 == 0x7F);
68 	static assert(is(typeof(b2) == ubyte));
69 }
70 
71 T swapBytes(T)(T b)
72 {
73 	import core.bitop : bswap;
74 	static if (b.sizeof == 1)
75 		return b;
76 	else
77 	static if (b.sizeof == 2)
78 		return cast(T)((b >> 8) | (b << 8));
79 	else
80 	static if (b.sizeof == 4)
81 		return bswap(b);
82 	else
83 		static assert(false, "Don't know how to bswap " ~ T.stringof);
84 }
85 
86 bool isPowerOfTwo(T)(T x) { return (x & (x-1)) == 0; }
87 T roundUpToPowerOfTwo(T)(T x) { return nextPowerOfTwo(x-1); }
88 T nextPowerOfTwo(T)(T x)
89 {
90 	x |= x >>  1;
91 	x |= x >>  2;
92 	x |= x >>  4;
93 	static if (T.sizeof > 1)
94 		x |= x >>  8;
95 	static if (T.sizeof > 2)
96 		x |= x >> 16;
97 	static if (T.sizeof > 4)
98 		x |= x >> 32;
99 	return x + 1;
100 }
101 
102 /// Integer log2.
103 ubyte ilog2(T)(T n)
104 {
105 	ubyte result = 0;
106 	while (n >>= 1)
107 		result++;
108 	return result;
109 }
110 
111 unittest
112 {
113 	assert(ilog2(0) == 0);
114 	assert(ilog2(1) == 0);
115 	assert(ilog2(2) == 1);
116 	assert(ilog2(3) == 1);
117 	assert(ilog2(4) == 2);
118 }
119 
120 /// Returns the number of bits needed to
121 /// store a number up to n (inclusive).
122 ubyte bitsFor(T)(T n)
123 {
124 	return cast(ubyte)(ilog2(n)+1);
125 }
126 
127 unittest
128 {
129 	assert(bitsFor( int.max) == 31);
130 	assert(bitsFor(uint.max) == 32);
131 }
132 
133 /// Get the smallest built-in unsigned integer type
134 /// that can store this many bits of data.
135 template TypeForBits(uint bits)
136 {
137 	static if (bits <= 8)
138 		alias TypeForBits = ubyte;
139 	else
140 	static if (bits <= 16)
141 		alias TypeForBits = ushort;
142 	else
143 	static if (bits <= 32)
144 		alias TypeForBits = uint;
145 	else
146 	static if (bits <= 64)
147 		alias TypeForBits = ulong;
148 	else
149 		static assert(false, "No integer type big enough for " ~ bits.stringof ~ " bits");
150 }
151 
152 static assert(is(TypeForBits!7 == ubyte));
153 static assert(is(TypeForBits!8 == ubyte));
154 static assert(is(TypeForBits!9 == ushort));
155 static assert(is(TypeForBits!64 == ulong));
156 static assert(!is(TypeForBits!65));