Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/intl/icu/source/i18n/numparse_scientific.cpp
Line
Count
Source (jump to first uncovered line)
1
// © 2018 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
4
#include "unicode/utypes.h"
5
6
#if !UCONFIG_NO_FORMATTING
7
8
// Allow implicit conversion from char16_t* to UnicodeString for this file:
9
// Helpful in toString methods and elsewhere.
10
#define UNISTR_FROM_STRING_EXPLICIT
11
12
#include "numparse_types.h"
13
#include "numparse_scientific.h"
14
#include "static_unicode_sets.h"
15
16
using namespace icu;
17
using namespace icu::numparse;
18
using namespace icu::numparse::impl;
19
20
21
namespace {
22
23
0
inline const UnicodeSet& minusSignSet() {
24
0
    return *unisets::get(unisets::MINUS_SIGN);
25
0
}
26
27
0
inline const UnicodeSet& plusSignSet() {
28
0
    return *unisets::get(unisets::PLUS_SIGN);
29
0
}
30
31
} // namespace
32
33
34
ScientificMatcher::ScientificMatcher(const DecimalFormatSymbols& dfs, const Grouper& grouper)
35
        : fExponentSeparatorString(dfs.getConstSymbol(DecimalFormatSymbols::kExponentialSymbol)),
36
0
          fExponentMatcher(dfs, grouper, PARSE_FLAG_INTEGER_ONLY | PARSE_FLAG_GROUPING_DISABLED) {
37
0
38
0
    const UnicodeString& minusSign = dfs.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
39
0
    if (minusSignSet().contains(minusSign)) {
40
0
        fCustomMinusSign.setToBogus();
41
0
    } else {
42
0
        fCustomMinusSign = minusSign;
43
0
    }
44
0
45
0
    const UnicodeString& plusSign = dfs.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
46
0
    if (plusSignSet().contains(plusSign)) {
47
0
        fCustomPlusSign.setToBogus();
48
0
    } else {
49
0
        fCustomPlusSign = plusSign;
50
0
    }
51
0
}
52
53
0
bool ScientificMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const {
54
0
    // Only accept scientific notation after the mantissa.
55
0
    if (!result.seenNumber()) {
56
0
        return false;
57
0
    }
58
0
59
0
    // First match the scientific separator, and then match another number after it.
60
0
    // NOTE: This is guarded by the smoke test; no need to check fExponentSeparatorString length again.
61
0
    int overlap1 = segment.getCommonPrefixLength(fExponentSeparatorString);
62
0
    if (overlap1 == fExponentSeparatorString.length()) {
63
0
        // Full exponent separator match.
64
0
65
0
        // First attempt to get a code point, returning true if we can't get one.
66
0
        if (segment.length() == overlap1) {
67
0
            return true;
68
0
        }
69
0
        segment.adjustOffset(overlap1);
70
0
71
0
        // Allow a sign, and then try to match digits.
72
0
        int8_t exponentSign = 1;
73
0
        if (segment.startsWith(minusSignSet())) {
74
0
            exponentSign = -1;
75
0
            segment.adjustOffsetByCodePoint();
76
0
        } else if (segment.startsWith(plusSignSet())) {
77
0
            segment.adjustOffsetByCodePoint();
78
0
        } else if (segment.startsWith(fCustomMinusSign)) {
79
0
            // Note: call site is guarded with startsWith, which returns false on empty string
80
0
            int32_t overlap2 = segment.getCommonPrefixLength(fCustomMinusSign);
81
0
            if (overlap2 != fCustomMinusSign.length()) {
82
0
                // Partial custom sign match; un-match the exponent separator.
83
0
                segment.adjustOffset(-overlap1);
84
0
                return true;
85
0
            }
86
0
            exponentSign = -1;
87
0
            segment.adjustOffset(overlap2);
88
0
        } else if (segment.startsWith(fCustomPlusSign)) {
89
0
            // Note: call site is guarded with startsWith, which returns false on empty string
90
0
            int32_t overlap2 = segment.getCommonPrefixLength(fCustomPlusSign);
91
0
            if (overlap2 != fCustomPlusSign.length()) {
92
0
                // Partial custom sign match; un-match the exponent separator.
93
0
                segment.adjustOffset(-overlap1);
94
0
                return true;
95
0
            }
96
0
            segment.adjustOffset(overlap2);
97
0
        }
98
0
99
0
        // We are supposed to accept E0 after NaN, so we need to make sure result.quantity is available.
100
0
        bool wasBogus = result.quantity.bogus;
101
0
        result.quantity.bogus = false;
102
0
        int digitsOffset = segment.getOffset();
103
0
        bool digitsReturnValue = fExponentMatcher.match(segment, result, exponentSign, status);
104
0
        result.quantity.bogus = wasBogus;
105
0
106
0
        if (segment.getOffset() != digitsOffset) {
107
0
            // At least one exponent digit was matched.
108
0
            result.flags |= FLAG_HAS_EXPONENT;
109
0
        } else {
110
0
            // No exponent digits were matched; un-match the exponent separator.
111
0
            segment.adjustOffset(-overlap1);
112
0
        }
113
0
        return digitsReturnValue;
114
0
115
0
    } else if (overlap1 == segment.length()) {
116
0
        // Partial exponent separator match
117
0
        return true;
118
0
    }
119
0
120
0
    // No match
121
0
    return false;
122
0
}
123
124
0
bool ScientificMatcher::smokeTest(const StringSegment& segment) const {
125
0
    return segment.startsWith(fExponentSeparatorString);
126
0
}
127
128
0
UnicodeString ScientificMatcher::toString() const {
129
0
    return u"<Scientific>";
130
0
}
131
132
133
#endif /* #if !UCONFIG_NO_FORMATTING */