Commit 40e9e5f0 authored by Kent Tamura's avatar Kent Tamura Committed by Commit Bot

Make ToIntegralType() behavior configurable.

Introduce NumberParsingOptions, which is a set of parsing behavior flags, and
CharactersToFoo{,Strict}() pass options to ToIntegralType().

This CL has no behavior changes.
This CL is a preparation to merge CharactersToFoo and CharactersToFooStrict.

Bug: 746157
Change-Id: I34d001bb193928288b99afcd0d531536105ce7e0
Reviewed-on: https://chromium-review.googlesource.com/580170Reviewed-by: default avatarTakayoshi Kochi <kochi@chromium.org>
Commit-Queue: Kent Tamura <tkent@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488581}
parent 26ffad3a
......@@ -27,6 +27,7 @@ bool IsCharacterAllowedInBase<16>(UChar c) {
template <typename IntegralType, typename CharType, int base>
static inline IntegralType ToIntegralType(const CharType* data,
size_t length,
NumberParsingOptions options,
NumberParsingState* parsing_state) {
static_assert(std::is_integral<IntegralType>::value,
"IntegralType must be an integral type.");
......@@ -46,17 +47,18 @@ static inline IntegralType ToIntegralType(const CharType* data,
if (!data)
goto bye;
// skip leading whitespace
while (length && IsSpaceOrNewline(*data)) {
--length;
++data;
if (options.AcceptWhitespace()) {
while (length && IsSpaceOrNewline(*data)) {
--length;
++data;
}
}
if (kIsSigned && length && *data == '-') {
--length;
++data;
is_negative = true;
} else if (length && *data == '+') {
} else if (length && options.AcceptLeadingPlus() && *data == '+') {
--length;
++data;
}
......@@ -105,13 +107,14 @@ static inline IntegralType ToIntegralType(const CharType* data,
++data;
}
// skip trailing space
while (length && IsSpaceOrNewline(*data)) {
--length;
++data;
if (options.AcceptWhitespace()) {
while (length && IsSpaceOrNewline(*data)) {
--length;
++data;
}
}
if (length == 0) {
if (length == 0 || options.AcceptTrailingGarbage()) {
if (!overflow)
state = NumberParsingState::kSuccess;
} else {
......@@ -126,129 +129,118 @@ bye:
template <typename IntegralType, typename CharType, int base>
static inline IntegralType ToIntegralType(const CharType* data,
size_t length,
NumberParsingOptions options,
bool* ok) {
NumberParsingState state;
IntegralType value =
ToIntegralType<IntegralType, CharType, base>(data, length, &state);
IntegralType value = ToIntegralType<IntegralType, CharType, base>(
data, length, options, &state);
if (ok)
*ok = state == NumberParsingState::kSuccess;
return value;
}
template <typename CharType>
static unsigned LengthOfCharactersAsInteger(const CharType* data,
size_t length) {
size_t i = 0;
// Allow leading spaces.
for (; i != length; ++i) {
if (!IsSpaceOrNewline(data[i]))
break;
}
// Allow sign.
if (i != length && (data[i] == '+' || data[i] == '-'))
++i;
// Allow digits.
for (; i != length; ++i) {
if (!IsASCIIDigit(data[i]))
break;
}
return i;
}
unsigned CharactersToUIntStrict(const LChar* data,
size_t length,
NumberParsingState* state) {
return ToIntegralType<unsigned, LChar, 10>(data, length, state);
return ToIntegralType<unsigned, LChar, 10>(
data, length, NumberParsingOptions::kStrict, state);
}
unsigned CharactersToUIntStrict(const UChar* data,
size_t length,
NumberParsingState* state) {
return ToIntegralType<unsigned, UChar, 10>(data, length, state);
return ToIntegralType<unsigned, UChar, 10>(
data, length, NumberParsingOptions::kStrict, state);
}
int CharactersToIntStrict(const LChar* data, size_t length, bool* ok) {
return ToIntegralType<int, LChar, 10>(data, length, ok);
return ToIntegralType<int, LChar, 10>(data, length,
NumberParsingOptions::kStrict, ok);
}
int CharactersToIntStrict(const UChar* data, size_t length, bool* ok) {
return ToIntegralType<int, UChar, 10>(data, length, ok);
return ToIntegralType<int, UChar, 10>(data, length,
NumberParsingOptions::kStrict, ok);
}
unsigned CharactersToUIntStrict(const LChar* data, size_t length, bool* ok) {
return ToIntegralType<unsigned, LChar, 10>(data, length, ok);
return ToIntegralType<unsigned, LChar, 10>(data, length,
NumberParsingOptions::kStrict, ok);
}
unsigned CharactersToUIntStrict(const UChar* data, size_t length, bool* ok) {
return ToIntegralType<unsigned, UChar, 10>(data, length, ok);
return ToIntegralType<unsigned, UChar, 10>(data, length,
NumberParsingOptions::kStrict, ok);
}
unsigned HexCharactersToUIntStrict(const LChar* data, size_t length, bool* ok) {
return ToIntegralType<unsigned, LChar, 16>(data, length, ok);
return ToIntegralType<unsigned, LChar, 16>(data, length,
NumberParsingOptions::kStrict, ok);
}
unsigned HexCharactersToUIntStrict(const UChar* data, size_t length, bool* ok) {
return ToIntegralType<unsigned, UChar, 16>(data, length, ok);
return ToIntegralType<unsigned, UChar, 16>(data, length,
NumberParsingOptions::kStrict, ok);
}
int64_t CharactersToInt64Strict(const LChar* data, size_t length, bool* ok) {
return ToIntegralType<int64_t, LChar, 10>(data, length, ok);
return ToIntegralType<int64_t, LChar, 10>(data, length,
NumberParsingOptions::kStrict, ok);
}
int64_t CharactersToInt64Strict(const UChar* data, size_t length, bool* ok) {
return ToIntegralType<int64_t, UChar, 10>(data, length, ok);
return ToIntegralType<int64_t, UChar, 10>(data, length,
NumberParsingOptions::kStrict, ok);
}
uint64_t CharactersToUInt64Strict(const LChar* data, size_t length, bool* ok) {
return ToIntegralType<uint64_t, LChar, 10>(data, length, ok);
return ToIntegralType<uint64_t, LChar, 10>(data, length,
NumberParsingOptions::kStrict, ok);
}
uint64_t CharactersToUInt64Strict(const UChar* data, size_t length, bool* ok) {
return ToIntegralType<uint64_t, UChar, 10>(data, length, ok);
return ToIntegralType<uint64_t, UChar, 10>(data, length,
NumberParsingOptions::kStrict, ok);
}
int CharactersToInt(const LChar* data, size_t length, bool* ok) {
return ToIntegralType<int, LChar, 10>(
data, LengthOfCharactersAsInteger<LChar>(data, length), ok);
return ToIntegralType<int, LChar, 10>(data, length,
NumberParsingOptions::kLoose, ok);
}
int CharactersToInt(const UChar* data, size_t length, bool* ok) {
return ToIntegralType<int, UChar, 10>(
data, LengthOfCharactersAsInteger(data, length), ok);
return ToIntegralType<int, UChar, 10>(data, length,
NumberParsingOptions::kLoose, ok);
}
unsigned CharactersToUInt(const LChar* data, size_t length, bool* ok) {
return ToIntegralType<unsigned, LChar, 10>(
data, LengthOfCharactersAsInteger<LChar>(data, length), ok);
return ToIntegralType<unsigned, LChar, 10>(data, length,
NumberParsingOptions::kLoose, ok);
}
unsigned CharactersToUInt(const UChar* data, size_t length, bool* ok) {
return ToIntegralType<unsigned, UChar, 10>(
data, LengthOfCharactersAsInteger<UChar>(data, length), ok);
return ToIntegralType<unsigned, UChar, 10>(data, length,
NumberParsingOptions::kLoose, ok);
}
int64_t CharactersToInt64(const LChar* data, size_t length, bool* ok) {
return ToIntegralType<int64_t, LChar, 10>(
data, LengthOfCharactersAsInteger<LChar>(data, length), ok);
return ToIntegralType<int64_t, LChar, 10>(data, length,
NumberParsingOptions::kLoose, ok);
}
int64_t CharactersToInt64(const UChar* data, size_t length, bool* ok) {
return ToIntegralType<int64_t, UChar, 10>(
data, LengthOfCharactersAsInteger<UChar>(data, length), ok);
return ToIntegralType<int64_t, UChar, 10>(data, length,
NumberParsingOptions::kLoose, ok);
}
uint64_t CharactersToUInt64(const LChar* data, size_t length, bool* ok) {
return ToIntegralType<uint64_t, LChar, 10>(
data, LengthOfCharactersAsInteger<LChar>(data, length), ok);
return ToIntegralType<uint64_t, LChar, 10>(data, length,
NumberParsingOptions::kLoose, ok);
}
uint64_t CharactersToUInt64(const UChar* data, size_t length, bool* ok) {
return ToIntegralType<uint64_t, UChar, 10>(
data, LengthOfCharactersAsInteger<UChar>(data, length), ok);
return ToIntegralType<uint64_t, UChar, 10>(data, length,
NumberParsingOptions::kLoose, ok);
}
enum TrailingJunkPolicy { kDisallowTrailingJunk, kAllowTrailingJunk };
......
......@@ -10,6 +10,39 @@
namespace WTF {
// Copyable and immutable object representing number parsing flags.
class NumberParsingOptions {
public:
static constexpr unsigned kNone = 0;
static constexpr unsigned kAcceptTrailingGarbage = 1;
static constexpr unsigned kAcceptLeadingPlus = 1 << 1;
static constexpr unsigned kAcceptLeadingTrailingWhitespace = 1 << 2;
// TODO(tkent): Add kAcceptMinusZeroForUnsigned
// Legacy 'Strict' behavior.
static constexpr unsigned kStrict =
kAcceptLeadingPlus | kAcceptLeadingTrailingWhitespace;
// Legacy non-'Strict' behavior.
static constexpr unsigned kLoose = kStrict | kAcceptTrailingGarbage;
// This constructor allows implicit conversion from unsigned.
NumberParsingOptions(unsigned options) : options_(options) {}
bool AcceptTrailingGarbage() const {
return options_ & kAcceptTrailingGarbage;
}
bool AcceptLeadingPlus() const { return options_ & kAcceptLeadingPlus; }
bool AcceptWhitespace() const {
return options_ & kAcceptLeadingTrailingWhitespace;
}
private:
unsigned options_;
};
// TODO(tkent): Merge CharactersToFooStrict and CharactersToFoo by adding
// NumberParsingOptions argument.
// string -> int.
WTF_EXPORT int CharactersToIntStrict(const LChar*, size_t, bool* ok);
WTF_EXPORT int CharactersToIntStrict(const UChar*, size_t, bool* ok);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment