ScalarTest.cpp revision 7886ad3de1aa523d5c71f1fa9f355dfcb2412d1d
1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "Test.h"
9#include "SkFloatingPoint.h"
10#include "SkMath.h"
11#include "SkPoint.h"
12#include "SkRandom.h"
13#include "SkRect.h"
14
15struct PointSet {
16    const SkPoint* fPts;
17    size_t         fCount;
18    bool           fIsFinite;
19};
20
21static void test_isRectFinite(skiatest::Reporter* reporter) {
22#ifdef SK_SCALAR_IS_FLOAT
23    static const SkPoint gF0[] = {
24        { 0, 0 }, { 1, 1 }
25    };
26    static const SkPoint gF1[] = {
27        { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }
28    };
29
30    static const SkPoint gI0[] = {
31        { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { SK_ScalarNaN, 3 }, { 2, 3 },
32    };
33    static const SkPoint gI1[] = {
34        { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { 3, SK_ScalarNaN }, { 2, 3 },
35    };
36    static const SkPoint gI2[] = {
37        { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { SK_ScalarInfinity, 3 }, { 2, 3 },
38    };
39    static const SkPoint gI3[] = {
40        { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { 3, SK_ScalarInfinity }, { 2, 3 },
41    };
42
43    static const struct {
44        const SkPoint* fPts;
45        size_t         fCount;
46        bool           fIsFinite;
47    } gSets[] = {
48        { gF0, SK_ARRAY_COUNT(gF0), true },
49        { gF1, SK_ARRAY_COUNT(gF1), true },
50
51        { gI0, SK_ARRAY_COUNT(gI0), false },
52        { gI1, SK_ARRAY_COUNT(gI1), false },
53        { gI2, SK_ARRAY_COUNT(gI2), false },
54        { gI3, SK_ARRAY_COUNT(gI3), false },
55    };
56
57    for (size_t i = 0; i < SK_ARRAY_COUNT(gSets); ++i) {
58        SkRect r;
59        r.set(gSets[i].fPts, gSets[i].fCount);
60        bool rectIsFinite = !r.isEmpty();
61        REPORTER_ASSERT(reporter, gSets[i].fIsFinite == rectIsFinite);
62    }
63#endif
64}
65
66static bool isFinite_int(float x) {
67    uint32_t bits = SkFloat2Bits(x);    // need unsigned for our shifts
68    int exponent = bits << 1 >> 24;
69    return exponent != 0xFF;
70}
71
72static bool isFinite_float(float x) {
73    return SkToBool(sk_float_isfinite(x));
74}
75
76static bool isFinite_mulzero(float x) {
77    float y = x * 0;
78    return y == y;
79}
80
81// return true if the float is finite
82typedef bool (*IsFiniteProc1)(float);
83
84static bool isFinite2_and(float x, float y, IsFiniteProc1 proc) {
85    return proc(x) && proc(y);
86}
87
88static bool isFinite2_mulzeroadd(float x, float y, IsFiniteProc1 proc) {
89    return proc(x * 0 + y * 0);
90}
91
92// return true if both floats are finite
93typedef bool (*IsFiniteProc2)(float, float, IsFiniteProc1);
94
95enum FloatClass {
96    kFinite,
97    kInfinite,
98    kNaN
99};
100
101static void test_floatclass(skiatest::Reporter* reporter, float value, FloatClass fc) {
102    // our sk_float_is... function may return int instead of bool,
103    // hence the double ! to turn it into a bool
104    REPORTER_ASSERT(reporter, !!sk_float_isfinite(value) == (fc == kFinite));
105    REPORTER_ASSERT(reporter, !!sk_float_isinf(value) == (fc == kInfinite));
106    REPORTER_ASSERT(reporter, !!sk_float_isnan(value) == (fc == kNaN));
107}
108
109#if defined _WIN32
110#pragma warning ( push )
111// we are intentionally causing an overflow here
112//      (warning C4756: overflow in constant arithmetic)
113#pragma warning ( disable : 4756 )
114#endif
115
116static void test_isfinite(skiatest::Reporter* reporter) {
117    struct Rec {
118        float   fValue;
119        bool    fIsFinite;
120    };
121
122    float max = 3.402823466e+38f;
123    float inf = max * max;
124    float nan = inf * 0;
125
126    test_floatclass(reporter,    0, kFinite);
127    test_floatclass(reporter,  max, kFinite);
128    test_floatclass(reporter, -max, kFinite);
129    test_floatclass(reporter,  inf, kInfinite);
130    test_floatclass(reporter, -inf, kInfinite);
131    test_floatclass(reporter,  nan, kNaN);
132    test_floatclass(reporter, -nan, kNaN);
133
134    const Rec data[] = {
135        {   0,           true    },
136        {   1,           true    },
137        {  -1,           true    },
138        {  max * 0.75f,  true    },
139        {  max,          true    },
140        {  -max * 0.75f, true    },
141        {  -max,         true    },
142        {  inf,          false   },
143        { -inf,          false   },
144        {  nan,          false   },
145    };
146
147    const IsFiniteProc1 gProc1[] = {
148        isFinite_int,
149        isFinite_float,
150        isFinite_mulzero
151    };
152    const IsFiniteProc2 gProc2[] = {
153        isFinite2_and,
154        isFinite2_mulzeroadd
155    };
156
157    size_t i, n = SK_ARRAY_COUNT(data);
158
159    for (i = 0; i < n; ++i) {
160        for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) {
161            const Rec& rec = data[i];
162            bool finite = gProc1[k](rec.fValue);
163            REPORTER_ASSERT(reporter, rec.fIsFinite == finite);
164        }
165    }
166
167    for (i = 0; i < n; ++i) {
168        const Rec& rec0 = data[i];
169        for (size_t j = 0; j < n; ++j) {
170            const Rec& rec1 = data[j];
171            for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) {
172                IsFiniteProc1 proc1 = gProc1[k];
173
174                for (size_t m = 0; m < SK_ARRAY_COUNT(gProc2); ++m) {
175                    bool finite = gProc2[m](rec0.fValue, rec1.fValue, proc1);
176                    bool finite2 = rec0.fIsFinite && rec1.fIsFinite;
177                    REPORTER_ASSERT(reporter, finite2 == finite);
178                }
179            }
180        }
181    }
182
183    test_isRectFinite(reporter);
184}
185
186#if defined _WIN32
187#pragma warning ( pop )
188#endif
189
190static void TestScalar(skiatest::Reporter* reporter) {
191    test_isfinite(reporter);
192}
193
194#include "TestClassDef.h"
195DEFINE_TESTCLASS("Scalar", TestScalarClass, TestScalar)
196
197