Jelajahi Sumber

[std] Fix unsigned behavior in some UInt ops

Mike Welsh 11 tahun lalu
induk
melakukan
a8de5bf311
2 mengubah file dengan 56 tambahan dan 35 penghapusan
  1. 23 35
      std/UInt.hx
  2. 33 0
      tests/unit/issues/Issue2736.hx

+ 23 - 35
std/UInt.hx

@@ -38,7 +38,7 @@ abstract UInt(Int) from Int to Int {
 	}
 
 	@:op(A / B) private static inline function div(a:UInt, b:UInt):Float {
-		return a.toInt() / b.toInt();
+		return a.toFloat() / b.toFloat();
 	}
 
 	@:op(A * B) private static inline function mul(a:UInt, b:UInt):UInt {
@@ -50,41 +50,19 @@ abstract UInt(Int) from Int to Int {
 	}
 
 	@:op(A > B) private static inline function gt(a:UInt, b:UInt):Bool {
-		if (a.toInt() < 0) {
-			if (b.toInt() >= 0) {
-				return false;
-			}
-			else {
-				return a.toInt() > b.toInt();
-			}
-		}
-		else {
-			if (b.toInt() >= 0) {
-				return a.toInt() > b.toInt();
-			}
-			else {
-				return true;
-			}
-		}
+		var aNeg = a.toInt() < 0;
+		var bNeg = b.toInt() < 0;
+		return
+			if( aNeg != bNeg ) aNeg;
+			else a.toInt() > b.toInt();
 	}
 
 	@:op(A >= B) private static inline function gte(a:UInt, b:UInt):Bool {
-		if (a.toInt() < 0) {
-			if (b.toInt() >= 0) {
-				return false;
-			}
-			else {
-				return a.toInt() >= b.toInt();
-			}
-		}
-		else {
-			if (b.toInt() >= 0) {
-				return a.toInt() >= b.toInt();
-			}
-			else {
-				return true;
-			}
-		}
+		var aNeg = a.toInt() < 0;
+		var bNeg = b.toInt() < 0;
+		return
+			if( aNeg != bNeg ) aNeg;
+			else a.toInt() >= b.toInt();
 	}
 
 	@:op(A < B) private static inline function lt(a:UInt, b:UInt):Bool {
@@ -120,7 +98,7 @@ abstract UInt(Int) from Int to Int {
 	}
 
 	@:op(A % B) private static inline function mod(a:UInt, b:UInt):UInt {
-		return a.toInt() % b.toInt();
+		return Std.int( a.toFloat() % b.toFloat() );
 	}
 	
 	@:commutative @:op(A + B) private static inline function addWithFloat(a:UInt, b:Float):Float {
@@ -151,6 +129,14 @@ abstract UInt(Int) from Int to Int {
 		return a.toFloat() > b;
 	}
 
+	@:commutative @:op(A == B) private static inline function equalsFloat(a:UInt, b:Float):Bool {
+        return a.toFloat() == b;
+    }
+
+    @:commutative @:op(A != B) private static inline function notEqualsFloat(a:UInt, b:Float):Bool {
+        return a.toFloat() != b;
+    }
+
 	@:op(A >= B) private static inline function gteFloat(a:UInt, b:Float):Bool {
 		return a.toFloat() >= b;
 	}
@@ -224,7 +210,9 @@ abstract UInt(Int) from Int to Int {
 			return 4294967296.0 + int;
 		}
 		else {
-			return int;
+			// + 0.0 here to make sure we promote to Float on some platforms
+			// In particular, PHP was having issues when comparing to Int in the == op.
+			return int + 0.0;
 		}
 	}
 }

+ 33 - 0
tests/unit/issues/Issue2736.hx

@@ -0,0 +1,33 @@
+package unit.issues;
+import unit.Test;
+
+/** UInt not showing proper unsigned behavior */
+class Issue2736 extends Test {
+	function test() {
+        var a:UInt, b:UInt;
+
+        b = 50000;
+        a = b * b;
+
+        eq( a, b*b );
+        eq( a/b, 50000 );
+        eq(a % b, 0);
+
+        f(a == b); t(a != b);
+        t(a > b); t(a >= b);
+        f(a < b); f(a <= b);
+        
+        // UInt vs Float comparisons
+        f( a == 1.0 ); t( b == 50000.0 );
+        t( a > 1.0 ); t( a >= 1.0 );
+        f( a < -1.0 ); f( a <= 1.0 );
+        
+        /* These are currently broken but should be fixed in the future:
+		 * Currently we don't allow UInt vs Int comparisons.
+         * trace(a == -1794967296);
+
+         * Shift on swf9 return as Int and not UInt
+         * trace(a >> 1); //-897483648 in flash, but 3397483648 in neko and js
+         */
+	}
+}