diff --git a/posix.mak b/posix.mak index af25eab005d..023e810b236 100644 --- a/posix.mak +++ b/posix.mak @@ -210,7 +210,7 @@ STD_PACKAGES = std $(addprefix std/,\ PACKAGE_std = array ascii base64 bigint bitmanip checkedint compiler complex concurrency \ conv csv demangle encoding exception file \ - functional getopt json mathspecial meta mmfile numeric \ + functional getopt int128 json mathspecial meta mmfile numeric \ outbuffer package parallelism path process random signals socket stdint \ stdio string sumtype system traits typecons \ uri utf uuid variant xml zip zlib diff --git a/std/int128.d b/std/int128.d new file mode 100644 index 00000000000..b2e93fa926c --- /dev/null +++ b/std/int128.d @@ -0,0 +1,279 @@ +// Written in the D programming language +/** + * Implements a signed 128 bit integer type. + * + Author: Walter Bright + Copyright: Copyright (c) 2022, D Language Foundation + License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0) + Source: $(PHOBOSSRC std/int128.d) + */ +module std.int128; + +private import core.int128; + + +/*********************************** + * 128 bit signed integer type. + */ + +public struct Int128 +{ + @safe pure nothrow @nogc: + + Cent data; + + /**************** + * Construct an `Int128` from a `long` value. + * The upper 64 bits are formed by sign extension. + * Params: + * lo = signed lower 64 bits + */ + this(long lo) + { + data.lo = lo; + data.hi = lo < 0 ? ~0L : 0; + } + + /**************** + * Construct an `Int128` from a `long` value. + * Params: + * hi = upper 64 bits + * lo = lower 64 bits + */ + this(long hi, long lo) + { + data.hi = hi; + data.lo = lo; + } + + this(Cent data) + { + this.data = data; + } + + bool opEquals(long lo) const + { + return data.hi == 0 && data.lo == lo; + } + + bool opEquals(Int128 op2) const + { + return data.hi == op2.data.hi && data.lo == op2.data.lo; + } + + // +Int128 + Int128 opUnary(string op)() const + if (op == "+") + { + return this; + } + + // -Int128 + Int128 opUnary(string op)() const + if (op == "-") + { + return Int128(neg(this.data)); + } + + // ~Int128 + Int128 opUnary(string op)() const + if (op == "~") + { + return Int128(com(this.data)); + } + + // cast(T)Int128 + bool opCast(T : bool)() const + { + return tst(this.data); + } + + // Int128 + Int128 + Int128 opBinary(string op)(Int128 op2) const + if (op == "+" || op == "-" || + op == "*" || op == "/" || op == "%" || + op == "&" || op == "|" || op == "^") + { + if (op == "+") + return Int128(add(this.data, op2.data)); + else if (op == "-") + return Int128(sub(this.data, op2.data)); + else if (op == "*") + return Int128(mul(this.data, op2.data)); + else if (op == "/") + return Int128(div(this.data, op2.data)); + else if (op == "%") + { + Cent modulus; + divmod(this.data, op2.data, modulus); + return Int128(modulus); + } + else if (op == "&") + return Int128(and(this.data, op2.data)); + else if (op == "|") + return Int128(or(this.data, op2.data)); + else if (op == "^") + return Int128(xor(this.data, op2.data)); + else + assert(0); + } + + // Int128 + long + Int128 opBinary(string op)(long lo) const + if (op == "+" || op == "-" || + op == "*" || op == "/" || op == "%" || + op == "&" || op == "|" || op == "^") + { + return mixin("this " ~ op ~ " Int128(0, lo)"); + } + + // long + Int128 + Int128 opBinaryRight(string op)(long lo) const + if (op == "+" || op == "-" || + op == "*" || op == "/" || op == "%" || + op == "&" || op == "|" || op == "^") + { + mixin("return Int128(0, lo) " ~ op ~ " this;"); + } + + // Int128 << uint + Int128 opBinary(string op)(long n) const + if (op == "<<") + { + return Int128(shl(this.data, cast(uint)n)); + } + + // Int128 >> uint + Int128 opBinary(string op)(long n) const + if (op == ">>") + { + return Int128(sar(this.data, cast(uint)n)); + } + + // Int128 >>> uint + Int128 opBinary(string op)(long n) const + if (op == ">>>") + { + return Int128(shr(this.data, cast(uint)n)); + } + + ref Int128 opOpAssign(string op)(Int128 op2) + if (op == "+" || op == "-" || + op == "*" || op == "/" || op == "%" || + op == "&" || op == "|" || op == "^" || + op == "<<" || op == ">>" || op == ">>>") + { + mixin("this = this " ~ op ~ " op2;"); + return this; + } + + ref Int128 opOpAssign(string op)(long op2) + if (op == "+" || op == "-" || + op == "*" || op == "/" || op == "%" || + op == "&" || op == "|" || op == "^" || + op == "<<" || op == ">>" || op == ">>>") + { + mixin("this = this " ~ op ~ " op2;"); + return this; + } + + int opCmp(Int128 op2) + { + return this == op2 ? 0 : gt(this.data, op2.data) * 2 - 1; + } + + int opCmp(long op2) + { + return opCmp(Int128(0, op2)); + } + + enum min = Int128(long.min, 0); /// minimum value + enum max = Int128(long.max, ulong.max); /// maximum value +} + +/********************************************* Tests ************************************/ + +version (unittest) +{ +import core.stdc.stdio; + +void print(Int128 c) +{ + printf("%lld, %lld\n", c.data.hi, c.data.lo); +} + +void printx(Int128 c) +{ + printf("%llx, %llx\n", c.data.hi, c.data.lo); +} +} + +unittest +{ + Int128 c = Int128(5, 6); + assert(c == c); + assert(c == +c); + assert(c == - -c); + assert(~c == Int128(~5, ~6)); + assert(!!c); + assert(!Int128()); + + assert(c + Int128(10, 20) == Int128(15, 26)); + assert(c - Int128(1, 2) == Int128(4, 4)); + assert(c * Int128(100, 2) == Int128(610, 12)); + assert(c / Int128(3, 2) == Int128(0, 1)); + assert(c % Int128(3, 2) == Int128(2, 4)); + assert((c & Int128(3, 2)) == Int128(1, 2)); + assert((c | Int128(3, 2)) == Int128(7, 6)); + assert((c ^ Int128(3, 2)) == Int128(6, 4)); + + assert(c + 15 == Int128(5, 21)); + assert(c - 15 == Int128(4, -9)); + assert(c * 15 == Int128(75, 90)); + assert(c / 15 == Int128(0, 6148914691236517205)); + assert(c % 15 == Int128(0, 11)); + assert((c & 15) == Int128(0, 6)); + assert((c | 15) == Int128(5, 15)); + assert((c ^ 15) == Int128(5, 9)); + + assert(15 + c == Int128(5, 21)); + assert(15 - c == Int128(-5, 9)); + assert(15 * c == Int128(75, 90)); + assert(15 / c == Int128(0, 0)); + assert(15 % c == Int128(0, 15)); + assert((15 & c) == Int128(0, 6)); + assert((15 | c) == Int128(5, 15)); + assert((15 ^ c) == Int128(5, 9)); + + assert(c << 1 == Int128(10, 12)); + assert(-c >> 1 == Int128(-3, 9223372036854775805)); + assert(-c >>> 1 == Int128(9223372036854775805, 9223372036854775805)); + + assert((c += 1) == Int128(5, 7)); + assert((c -= 1) == Int128(5, 6)); + assert((c += Int128(0, 1)) == Int128(5, 7)); + assert((c -= Int128(0, 1)) == Int128(5, 6)); + assert((c *= 2) == Int128(10, 12)); + assert((c /= 2) == Int128(5, 6)); + assert((c %= 2) == Int128()); + c += Int128(5, 6); + assert((c *= Int128(10, 20)) == Int128(160, 120)); + assert((c /= Int128(10, 20)) == Int128(0, 15)); + c += Int128(72, 0); + assert((c %= Int128(10, 20)) == Int128(1, -125)); + assert((c &= Int128(3, 20)) == Int128(1, 0)); + assert((c |= Int128(8, 2)) == Int128(9, 2)); + assert((c ^= Int128(8, 2)) == Int128(1, 0)); + c |= Int128(10, 5); + assert((c <<= 1) == Int128(11 * 2, 5 * 2)); + assert((c >>>= 1) == Int128(11, 5)); + c = Int128(long.min, long.min); + assert((c >>= 1) == Int128(long.min >> 1, cast(ulong)long.min >> 1)); + + assert(-Int128.min == Int128.min); + assert(Int128.max + 1 == Int128.min); + + c = Int128(5, 6); + assert(c < Int128(6, 5)); + assert(c > 10); +} diff --git a/win32.mak b/win32.mak index 810fe8dd796..e3840e60af4 100644 --- a/win32.mak +++ b/win32.mak @@ -139,6 +139,7 @@ SRC_STD_3a= \ std\concurrency.d SRC_STD_4= \ + std\int128.d \ std\uuid.d SRC_STD_6= \ @@ -457,6 +458,7 @@ cov : $(SRC_TO_COMPILE) $(LIB) $(DMD) -conf= -cov=ctfe -cov=89 $(UDFLAGS) -main -run std\utf.d $(DMD) -conf= -cov=ctfe -cov=93 $(UDFLAGS) -main -run std\csv.d $(DMD) -conf= -cov=ctfe -cov=95 $(UDFLAGS) -main -run std\complex.d + $(DMD) -conf= -cov=ctfe -cov=95 $(UDFLAGS) -main -run std\int128.d $(DMD) -conf= -cov=ctfe -cov=70 $(UDFLAGS) -main -run std\numeric.d $(DMD) -conf= -cov=ctfe -cov=94 $(UDFLAGS) -main -run std\bigint.d $(DMD) -conf= -cov=ctfe -cov=95 $(UDFLAGS) -main -run std\bitmanip.d diff --git a/win64.mak b/win64.mak index 041fb19c21a..694500b5991 100644 --- a/win64.mak +++ b/win64.mak @@ -145,6 +145,7 @@ SRC_STD_3d= \ std\typecons.d SRC_STD_4= \ + std\int128.d \ std\uuid.d SRC_STD_6a=std\variant.d