diff --git a/absl/strings/charconv.h b/absl/strings/charconv.h index e5733f8c251..f8abbfc2253 100644 --- a/absl/strings/charconv.h +++ b/absl/strings/charconv.h @@ -47,6 +47,15 @@ enum class chars_format { struct from_chars_result { const char* absl_nonnull ptr; std::errc ec; + + constexpr friend bool operator==(const from_chars_result& l, + const from_chars_result& r) noexcept { + return l.ptr == r.ptr && l.ec == r.ec; + } + + constexpr explicit operator bool() const noexcept { + return ec == std::errc{}; + } }; // Workalike compatibility version of std::from_chars from C++17. Currently diff --git a/absl/strings/charconv_test.cc b/absl/strings/charconv_test.cc index c16c735c24b..55a3f785efb 100644 --- a/absl/strings/charconv_test.cc +++ b/absl/strings/charconv_test.cc @@ -784,4 +784,117 @@ TEST(FromChars, DecimalFloatLimits) { TestOverflowAndUnderflow(input_gen, expected_gen, -45, 38); } +#if !defined(ABSL_INTERNAL_CPLUSPLUS_LANG) || \ + ABSL_INTERNAL_CPLUSPLUS_LANG < 202002L +constexpr bool operator!=(const absl::from_chars_result& l, + const absl::from_chars_result& r) noexcept { + return !(l == r); +} +#endif +// Check that the operator== for from_chars_result works as expected. +// +// EXPECT_TRUE and EXPECT_FALSE used intentionally to check operator== and +// operator!= explicitly. +// Before C++20 we need to define the operator!= explicitly, as it is not +// automatically generated by the compiler. +TEST(FromChars, ResultOperatorEqual) { + { + absl::from_chars_result result1{}; + absl::from_chars_result result2{}; + EXPECT_TRUE(result1 == result2); + EXPECT_FALSE(result1 != result2); + } + + { + absl::from_chars_result result1{}; + result1.ec = std::errc::result_out_of_range; + absl::from_chars_result result2{}; + result2.ec = std::errc::result_out_of_range; + EXPECT_TRUE(result1 == result2); + EXPECT_FALSE(result1 != result2); + } + { + absl::from_chars_result result1{}; + result1.ec = std::errc::result_out_of_range; + absl::from_chars_result result2{}; + EXPECT_FALSE(result1 == result2); + EXPECT_TRUE(result1 != result2); + } + { + absl::from_chars_result result1{}; + absl::from_chars_result result2{}; + result2.ec = std::errc::result_out_of_range; + EXPECT_FALSE(result1 == result2); + EXPECT_TRUE(result1 != result2); + } + + { + absl::from_chars_result result1{}; + result1.ptr = ""; + absl::from_chars_result result2{}; + result2.ptr = ""; + EXPECT_TRUE(result1 == result2); + EXPECT_FALSE(result1 != result2); + } + { + absl::from_chars_result result1{}; + result1.ptr = ""; + absl::from_chars_result result2{}; + EXPECT_FALSE(result1 == result2); + EXPECT_TRUE(result1 != result2); + } + { + absl::from_chars_result result1{}; + absl::from_chars_result result2{}; + result2.ptr = ""; + EXPECT_FALSE(result1 == result2); + EXPECT_TRUE(result1 != result2); + } + + { + absl::from_chars_result result1{"", std::errc::result_out_of_range}; + absl::from_chars_result result2{"", std::errc::result_out_of_range}; + EXPECT_TRUE(result1 == result2); + EXPECT_FALSE(result1 != result2); + } + { + absl::from_chars_result result1{"", std::errc::result_out_of_range}; + absl::from_chars_result result2{}; + EXPECT_FALSE(result1 == result2); + EXPECT_TRUE(result1 != result2); + } + { + absl::from_chars_result result1{}; + absl::from_chars_result result2{"", std::errc::result_out_of_range}; + EXPECT_FALSE(result1 == result2); + EXPECT_TRUE(result1 != result2); + } +} + +// Check that the operator bool for from_chars_result works as expected. +TEST(FromChars, ResultOperatorBool) { + { + absl::from_chars_result result{}; + EXPECT_TRUE(result); + EXPECT_FALSE(!result); + } + { + absl::from_chars_result result{}; + result.ec = std::errc::result_out_of_range; + EXPECT_FALSE(result); + EXPECT_TRUE(!result); + } + { + absl::from_chars_result result{}; + result.ptr = ""; + EXPECT_TRUE(result); + EXPECT_FALSE(!result); + } + { + absl::from_chars_result result{"", std::errc::result_out_of_range}; + EXPECT_FALSE(result); + EXPECT_TRUE(!result); + } +} + } // namespace