Skip to content

Commit d7e79f0

Browse files
authored
Merge pull request #8816 from ibuclaw/merge_stable
merge stable
2 parents 0c8e5e5 + 71ec2cc commit d7e79f0

File tree

1 file changed

+112
-19
lines changed

1 file changed

+112
-19
lines changed

std/int128.d

Lines changed: 112 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ public struct Int128
153153
{
154154
return tst(this.data);
155155
}
156+
} // @safe pure nothrow @nogc
156157

157158
/** Support binary arithmetic operators + - * / % & | ^ << >> >>>
158159
* Params:
@@ -190,21 +191,49 @@ public struct Int128
190191
}
191192

192193
/// ditto
193-
Int128 opBinary(string op)(long op2) const
194-
if (op == "+" || op == "-" ||
194+
Int128 opBinary(string op, Int)(const Int op2) const
195+
if ((op == "+" || op == "-" ||
195196
op == "*" || op == "/" || op == "%" ||
196-
op == "&" || op == "|" || op == "^")
197+
op == "&" || op == "|" || op == "^") &&
198+
is(Int : long) && __traits(isIntegral, Int))
197199
{
198-
return mixin("this " ~ op ~ " Int128(0, op2)");
200+
static if (__traits(isUnsigned, Int))
201+
return mixin("this " ~ op ~ " Int128(0, op2)");
202+
else
203+
return mixin("this " ~ op ~ " Int128((cast(long) op2) >> 63 , op2)");
199204
}
200205

201206
/// ditto
202-
Int128 opBinaryRight(string op)(long op2) const
203-
if (op == "+" || op == "-" ||
207+
Int128 opBinary(string op, IntLike)(auto ref IntLike op2) const
208+
if ((op == "+" || op == "-" ||
204209
op == "*" || op == "/" || op == "%" ||
205-
op == "&" || op == "|" || op == "^")
210+
op == "&" || op == "|" || op == "^") &&
211+
is(IntLike : long) && !__traits(isIntegral, IntLike))
212+
{
213+
return opBinary!(op)(__traits(getMember, op2, __traits(getAliasThis, IntLike)[0]));
214+
}
215+
216+
/// ditto
217+
Int128 opBinaryRight(string op, Int)(const Int op2) const
218+
if ((op == "+" || op == "-" ||
219+
op == "*" || op == "/" || op == "%" ||
220+
op == "&" || op == "|" || op == "^") &&
221+
is(Int : long) && __traits(isIntegral, Int))
222+
{
223+
static if (__traits(isUnsigned, Int))
224+
mixin("return Int128(0, op2) " ~ op ~ " this;");
225+
else
226+
mixin("return Int128((cast(long) op2) >> 63, op2) " ~ op ~ " this;");
227+
}
228+
229+
/// ditto
230+
Int128 opBinaryRight(string op, IntLike)(auto ref IntLike op2) const
231+
if ((op == "+" || op == "-" ||
232+
op == "*" || op == "/" || op == "%" ||
233+
op == "&" || op == "|" || op == "^") &&
234+
is(IntLike : long) && !__traits(isIntegral, IntLike))
206235
{
207-
mixin("return Int128(0, op2) " ~ op ~ " this;");
236+
return opBinaryRight!(op)(__traits(getMember, op2, __traits(getAliasThis, IntLike)[0]));
208237
}
209238

210239
/// ditto
@@ -244,34 +273,42 @@ public struct Int128
244273
}
245274

246275
/// ditto
247-
ref Int128 opOpAssign(string op)(long op2)
248-
if (op == "+" || op == "-" ||
276+
ref Int128 opOpAssign(string op, Int)(auto ref Int op2)
277+
if ((op == "+" || op == "-" ||
249278
op == "*" || op == "/" || op == "%" ||
250279
op == "&" || op == "|" || op == "^" ||
251280
op == "<<" || op == ">>" || op == ">>>")
281+
&& is(Int : long))
252282
{
253283
mixin("this = this " ~ op ~ " op2;");
254284
return this;
255285
}
256286

257-
/** support signed arithmentic comparison operators < <= > >=
287+
/** support arithmentic comparison operators < <= > >=
258288
* Params: op2 = right hand operand
259289
* Returns: -1 for less than, 0 for equals, 1 for greater than
260290
*/
261-
int opCmp(Int128 op2) const
291+
int opCmp(Int128 op2) const @nogc nothrow pure @safe
262292
{
263293
return this == op2 ? 0 : gt(this.data, op2.data) * 2 - 1;
264294
}
265295

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-
*/
270-
int opCmp(long op2) const
296+
/// ditto
297+
int opCmp(Int)(const Int op2) const @nogc nothrow pure @safe
298+
if (is(Int : long) && __traits(isIntegral, Int))
271299
{
272-
return opCmp(Int128(0, op2));
300+
static if (__traits(isUnsigned, Int))
301+
return opCmp(Int128(0, op2));
302+
else
303+
return opCmp(Int128((cast(long) op2) >> 63, op2));
304+
}
305+
306+
/// ditto
307+
int opCmp(IntLike)(auto ref IntLike op2) const
308+
if (is(IntLike : long) && !__traits(isIntegral, IntLike))
309+
{
310+
return opCmp(__traits(getMember, op2, __traits(getAliasThis, IntLike)[0]));
273311
}
274-
} // @safe pure nothrow @nogc
275312

276313
/**
277314
* Formats `Int128` with either `%d`, `%x`, `%X`, or `%s` (same as `%d`).
@@ -514,3 +551,59 @@ unittest
514551
c = Int128(-1L);
515552
assert(c == -1L);
516553
}
554+
555+
@system unittest
556+
{
557+
alias Seq(T...) = T;
558+
Int128 c = Int128(-1L);
559+
assert(c.opCmp(-1L) == 0);
560+
// To avoid regression calling opCmp with any integral type needs to
561+
// work without the compiler complaining "opCmp called with argument
562+
// X matches both <...>".
563+
static foreach (Int; Seq!(long, int, short, byte, ulong, uint, ushort, ubyte, dchar, wchar, char))
564+
assert(c < Int.max);
565+
static foreach (Int; Seq!(int, short, byte))
566+
assert(c.opCmp(Int(-1)) == 0);
567+
assert(c < true);
568+
// To avoid regression calling opCmp with any type that converts to an
569+
// integral type through alias this needs to work regardless of whether
570+
// the alias is safe/pure/nothrow/nogc and regardless of whether the
571+
// type has a disabled postblit.
572+
static struct Wrapped(T)
573+
{
574+
T value;
575+
uint count;
576+
T get() @system { ++count; return value; } // not const
577+
alias get this;
578+
@disable this(this); // no implicit copies
579+
}
580+
assert(c.opCmp(Wrapped!long(-1)) == 0);
581+
auto w = Wrapped!ulong(ulong.max);
582+
w.count++; // avoid invalid D-Scanner message that w could have been declared const
583+
assert(c < w);
584+
585+
const zero = Int128(0L);
586+
const one = Int128(1L);
587+
const neg_one = Int128(-1L);
588+
const neg_two = Int128(-2L);
589+
// Correct result with ulong.max:
590+
assert(zero + ulong.max == ulong.max);
591+
assert(one * ulong.max == ulong.max);
592+
assert((neg_one & ulong.max) == ulong.max);
593+
assert((zero | ulong.max) == ulong.max);
594+
assert((zero ^ ulong.max) == ulong.max);
595+
// Correct result with negative arguments:
596+
assert(zero + -1L == -1L);
597+
assert(neg_two * -3L == 6L);
598+
assert(neg_two / -2L == 1L);
599+
assert(neg_two % -2L == 0L);
600+
assert((neg_one & -1L) == -1L);
601+
assert((zero | -1L) == -1L);
602+
assert((zero ^ -1L) == -1L);
603+
// Ensure alias this still works.
604+
{
605+
Int128 a = zero;
606+
assert((a ^= w) == ulong.max);
607+
}
608+
assert((Wrapped!long(-1L) + zero) == -1L);
609+
}

0 commit comments

Comments
 (0)