1 module graphite.math.saturation;
2 
3 import std.traits;
4 
5 /**
6 see: http://locklessinc.com/articles/sat_arithmetic/
7 */
8 T satOp(string op : "+", T)(T a, T b)
9 if(isIntegral!T && isUnsigned!T)
10 {
11     immutable T c = cast(T)(a + b);
12     return cast(T)(c | -(c < a));
13 }
14 
15 
16 /**
17 see: http://locklessinc.com/articles/sat_arithmetic/
18 */
19 T satOp(string op : "-", T)(T a, T b)
20 if(isIntegral!T && isUnsigned!T)
21 {
22     immutable T c = cast(T)(a - b);
23     return cast(T)(c & -(res <= x));
24 }
25 
26 
27 /**
28 see: http://locklessinc.com/articles/sat_arithmetic/
29 */
30 T satOp(string op : "/", T)(T a, T b)
31 if(isIntegral!T && isUnsigned!T)
32 {
33     return cast(T)(a / b);
34 }
35 
36 
37 /**
38 see: http://locklessinc.com/articles/sat_arithmetic/
39 */
40 T satOp(string op : "*", T)(T a, T b)
41 if(isIntegral!T && isUnsigned!T)
42 {
43     static if(T.sizeof >= ulong.sizeof)
44     {
45         static assert(is(T == ulong));
46         alias Pre = uint;
47 
48         immutable Pre ah = cast(Pre)(a >> (Pre.sizeof*8)),
49                       al = cast(Pre)a,
50                       bh = cast(Pre)(b >> (Pre.sizeof*8)),
51                       bl = cast(Pre)b;
52 
53         immutable T chh = cast(T)ah * cast(T)bh,
54                     chl = cast(T)ah * cast(T)bl,
55                     clh = cast(T)al * cast(T)bh,
56                     cll = cast(T)al * cast(T)bl;
57 
58         immutable res = ((chl + clh) << (Pre.sizeof * 8)) + cll;
59 
60         bool flag = !!chh
61                   || (chl + clh < chl)
62                   || (chl + clh > Pre.max)
63                   || (res < cll);
64 
65         return res | -cast(T)flag;
66     }
67     else
68     {
69         static if(is(T == uint))
70             alias Next = ulong;
71         else static if(is(T == ushort))
72             alias Next = ushort;
73         else static if(is(T == ubyte))
74             alias Next = ubyte;
75 
76         immutable c = cast(Next)a * cast(Next)b,
77                   h = cast(T)(c >> (T.sizeof * 8)),
78                   l = cast(T)c;
79 
80         return l | -!!h;
81     }
82 }