Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions absl/strings/charconv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
113 changes: 113 additions & 0 deletions absl/strings/charconv_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -784,4 +784,117 @@ TEST(FromChars, DecimalFloatLimits) {
TestOverflowAndUnderflow<float>(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