speedup SkRect::isFinite() (almost 2x)
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 16 May 2012 13:35:36 +0000 (13:35 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 16 May 2012 13:35:36 +0000 (13:35 +0000)
add SkRect:set(p0, p1) for quick bounds of 2 points

git-svn-id: http://skia.googlecode.com/svn/trunk@3967 2bbb7eff-a529-9590-31e7-b0007b416f81

include/core/SkRect.h
tests/InfRectTest.cpp

index 2fa3256..e055c3d 100644 (file)
@@ -75,7 +75,7 @@ struct SK_API SkIRect {
      *  Return true if the rectangle's width or height are <= 0
      */
     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
-
+    
     friend bool operator==(const SkIRect& a, const SkIRect& b) {
         return !memcmp(&a, &b, sizeof(a));
     }
@@ -354,13 +354,18 @@ struct SK_API SkRect {
      */
     bool isFinite() const {
 #ifdef SK_SCALAR_IS_FLOAT
-        // x * 0 will be NaN iff x is infinity or NaN.
-        // a + b will be NaN iff either a or b is NaN.
-        float value = fLeft * 0 + fTop * 0 + fRight * 0 + fBottom * 0;
+        float accum = 0;
+        accum *= fLeft;
+        accum *= fTop;
+        accum *= fRight;
+        accum *= fBottom;
         
-        // value is either NaN or it is finite (zero).
+        // accum is either NaN or it is finite (zero).
+        SkASSERT(0 == accum || !(accum == accum));
+
         // value==value will be true iff value is not NaN
-        return value == value;
+        // TODO: is it faster to say !accum or accum==accum?
+        return accum == accum;
 #else
         // use bit-or for speed, since we don't care about short-circuting the
         // tests, and we expect the common case will be that we need to check all.
@@ -436,6 +441,13 @@ struct SK_API SkRect {
         this->set(pts, count);
     }
 
+    void set(const SkPoint& p0, const SkPoint& p1) {
+        fLeft =   SkMinScalar(p0.fX, p1.fX);
+        fRight =  SkMaxScalar(p0.fX, p1.fX);
+        fTop =    SkMinScalar(p0.fY, p1.fY);
+        fBottom = SkMaxScalar(p0.fY, p1.fY);
+    }
+
     void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) {
         fLeft = x;
         fTop = y;
index 12356d9..1dc6ca7 100644 (file)
@@ -25,24 +25,28 @@ static void check_invalid(skiatest::Reporter* reporter,
 // as one of its coordinates.
 static void TestInfRect(skiatest::Reporter* reporter) {
 #ifdef SK_SCALAR_IS_FLOAT
-    float invalid = 1 / make_zero();    // infinity
+    float inf = 1 / make_zero();    // infinity
+    float nan = inf * 0;
+    SkASSERT(!(nan == nan));
 #else
-    SkFixed invalid = SK_FixedNaN;
+    SkFixed inf = SK_FixedNaN;
+    SkFixed nan = SK_FixedNaN;
 #endif
     SkScalar small = SkIntToScalar(10);
     SkScalar big = SkIntToScalar(100);
 
+    REPORTER_ASSERT(reporter, SkRect::MakeEmpty().isFinite());
+
     SkRect rect = SkRect::MakeXYWH(small, small, big, big);
     REPORTER_ASSERT(reporter, rect.isFinite());
 
-    check_invalid(reporter, small, small, big, invalid);
-    check_invalid(reporter, small, small, invalid, big);
-    check_invalid(reporter, small, invalid, big, big);
-    check_invalid(reporter, invalid, small, big, big);
-    check_invalid(reporter, small, small, big, -invalid);
-    check_invalid(reporter, small, small, -invalid, big);
-    check_invalid(reporter, small, -invalid, big, big);
-    check_invalid(reporter, -invalid, small, big, big);
+    const SkScalar invalid[] = { nan, inf, -inf };
+    for (size_t i = 0; i < SK_ARRAY_COUNT(invalid); ++i) {
+        check_invalid(reporter, small, small, big, invalid[i]);
+        check_invalid(reporter, small, small, invalid[i], big);
+        check_invalid(reporter, small, invalid[i], big, big);
+        check_invalid(reporter, invalid[i], small, big, big);
+    }
 }
 
 // need tests for SkStrSearch