[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>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index 7f2dd00..3305b8d 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -251,6 +251,8 @@
"utils/hashset.h",
"utils/map.h",
"utils/math.h",
+ "utils/parse_num.cc",
+ "utils/parse_num.h",
"utils/predicates.h",
"utils/scoped_assignment.h",
"utils/slice.h",
@@ -273,6 +275,8 @@
} else {
sources += [ "diagnostic/printer_other.cc" ]
}
+
+ deps = [ ":abseil" ]
}
libtint_source_set("libtint_clone_context_hdrs") {
@@ -1064,7 +1068,6 @@
]
deps = [
- ":abseil",
":libtint_ast_src",
":libtint_builtins_src",
":libtint_program_src",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 2e097f4..d8fe22a 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -536,6 +536,8 @@
utils/hashset.h
utils/map.h
utils/math.h
+ utils/parse_num.cc
+ utils/parse_num.h
utils/predicates.h
utils/scoped_assignment.h
utils/slice.h
diff --git a/src/tint/reader/wgsl/lexer.cc b/src/tint/reader/wgsl/lexer.cc
index 1e1dad4..4ed4786 100644
--- a/src/tint/reader/wgsl/lexer.cc
+++ b/src/tint/reader/wgsl/lexer.cc
@@ -25,9 +25,9 @@
#include <type_traits>
#include <utility>
-#include "absl/strings/charconv.h"
#include "src/tint/debug.h"
#include "src/tint/number.h"
+#include "src/tint/utils/parse_num.h"
#include "src/tint/utils/unicode.h"
namespace tint::reader::wgsl {
@@ -414,12 +414,13 @@
end_ptr = &at(length() - 1) + 1;
}
- double value = 0;
- auto ret = absl::from_chars(&at(start), end_ptr, value);
- bool overflow = ret.ec != std::errc();
+ auto ret = utils::ParseDouble(std::string_view(&at(start), end - start));
+ double value = ret ? ret.Get() : 0.0;
+ 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 (ret.ec == std::errc::result_out_of_range) {
+ // If the value didn't fit in a double, check for underflow as that is 0.0 in WGSL and not an
+ // error.
+ if (overflow) {
// The exponent is negative, so treat as underflow
if (negative_exponent) {
overflow = false;
@@ -446,7 +447,6 @@
}
}
- TINT_ASSERT(Reader, end_ptr == ret.ptr);
advance(end - start);
if (has_f_suffix) {
diff --git a/src/tint/utils/parse_num.cc b/src/tint/utils/parse_num.cc
new file mode 100644
index 0000000..fa04344
--- /dev/null
+++ b/src/tint/utils/parse_num.cc
@@ -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
diff --git a/src/tint/utils/parse_num.h b/src/tint/utils/parse_num.h
new file mode 100644
index 0000000..6d4fcb4
--- /dev/null
+++ b/src/tint/utils/parse_num.h
@@ -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_