xref: /netbsd-src/external/gpl3/gcc/dist/libphobos/src/std/int128.d (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1 // Written in the D programming language
2 /**
3  * Implements a signed 128 bit integer type.
4  *
5     Author:     Walter Bright
6     Copyright:  Copyright (c) 2022, D Language Foundation
7     License:    $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0)
8     Source:     $(PHOBOSSRC std/int128.d)
9  */
10 module std.int128;
11 
12 private import core.int128;
13 
14 
15 /***********************************
16  * 128 bit signed integer type.
17  */
18 
19 public struct Int128
20 {
21   @safe pure nothrow @nogc:
22 
23     Cent data;          /// core.int128.Cent
24 
25     /****************
26      * Construct an `Int128` from a `long` value.
27      * The upper 64 bits are formed by sign extension.
28      * Params:
29      *  lo = signed lower 64 bits
30      */
thisInt12831     this(long lo)
32     {
33         data.lo = lo;
34         data.hi = lo < 0 ? ~0L : 0;
35     }
36 
37     /****************
38      * Construct an `Int128` from a `ulong` value.
39      * The upper 64 bits are set to zero.
40      * Params:
41      *  lo = unsigned lower 64 bits
42      */
thisInt12843     this(ulong lo)
44     {
45         data.lo = lo;
46         data.hi = 0;
47     }
48 
49     /****************
50      * Construct an `Int128` from a `long` value.
51      * Params:
52      *  hi = upper 64 bits
53      *  lo = lower 64 bits
54      */
thisInt12855     this(long hi, long lo)
56     {
57         data.hi = hi;
58         data.lo = lo;
59     }
60 
61     /********************
62      * Construct an `Int128` from a `Cent`.
63      * Params:
64      *  data = Cent data
65      */
thisInt12866     this(Cent data)
67     {
68         this.data = data;
69     }
70 
71     /********************
72      * Returns: hash value for Int128
73      */
toHashInt12874     size_t toHash() const
75     {
76         return cast(size_t)((data.lo & 0xFFFF_FFFF) + (data.hi & 0xFFFF_FFFF) + (data.lo >> 32) + (data.hi >> 32));
77     }
78 
79     /************************
80      * Compare for equality
81      * Params: lo = signed value to compare with
82      * Returns: true if Int128 equals value
83      */
opEqualsInt12884     bool opEquals(long lo) const
85     {
86         return data.lo == lo && data.hi == (lo >> 63);
87     }
88 
89     /************************
90      * Compare for equality
91      * Params: lo = unsigned value to compare with
92      * Returns: true if Int128 equals value
93      */
opEqualsInt12894     bool opEquals(ulong lo) const
95     {
96         return data.hi == 0 && data.lo == lo;
97     }
98 
99     /************************
100      * Compare for equality
101      * Params: op2 = value to compare with
102      * Returns: true if Int128 equals value
103      */
opEqualsInt128104     bool opEquals(Int128 op2) const
105     {
106         return data.hi == op2.data.hi && data.lo == op2.data.lo;
107     }
108 
109     /** Support unary arithmentic operator +
110      * Params: op = "+"
111      * Returns: lvalue of result
112      */
113     Int128 opUnary(string op)() const
114         if (op == "+")
115     {
116         return this;
117     }
118 
119     /** Support unary arithmentic operator - ~
120      * Params: op = "-", "~"
121      * Returns: lvalue of result
122      */
123     Int128 opUnary(string op)() const
124         if (op == "-" || op == "~")
125     {
126         static if (op == "-")
127             return Int128(neg(this.data));
128         else static if (op == "~")
129             return Int128(com(this.data));
130     }
131 
132     /** Support unary arithmentic operator ++ --
133      * Params: op = "++", "--"
134      * Returns: lvalue of result
135      */
136     Int128 opUnary(string op)()
137         if (op == "++" || op == "--")
138     {
139         static if (op == "++")
140             this.data = inc(this.data);
141         else static if (op == "--")
142             this.data = dec(this.data);
143         else
144             static assert(0, op);
145         return this;
146     }
147 
148     /** Support casting to a bool
149      * Params: T = bool
150      * Returns: boolean result
151      */
152     bool opCast(T : bool)() const
153     {
154         return tst(this.data);
155     }
156 
157     /** Support binary arithmetic operators + - * / % & | ^ << >> >>>
158      * Params:
159      *   op = one of the arithmetic binary operators
160      *   op2 = second operand
161      * Returns: value after the operation is applied
162      */
163     Int128 opBinary(string op)(Int128 op2) const
164         if (op == "+" || op == "-" ||
165             op == "*" || op == "/" || op == "%" ||
166             op == "&" || op == "|" || op == "^")
167     {
168         static if (op == "+")
169             return Int128(add(this.data, op2.data));
170         else static if (op == "-")
171             return Int128(sub(this.data, op2.data));
172         else static if (op == "*")
173             return Int128(mul(this.data, op2.data));
174         else static if (op == "/")
175             return Int128(div(this.data, op2.data));
176         else static if (op == "%")
177         {
178             Cent modulus;
179             divmod(this.data, op2.data, modulus);
180             return Int128(modulus);
181         }
182         else static if (op == "&")
183             return Int128(and(this.data, op2.data));
184         else static if (op == "|")
185             return Int128(or(this.data, op2.data));
186         else static if (op == "^")
187             return Int128(xor(this.data, op2.data));
188         else
189             static assert(0, "wrong op value");
190     }
191 
192     /// ditto
193     Int128 opBinary(string op)(long op2) const
194         if (op == "+" || op == "-" ||
195             op == "*" || op == "/" || op == "%" ||
196             op == "&" || op == "|" || op == "^")
197     {
198         return mixin("this " ~ op ~ " Int128(0, op2)");
199     }
200 
201     /// ditto
202     Int128 opBinaryRight(string op)(long op2) const
203         if (op == "+" || op == "-" ||
204             op == "*" || op == "/" || op == "%" ||
205             op == "&" || op == "|" || op == "^")
206     {
207         mixin("return Int128(0, op2) " ~ op ~ " this;");
208     }
209 
210     /// ditto
211     Int128 opBinary(string op)(long op2) const
212         if (op == "<<")
213     {
214         return Int128(shl(this.data, cast(uint) op2));
215     }
216 
217     /// ditto
218     Int128 opBinary(string op)(long op2) const
219         if (op == ">>")
220     {
221         return Int128(sar(this.data, cast(uint) op2));
222     }
223 
224     /// ditto
225     Int128 opBinary(string op)(long op2) const
226         if (op == ">>>")
227     {
228         return Int128(shr(this.data, cast(uint) op2));
229     }
230 
231     /** arithmetic assignment operators += -= *= /= %= &= |= ^= <<= >>= >>>=
232      * Params: op = one of +, -, etc.
233      *   op2 = second operand
234      * Returns: lvalue of updated left operand
235      */
236     ref Int128 opOpAssign(string op)(Int128 op2)
237         if (op == "+" || op == "-" ||
238             op == "*" || op == "/" || op == "%" ||
239             op == "&" || op == "|" || op == "^" ||
240             op == "<<" || op == ">>" || op == ">>>")
241     {
242         mixin("this = this " ~ op ~ " op2;");
243         return this;
244     }
245 
246     /// ditto
247     ref Int128 opOpAssign(string op)(long op2)
248         if (op == "+" || op == "-" ||
249             op == "*" || op == "/" || op == "%" ||
250             op == "&" || op == "|" || op == "^" ||
251             op == "<<" || op == ">>" || op == ">>>")
252     {
253         mixin("this = this " ~ op ~ " op2;");
254         return this;
255     }
256 
257     /** support signed arithmentic comparison operators < <= > >=
258      * Params: op2 = right hand operand
259      * Returns: -1 for less than, 0 for equals, 1 for greater than
260      */
opCmpInt128261     int opCmp(Int128 op2) const
262     {
263         return this == op2 ? 0 : gt(this.data, op2.data) * 2 - 1;
264     }
265 
266     /** support signed arithmentic comparison operators < <= > >=
267      * Params: op2 = right hand operand
268      * Returns: -1 for less than, 0 for equals, 1 for greater than
269      */
opCmpInt128270     int opCmp(long op2) const
271     {
272         return opCmp(Int128(0, op2));
273     }
274 
275     enum min = Int128(long.min, 0);             /// minimum value
276     enum max = Int128(long.max, ulong.max);     /// maximum value
277 }
278 
279 /********************************************* Tests ************************************/
280 
version(unittest)281 version (unittest)
282 {
283 import core.stdc.stdio;
284 
285 @trusted void print(Int128 c)
286 {
287     printf("%lld, %lld\n", c.data.hi, c.data.lo);
288 }
289 
290 @trusted void printx(Int128 c)
291 {
292     printf("%llx, %llx\n", c.data.hi, c.data.lo);
293 }
294 }
295 
296 /// Int128 tests
297 @safe pure nothrow @nogc
298 unittest
299 {
300     Int128 c = Int128(5, 6);
301     assert(c == c);
302     assert(c == +c);
303     assert(c == - -c);
304     assert(~c == Int128(~5, ~6));
305     ++c;
306     assert(c == Int128(5, 7));
307     assert(--c == Int128(5, 6));
308     assert(!!c);
309     assert(!Int128());
310 
311     assert(c + Int128(10, 20) == Int128(15, 26));
312     assert(c - Int128(1, 2)   == Int128(4, 4));
313     assert(c * Int128(100, 2) == Int128(610, 12));
314     assert(c / Int128(3, 2)   == Int128(0, 1));
315     assert(c % Int128(3, 2)   == Int128(2, 4));
316     assert((c & Int128(3, 2)) == Int128(1, 2));
317     assert((c | Int128(3, 2)) == Int128(7, 6));
318     assert((c ^ Int128(3, 2)) == Int128(6, 4));
319 
320     assert(c + 15   == Int128(5, 21));
321     assert(c - 15   == Int128(4, -9));
322     assert(c * 15   == Int128(75, 90));
323     assert(c / 15   == Int128(0, 6148914691236517205));
324     assert(c % 15   == Int128(0, 11));
325     assert((c & 15) == Int128(0, 6));
326     assert((c | 15) == Int128(5, 15));
327     assert((c ^ 15) == Int128(5, 9));
328 
329     assert(15 + c   == Int128(5, 21));
330     assert(15 - c   == Int128(-5, 9));
331     assert(15 * c   == Int128(75, 90));
332     assert(15 / c   == Int128(0, 0));
333     assert(15 % c   == Int128(0, 15));
334     assert((15 & c) == Int128(0, 6));
335     assert((15 | c) == Int128(5, 15));
336     assert((15 ^ c) == Int128(5, 9));
337 
338     assert(c << 1 == Int128(10, 12));
339     assert(-c >> 1 == Int128(-3, 9223372036854775805));
340     assert(-c >>> 1 == Int128(9223372036854775805, 9223372036854775805));
341 
342     assert((c += 1) == Int128(5, 7));
343     assert((c -= 1) == Int128(5, 6));
344     assert((c += Int128(0, 1)) == Int128(5, 7));
345     assert((c -= Int128(0, 1)) == Int128(5, 6));
346     assert((c *= 2) == Int128(10, 12));
347     assert((c /= 2) == Int128(5, 6));
348     assert((c %= 2) == Int128());
349     c += Int128(5, 6);
350     assert((c *= Int128(10, 20)) == Int128(160, 120));
351     assert((c /= Int128(10, 20)) == Int128(0, 15));
352     c += Int128(72, 0);
353     assert((c %= Int128(10, 20)) == Int128(1, -125));
354     assert((c &= Int128(3, 20)) == Int128(1, 0));
355     assert((c |= Int128(8, 2)) == Int128(9, 2));
356     assert((c ^= Int128(8, 2)) == Int128(1, 0));
357     c |= Int128(10, 5);
358     assert((c <<= 1) == Int128(11 * 2, 5 * 2));
359     assert((c >>>= 1) == Int128(11, 5));
360     c = Int128(long.min, long.min);
361     assert((c >>= 1) == Int128(long.min >> 1, cast(ulong) long.min >> 1));
362 
363     assert(-Int128.min == Int128.min);
364     assert(Int128.max + 1 == Int128.min);
365 
366     c = Int128(5, 6);
367     assert(c < Int128(6, 5));
368     assert(c > 10);
369 
370     c = Int128(-1UL);
371     assert(c == -1UL);
372     c = Int128(-1L);
373     assert(c == -1L);
374 }
375