summaryrefslogtreecommitdiff
path: root/libphobos/src/std/int128.d
diff options
context:
space:
mode:
Diffstat (limited to 'libphobos/src/std/int128.d')
-rw-r--r--libphobos/src/std/int128.d374
1 files changed, 374 insertions, 0 deletions
diff --git a/libphobos/src/std/int128.d b/libphobos/src/std/int128.d
new file mode 100644
index 00000000000..fc992f82422
--- /dev/null
+++ b/libphobos/src/std/int128.d
@@ -0,0 +1,374 @@
+// 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; /// core.int128.Cent
+
+ /****************
+ * 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 `ulong` value.
+ * The upper 64 bits are set to zero.
+ * Params:
+ * lo = unsigned lower 64 bits
+ */
+ this(ulong lo)
+ {
+ data.lo = lo;
+ data.hi = 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;
+ }
+
+ /********************
+ * Construct an `Int128` from a `Cent`.
+ * Params:
+ * data = Cent data
+ */
+ this(Cent data)
+ {
+ this.data = data;
+ }
+
+ /********************
+ * Returns: hash value for Int128
+ */
+ size_t toHash() const
+ {
+ return cast(size_t)((data.lo & 0xFFFF_FFFF) + (data.hi & 0xFFFF_FFFF) + (data.lo >> 32) + (data.hi >> 32));
+ }
+
+ /************************
+ * Compare for equality
+ * Params: lo = signed value to compare with
+ * Returns: true if Int128 equals value
+ */
+ bool opEquals(long lo) const
+ {
+ return data.lo == lo && data.hi == (lo >> 63);
+ }
+
+ /************************
+ * Compare for equality
+ * Params: lo = unsigned value to compare with
+ * Returns: true if Int128 equals value
+ */
+ bool opEquals(ulong lo) const
+ {
+ return data.hi == 0 && data.lo == lo;
+ }
+
+ /************************
+ * Compare for equality
+ * Params: op2 = value to compare with
+ * Returns: true if Int128 equals value
+ */
+ bool opEquals(Int128 op2) const
+ {
+ return data.hi == op2.data.hi && data.lo == op2.data.lo;
+ }
+
+ /** Support unary arithmentic operator +
+ * Params: op = "+"
+ * Returns: lvalue of result
+ */
+ Int128 opUnary(string op)() const
+ if (op == "+")
+ {
+ return this;
+ }
+
+ /** Support unary arithmentic operator - ~
+ * Params: op = "-", "~"
+ * Returns: lvalue of result
+ */
+ Int128 opUnary(string op)() const
+ if (op == "-" || op == "~")
+ {
+ static if (op == "-")
+ return Int128(neg(this.data));
+ else static if (op == "~")
+ return Int128(com(this.data));
+ }
+
+ /** Support unary arithmentic operator ++ --
+ * Params: op = "++", "--"
+ * Returns: lvalue of result
+ */
+ Int128 opUnary(string op)()
+ if (op == "++" || op == "--")
+ {
+ static if (op == "++")
+ this.data = inc(this.data);
+ else static if (op == "--")
+ this.data = dec(this.data);
+ else
+ static assert(0, op);
+ return this;
+ }
+
+ /** Support casting to a bool
+ * Params: T = bool
+ * Returns: boolean result
+ */
+ bool opCast(T : bool)() const
+ {
+ return tst(this.data);
+ }
+
+ /** Support binary arithmetic operators + - * / % & | ^ << >> >>>
+ * Params:
+ * op = one of the arithmetic binary operators
+ * op2 = second operand
+ * Returns: value after the operation is applied
+ */
+ Int128 opBinary(string op)(Int128 op2) const
+ if (op == "+" || op == "-" ||
+ op == "*" || op == "/" || op == "%" ||
+ op == "&" || op == "|" || op == "^")
+ {
+ static if (op == "+")
+ return Int128(add(this.data, op2.data));
+ else static if (op == "-")
+ return Int128(sub(this.data, op2.data));
+ else static if (op == "*")
+ return Int128(mul(this.data, op2.data));
+ else static if (op == "/")
+ return Int128(div(this.data, op2.data));
+ else static if (op == "%")
+ {
+ Cent modulus;
+ divmod(this.data, op2.data, modulus);
+ return Int128(modulus);
+ }
+ else static if (op == "&")
+ return Int128(and(this.data, op2.data));
+ else static if (op == "|")
+ return Int128(or(this.data, op2.data));
+ else static if (op == "^")
+ return Int128(xor(this.data, op2.data));
+ else
+ static assert(0, "wrong op value");
+ }
+
+ /// ditto
+ Int128 opBinary(string op)(long op2) const
+ if (op == "+" || op == "-" ||
+ op == "*" || op == "/" || op == "%" ||
+ op == "&" || op == "|" || op == "^")
+ {
+ return mixin("this " ~ op ~ " Int128(0, op2)");
+ }
+
+ /// ditto
+ Int128 opBinaryRight(string op)(long op2) const
+ if (op == "+" || op == "-" ||
+ op == "*" || op == "/" || op == "%" ||
+ op == "&" || op == "|" || op == "^")
+ {
+ mixin("return Int128(0, op2) " ~ op ~ " this;");
+ }
+
+ /// ditto
+ Int128 opBinary(string op)(long op2) const
+ if (op == "<<")
+ {
+ return Int128(shl(this.data, cast(uint) op2));
+ }
+
+ /// ditto
+ Int128 opBinary(string op)(long op2) const
+ if (op == ">>")
+ {
+ return Int128(sar(this.data, cast(uint) op2));
+ }
+
+ /// ditto
+ Int128 opBinary(string op)(long op2) const
+ if (op == ">>>")
+ {
+ return Int128(shr(this.data, cast(uint) op2));
+ }
+
+ /** arithmetic assignment operators += -= *= /= %= &= |= ^= <<= >>= >>>=
+ * Params: op = one of +, -, etc.
+ * op2 = second operand
+ * Returns: lvalue of updated left operand
+ */
+ 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;
+ }
+
+ /// ditto
+ 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;
+ }
+
+ /** support signed arithmentic comparison operators < <= > >=
+ * Params: op2 = right hand operand
+ * Returns: -1 for less than, 0 for equals, 1 for greater than
+ */
+ int opCmp(Int128 op2) const
+ {
+ return this == op2 ? 0 : gt(this.data, op2.data) * 2 - 1;
+ }
+
+ /** support signed arithmentic comparison operators < <= > >=
+ * Params: op2 = right hand operand
+ * Returns: -1 for less than, 0 for equals, 1 for greater than
+ */
+ int opCmp(long op2) const
+ {
+ 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;
+
+@trusted void print(Int128 c)
+{
+ printf("%lld, %lld\n", c.data.hi, c.data.lo);
+}
+
+@trusted void printx(Int128 c)
+{
+ printf("%llx, %llx\n", c.data.hi, c.data.lo);
+}
+}
+
+/// Int128 tests
+@safe pure nothrow @nogc
+unittest
+{
+ Int128 c = Int128(5, 6);
+ assert(c == c);
+ assert(c == +c);
+ assert(c == - -c);
+ assert(~c == Int128(~5, ~6));
+ ++c;
+ assert(c == Int128(5, 7));
+ 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);
+
+ c = Int128(-1UL);
+ assert(c == -1UL);
+ c = Int128(-1L);
+ assert(c == -1L);
+}