@@ -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