[tint][utils] Abstract absl dependency

Move the use of absl::from_chars() in the WGSL parser into utils, behind
a new abstraction.

If we decide one day to drop the absl dependency, we can reimplement
this function. It also consolodates tint source_set dependencies on absl
to the common utils module.

No new tests as this is a thin wrapper around an existing
implementation, and the single use is already heavily tested for parsing.

Change-Id: I1ce5d68857e81299d1c97322b0ec28f0a83a31b7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/134581
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
Ben Clayton 2023-05-27 00:50:46 +00:00 committed by Dawn LUCI CQ
parent 8ba1ff7789
commit f75e5c07b0
5 changed files with 237 additions and 8 deletions

View File

@ -251,6 +251,8 @@ libtint_source_set("libtint_utils_src") {
"utils/hashset.h", "utils/hashset.h",
"utils/map.h", "utils/map.h",
"utils/math.h", "utils/math.h",
"utils/parse_num.cc",
"utils/parse_num.h",
"utils/predicates.h", "utils/predicates.h",
"utils/scoped_assignment.h", "utils/scoped_assignment.h",
"utils/slice.h", "utils/slice.h",
@ -273,6 +275,8 @@ libtint_source_set("libtint_utils_src") {
} else { } else {
sources += [ "diagnostic/printer_other.cc" ] sources += [ "diagnostic/printer_other.cc" ]
} }
deps = [ ":abseil" ]
} }
libtint_source_set("libtint_clone_context_hdrs") { libtint_source_set("libtint_clone_context_hdrs") {
@ -1064,7 +1068,6 @@ libtint_source_set("libtint_wgsl_reader_src") {
] ]
deps = [ deps = [
":abseil",
":libtint_ast_src", ":libtint_ast_src",
":libtint_builtins_src", ":libtint_builtins_src",
":libtint_program_src", ":libtint_program_src",

View File

@ -536,6 +536,8 @@ list(APPEND TINT_LIB_SRCS
utils/hashset.h utils/hashset.h
utils/map.h utils/map.h
utils/math.h utils/math.h
utils/parse_num.cc
utils/parse_num.h
utils/predicates.h utils/predicates.h
utils/scoped_assignment.h utils/scoped_assignment.h
utils/slice.h utils/slice.h

View File

@ -25,9 +25,9 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include "absl/strings/charconv.h"
#include "src/tint/debug.h" #include "src/tint/debug.h"
#include "src/tint/number.h" #include "src/tint/number.h"
#include "src/tint/utils/parse_num.h"
#include "src/tint/utils/unicode.h" #include "src/tint/utils/unicode.h"
namespace tint::reader::wgsl { namespace tint::reader::wgsl {
@ -414,12 +414,13 @@ std::optional<Token> Lexer::try_float() {
end_ptr = &at(length() - 1) + 1; end_ptr = &at(length() - 1) + 1;
} }
double value = 0; auto ret = utils::ParseDouble(std::string_view(&at(start), end - start));
auto ret = absl::from_chars(&at(start), end_ptr, value); double value = ret ? ret.Get() : 0.0;
bool overflow = ret.ec != std::errc(); bool overflow = !ret && ret.Failure() == utils::ParseNumberError::kResultOutOfRange;
// Value didn't fit in a double, check for underflow as that is 0.0 in WGSL and not an error. // If the value didn't fit in a double, check for underflow as that is 0.0 in WGSL and not an
if (ret.ec == std::errc::result_out_of_range) { // error.
if (overflow) {
// The exponent is negative, so treat as underflow // The exponent is negative, so treat as underflow
if (negative_exponent) { if (negative_exponent) {
overflow = false; overflow = false;
@ -446,7 +447,6 @@ std::optional<Token> Lexer::try_float() {
} }
} }
TINT_ASSERT(Reader, end_ptr == ret.ptr);
advance(end - start); advance(end - start);
if (has_f_suffix) { if (has_f_suffix) {

View File

@ -0,0 +1,98 @@
// Copyright 2023 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/tint/utils/parse_num.h"
#include <charconv>
#include "absl/strings/charconv.h"
namespace tint::utils {
namespace {
template <typename T>
Result<T, ParseNumberError> Parse(std::string_view number) {
T val = 0;
if constexpr (std::is_floating_point_v<T>) {
auto result = absl::from_chars(number.data(), number.data() + number.size(), val);
if (result.ec == std::errc::result_out_of_range) {
return ParseNumberError::kResultOutOfRange;
}
if (result.ec != std::errc() || result.ptr != number.data() + number.size()) {
return ParseNumberError::kUnparsable;
}
} else {
auto result = std::from_chars(number.data(), number.data() + number.size(), val);
if (result.ec == std::errc::result_out_of_range) {
return ParseNumberError::kResultOutOfRange;
}
if (result.ec != std::errc() || result.ptr != number.data() + number.size()) {
return ParseNumberError::kUnparsable;
}
}
return val;
}
} // namespace
Result<float, ParseNumberError> ParseFloat(std::string_view str) {
return Parse<float>(str);
}
Result<double, ParseNumberError> ParseDouble(std::string_view str) {
return Parse<double>(str);
}
Result<int, ParseNumberError> ParseInt(std::string_view str) {
return Parse<int>(str);
}
Result<unsigned int, ParseNumberError> ParseUint(std::string_view str) {
return Parse<unsigned int>(str);
}
Result<int64_t, ParseNumberError> ParseInt64(std::string_view str) {
return Parse<int64_t>(str);
}
Result<uint64_t, ParseNumberError> ParseUint64(std::string_view str) {
return Parse<uint64_t>(str);
}
Result<int32_t, ParseNumberError> ParseInt32(std::string_view str) {
return Parse<int32_t>(str);
}
Result<uint32_t, ParseNumberError> ParseUint32(std::string_view str) {
return Parse<uint32_t>(str);
}
Result<int16_t, ParseNumberError> ParseInt16(std::string_view str) {
return Parse<int16_t>(str);
}
Result<uint16_t, ParseNumberError> ParseUint16(std::string_view str) {
return Parse<uint16_t>(str);
}
Result<int8_t, ParseNumberError> ParseInt8(std::string_view str) {
return Parse<int8_t>(str);
}
Result<uint8_t, ParseNumberError> ParseUint8(std::string_view str) {
return Parse<uint8_t>(str);
}
} // namespace tint::utils

126
src/tint/utils/parse_num.h Normal file
View File

@ -0,0 +1,126 @@
// Copyright 2023 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_TINT_UTILS_PARSE_NUM_H_
#define SRC_TINT_UTILS_PARSE_NUM_H_
#include <optional>
#include <string>
#include "src/tint/utils/result.h"
namespace tint::utils {
/// Error returned by the number parsing functions
enum class ParseNumberError {
/// The number was unparsable
kUnparsable,
/// The parsed number is not representable by the target datatype
kResultOutOfRange,
};
/// @param str the string
/// @returns the string @p str parsed as a float
Result<float, ParseNumberError> ParseFloat(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a double
Result<double, ParseNumberError> ParseDouble(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a int
Result<int, ParseNumberError> ParseInt(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a unsigned int
Result<unsigned int, ParseNumberError> ParseUint(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a int64_t
Result<int64_t, ParseNumberError> ParseInt64(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a uint64_t
Result<uint64_t, ParseNumberError> ParseUint64(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a int32_t
Result<int32_t, ParseNumberError> ParseInt32(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a uint32_t
Result<uint32_t, ParseNumberError> ParseUint32(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a int16_t
Result<int16_t, ParseNumberError> ParseInt16(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a uint16_t
Result<uint16_t, ParseNumberError> ParseUint16(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a int8_t
Result<int8_t, ParseNumberError> ParseInt8(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a uint8_t
Result<uint8_t, ParseNumberError> ParseUint8(std::string_view str);
/// @param str the string
/// @returns the string @p str parsed as a the number @p T
template <typename T>
inline Result<T, ParseNumberError> ParseNumber(std::string_view str) {
if constexpr (std::is_same_v<T, float>) {
return ParseFloat(str);
}
if constexpr (std::is_same_v<T, double>) {
return ParseDouble(str);
}
if constexpr (std::is_same_v<T, int>) {
return ParseInt(str);
}
if constexpr (std::is_same_v<T, unsigned int>) {
return ParseUint(str);
}
if constexpr (std::is_same_v<T, int64_t>) {
return ParseInt64(str);
}
if constexpr (std::is_same_v<T, uint64_t>) {
return ParseUint64(str);
}
if constexpr (std::is_same_v<T, int32_t>) {
return ParseInt32(str);
}
if constexpr (std::is_same_v<T, uint32_t>) {
return ParseUint32(str);
}
if constexpr (std::is_same_v<T, int16_t>) {
return ParseInt16(str);
}
if constexpr (std::is_same_v<T, uint16_t>) {
return ParseUint16(str);
}
if constexpr (std::is_same_v<T, int8_t>) {
return ParseInt8(str);
}
if constexpr (std::is_same_v<T, uint8_t>) {
return ParseUint8(str);
}
return ParseNumberError::kUnparsable;
}
} // namespace tint::utils
#endif // SRC_TINT_UTILS_PARSE_NUM_H_