From 268742fbd6314ba849b75edfb4df343518de0a8e Mon Sep 17 00:00:00 2001 From: Justin King Date: Wed, 14 Oct 2026 14:10:29 -0700 Subject: [PATCH] Implement three-way comparison for `cel::Attribute` and friends PiperOrigin-RevId: 999611174 --- base/BUILD | 1 + base/attribute.cc | 430 ++++++++++++++++++++++++++++------------------ base/attribute.h | 167 +++++++++++++++--- 3 files changed, 411 insertions(+), 187 deletions(-) diff --git a/base/BUILD b/base/BUILD index cf116727d..9becb06cb 100644 --- a/base/BUILD +++ b/base/BUILD @@ -47,6 +47,7 @@ cc_library( "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", + "@com_google_absl//absl/types:compare", "@com_google_absl//absl/types:optional_ref", "@com_google_absl//absl/types:span", ], diff --git a/base/attribute.cc b/base/attribute.cc index 0375067d8..2d8d8cada 100644 --- a/base/attribute.cc +++ b/base/attribute.cc @@ -14,6 +14,7 @@ #include "base/attribute.h" +#include #include #include #include @@ -21,7 +22,7 @@ #include #include "absl/algorithm/container.h" -#include "absl/base/macros.h" +#include "absl/base/attributes.h" #include "absl/base/nullability.h" #include "absl/log/absl_check.h" #include "absl/meta/type_traits.h" @@ -29,6 +30,7 @@ #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" +#include "absl/types/compare.h" #include "base/kind.h" #include "internal/lexis.h" #include "internal/status_macros.h" @@ -195,58 +197,6 @@ Kind AttributeQualifier::kind() const { return std::visit(AttributeQualifierTypeVisitor{}, value_); } -bool Attribute::operator==(const Attribute& other) const { - // We cannot check pointer equality as a short circuit because we have to - // treat all invalid AttributeQualifier as not equal to each other. - // TODO(issues/41) we only support Ident-rooted attributes at the moment. - if (variable_name() != other.variable_name()) { - return false; - } - - if (qualifier_path().size() != other.qualifier_path().size()) { - return false; - } - - for (size_t i = 0; i < qualifier_path().size(); i++) { - if (!(qualifier_path()[i] == other.qualifier_path()[i])) { - return false; - } - } - - return true; -} - -bool Attribute::operator<(const Attribute& other) const { - if (impl_.get() == other.impl_.get()) { - return false; - } - auto lhs_begin = qualifier_path().begin(); - auto lhs_end = qualifier_path().end(); - auto rhs_begin = other.qualifier_path().begin(); - auto rhs_end = other.qualifier_path().end(); - while (lhs_begin != lhs_end && rhs_begin != rhs_end) { - if (*lhs_begin < *rhs_begin) { - return true; - } - if (!(*lhs_begin == *rhs_begin)) { - return false; - } - lhs_begin++; - rhs_begin++; - } - if (lhs_begin == lhs_end && rhs_begin == rhs_end) { - // Neither has any elements left, they are equal. Compare variable names. - return variable_name() < other.variable_name(); - } - if (lhs_begin == lhs_end) { - // Left has no more elements. Right is greater. - return true; - } - // Right has no more elements. Left is greater. - ABSL_ASSERT(rhs_begin == rhs_end); - return false; -} - absl::StatusOr Attribute::AsString() const { if (variable_name().empty()) { return absl::InvalidArgumentError( @@ -368,65 +318,103 @@ bool AttributeQualifierPattern::IsMatch(absl::string_view other_key) const { namespace { struct AttributeQualifierEqualTo { - bool operator()(const std::monostate&, const std::monostate&) const { + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(const std::monostate&, + const std::monostate&) const { return false; } template - std::enable_if_t, std::monostate>, - bool> + ABSL_ATTRIBUTE_ALWAYS_INLINE std::enable_if_t< + !std::is_same_v, std::monostate>, bool> operator()(const std::monostate&, const T&) const { return false; } template - std::enable_if_t, std::monostate>, - bool> + ABSL_ATTRIBUTE_ALWAYS_INLINE std::enable_if_t< + !std::is_same_v, std::monostate>, bool> operator()(const T&, const std::monostate&) const { return false; } - bool operator()(bool lhs, bool rhs) const { return lhs == rhs; } + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(bool lhs, bool rhs) const { + return lhs == rhs; + } - bool operator()(bool, int64_t) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(bool, int64_t) const { + return false; + } - bool operator()(bool, uint64_t) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(bool, uint64_t) const { + return false; + } - bool operator()(bool, absl::string_view) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(bool, absl::string_view) const { + return false; + } - bool operator()(int64_t, bool) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(int64_t, bool) const { + return false; + } - bool operator()(int64_t lhs, int64_t rhs) const { return lhs == rhs; } + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(int64_t lhs, int64_t rhs) const { + return lhs == rhs; + } - bool operator()(int64_t, uint64_t) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(int64_t, uint64_t) const { + return false; + } - bool operator()(int64_t, absl::string_view) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(int64_t, + absl::string_view) const { + return false; + } - bool operator()(uint64_t, bool) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(uint64_t, bool) const { + return false; + } - bool operator()(uint64_t, int64_t) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(uint64_t, int64_t) const { + return false; + } - bool operator()(uint64_t lhs, uint64_t rhs) const { return lhs == rhs; } + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(uint64_t lhs, + uint64_t rhs) const { + return lhs == rhs; + } - bool operator()(uint64_t, absl::string_view) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(uint64_t, + absl::string_view) const { + return false; + } - bool operator()(absl::string_view, bool) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(absl::string_view, bool) const { + return false; + } - bool operator()(absl::string_view, int64_t) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(absl::string_view, + int64_t) const { + return false; + } - bool operator()(absl::string_view, uint64_t) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(absl::string_view, + uint64_t) const { + return false; + } - bool operator()(absl::string_view lhs, absl::string_view rhs) const { + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()(absl::string_view lhs, + absl::string_view rhs) const { return lhs == rhs; } - bool operator()(const common_internal::WildcardType&, - const common_internal::WildcardType&) const { + ABSL_ATTRIBUTE_ALWAYS_INLINE bool operator()( + const common_internal::WildcardType&, + const common_internal::WildcardType&) const { return true; } template - std::enable_if_t< + ABSL_ATTRIBUTE_ALWAYS_INLINE std::enable_if_t< !std::is_same_v, common_internal::WildcardType> && !std::is_same_v, std::monostate>, bool> @@ -435,7 +423,7 @@ struct AttributeQualifierEqualTo { } template - std::enable_if_t< + ABSL_ATTRIBUTE_ALWAYS_INLINE std::enable_if_t< !std::is_same_v, common_internal::WildcardType> && !std::is_same_v, std::monostate>, bool> @@ -444,85 +432,243 @@ struct AttributeQualifierEqualTo { } }; -struct AttributeQualifierLess { - bool operator()(const std::monostate&, const std::monostate&) const { - return false; +template +[[nodiscard]] +ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering SynthesizeCompare(T lhs, + T rhs) { +#if defined(__cpp_impl_three_way_comparison) && \ + defined(__cpp_lib_three_way_comparison) + return lhs <=> rhs; +#else + if (lhs < rhs) { + return absl::strong_ordering::less; + } + if (rhs < lhs) { + return absl::strong_ordering::greater; + } + return absl::strong_ordering::equal; +#endif +} + +struct AttributeQualifierCompare { + // monostate < int < uint < string < bool < wildcard + + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()( + const std::monostate&, const std::monostate&) const { + return absl::strong_ordering::equal; } template - std::enable_if_t, std::monostate>, - bool> - operator()(const std::monostate&, const T&) const { - return true; + ABSL_ATTRIBUTE_ALWAYS_INLINE + std::enable_if_t, std::monostate>, + absl::strong_ordering> + operator()(const std::monostate&, const T&) const { + return absl::strong_ordering::less; } template - std::enable_if_t, std::monostate>, - bool> - operator()(const T&, const std::monostate&) const { - return false; + ABSL_ATTRIBUTE_ALWAYS_INLINE + std::enable_if_t, std::monostate>, + absl::strong_ordering> + operator()(const T&, const std::monostate&) const { + return absl::strong_ordering::greater; } - bool operator()(bool lhs, bool rhs) const { return lhs < rhs; } + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()( + bool lhs, bool rhs) const { + return (SynthesizeCompare)(lhs, rhs); + } - bool operator()(bool, int64_t) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()(bool, + int64_t) const { + return absl::strong_ordering::greater; + } - bool operator()(bool, uint64_t) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()( + bool, uint64_t) const { + return absl::strong_ordering::greater; + } - bool operator()(bool, absl::string_view) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()( + bool, absl::string_view) const { + return absl::strong_ordering::greater; + } - bool operator()(int64_t, bool) const { return true; } + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()(int64_t, + bool) const { + return absl::strong_ordering::less; + } - bool operator()(int64_t lhs, int64_t rhs) const { return lhs < rhs; } + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()( + int64_t lhs, int64_t rhs) const { + return (SynthesizeCompare)(lhs, rhs); + } - bool operator()(int64_t, uint64_t) const { return true; } + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()( + int64_t, uint64_t) const { + return absl::strong_ordering::less; + } - bool operator()(int64_t, absl::string_view) const { return true; } + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()( + int64_t, absl::string_view) const { + return absl::strong_ordering::less; + } - bool operator()(uint64_t, bool) const { return true; } + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()(uint64_t, + bool) const { + return absl::strong_ordering::less; + } - bool operator()(uint64_t, int64_t) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()(uint64_t, + int64_t) const { + return absl::strong_ordering::greater; + } - bool operator()(uint64_t lhs, uint64_t rhs) const { return lhs < rhs; } + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()( + uint64_t lhs, uint64_t rhs) const { + return (SynthesizeCompare)(lhs, rhs); + } - bool operator()(uint64_t, absl::string_view) const { return true; } + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()( + uint64_t, absl::string_view) const { + return absl::strong_ordering::less; + } - bool operator()(absl::string_view, bool) const { return true; } + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()( + absl::string_view, bool) const { + return absl::strong_ordering::less; + } - bool operator()(absl::string_view, int64_t) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()( + absl::string_view, int64_t) const { + return absl::strong_ordering::greater; + } - bool operator()(absl::string_view, uint64_t) const { return false; } + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()( + absl::string_view, uint64_t) const { + return absl::strong_ordering::greater; + } - bool operator()(absl::string_view lhs, absl::string_view rhs) const { - return lhs < rhs; + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()( + absl::string_view lhs, absl::string_view rhs) const { + return (SynthesizeCompare)(lhs, rhs); } - bool operator()(const common_internal::WildcardType&, - const common_internal::WildcardType&) const { - return false; + ABSL_ATTRIBUTE_ALWAYS_INLINE absl::strong_ordering operator()( + const common_internal::WildcardType&, + const common_internal::WildcardType&) const { + return absl::strong_ordering::equal; } template - std::enable_if_t< + ABSL_ATTRIBUTE_ALWAYS_INLINE std::enable_if_t< !std::is_same_v, common_internal::WildcardType> && !std::is_same_v, std::monostate>, - bool> + absl::strong_ordering> operator()(const common_internal::WildcardType&, const T&) const { - return false; + return absl::strong_ordering::greater; } template - std::enable_if_t< + ABSL_ATTRIBUTE_ALWAYS_INLINE std::enable_if_t< !std::is_same_v, common_internal::WildcardType> && !std::is_same_v, std::monostate>, - bool> + absl::strong_ordering> operator()(const T&, const common_internal::WildcardType&) const { - return true; + return absl::strong_ordering::less; } }; } // namespace +absl::strong_ordering AttributeQualifier::Compare( + const AttributeQualifier& other) const { + return std::visit(AttributeQualifierCompare{}, + common_internal::AsVariant(*this), + common_internal::AsVariant(other)); +} + +absl::strong_ordering AttributeQualifier::Compare( + const AttributeQualifierView& other) const { + return std::visit(AttributeQualifierCompare{}, + common_internal::AsVariant(*this), + common_internal::AsVariant(other)); +} + +absl::strong_ordering AttributeQualifier::Compare( + const AttributeQualifierPattern& other) const { + return std::visit(AttributeQualifierCompare{}, + common_internal::AsVariant(*this), + common_internal::AsVariant(other)); +} + +absl::strong_ordering AttributeQualifierView::Compare( + const AttributeQualifier& other) const { + return std::visit(AttributeQualifierCompare{}, + common_internal::AsVariant(*this), + common_internal::AsVariant(other)); +} + +absl::strong_ordering AttributeQualifierView::Compare( + const AttributeQualifierView& other) const { + return std::visit(AttributeQualifierCompare{}, + common_internal::AsVariant(*this), + common_internal::AsVariant(other)); +} + +absl::strong_ordering AttributeQualifierView::Compare( + const AttributeQualifierPattern& other) const { + return std::visit(AttributeQualifierCompare{}, + common_internal::AsVariant(*this), + common_internal::AsVariant(other)); +} + +absl::strong_ordering AttributeQualifierPattern::Compare( + const AttributeQualifier& other) const { + return std::visit(AttributeQualifierCompare{}, + common_internal::AsVariant(*this), + common_internal::AsVariant(other)); +} + +absl::strong_ordering AttributeQualifierPattern::Compare( + const AttributeQualifierView& other) const { + return std::visit(AttributeQualifierCompare{}, + common_internal::AsVariant(*this), + common_internal::AsVariant(other)); +} + +absl::strong_ordering AttributeQualifierPattern::Compare( + const AttributeQualifierPattern& other) const { + return std::visit(AttributeQualifierCompare{}, + common_internal::AsVariant(*this), + common_internal::AsVariant(other)); +} + +absl::strong_ordering Attribute::Compare(const Attribute& other) const { + if (absl::strong_ordering order = + (SynthesizeCompare)(variable_name(), other.variable_name()); + order != absl::strong_ordering::equal) { + return order; + } + const auto& qualifiers = qualifier_path(); + const auto& other_qualifiers = other.qualifier_path(); + const size_t min_size = std::min(qualifiers.size(), other_qualifiers.size()); + for (size_t i = 0; i < min_size; ++i) { + if (absl::strong_ordering order = + qualifiers[i].Compare(other_qualifiers[i]); + order != absl::strong_ordering::equal) { + return order; + } + } + if (qualifiers.size() < other_qualifiers.size()) { + return absl::strong_ordering::less; + } + if (qualifiers.size() > other_qualifiers.size()) { + return absl::strong_ordering::greater; + } + return absl::strong_ordering::equal; +} + bool operator==(const AttributeQualifier& lhs, const AttributeQualifier& rhs) { return std::visit(AttributeQualifierEqualTo{}, common_internal::AsVariant(lhs), @@ -585,57 +731,9 @@ bool operator==(const AttributeQualifierPattern& lhs, common_internal::AsVariant(rhs)); } -bool operator<(const AttributeQualifier& lhs, const AttributeQualifier& rhs) { - return std::visit(AttributeQualifierLess{}, common_internal::AsVariant(lhs), - common_internal::AsVariant(rhs)); -} - -bool operator<(const AttributeQualifierView& lhs, - const AttributeQualifierView& rhs) { - return std::visit(AttributeQualifierLess{}, common_internal::AsVariant(lhs), - common_internal::AsVariant(rhs)); -} - -bool operator<(const AttributeQualifierPattern& lhs, - const AttributeQualifierPattern& rhs) { - return std::visit(AttributeQualifierLess{}, common_internal::AsVariant(lhs), - common_internal::AsVariant(rhs)); -} - -bool operator<(const AttributeQualifier& lhs, - const AttributeQualifierView& rhs) { - return std::visit(AttributeQualifierLess{}, common_internal::AsVariant(lhs), - common_internal::AsVariant(rhs)); -} - -bool operator<(const AttributeQualifier& lhs, - const AttributeQualifierPattern& rhs) { - return std::visit(AttributeQualifierLess{}, common_internal::AsVariant(lhs), - common_internal::AsVariant(rhs)); -} - -bool operator<(const AttributeQualifierView& lhs, - const AttributeQualifier& rhs) { - return std::visit(AttributeQualifierLess{}, common_internal::AsVariant(lhs), - common_internal::AsVariant(rhs)); -} - -bool operator<(const AttributeQualifierView& lhs, - const AttributeQualifierPattern& rhs) { - return std::visit(AttributeQualifierLess{}, common_internal::AsVariant(lhs), - common_internal::AsVariant(rhs)); -} - -bool operator<(const AttributeQualifierPattern& lhs, - const AttributeQualifier& rhs) { - return std::visit(AttributeQualifierLess{}, common_internal::AsVariant(lhs), - common_internal::AsVariant(rhs)); -} - -bool operator<(const AttributeQualifierPattern& lhs, - const AttributeQualifierView& rhs) { - return std::visit(AttributeQualifierLess{}, common_internal::AsVariant(lhs), - common_internal::AsVariant(rhs)); +bool operator==(const Attribute& lhs, const Attribute& rhs) { + return lhs.variable_name() == rhs.variable_name() && + absl::c_equal(lhs.qualifier_path(), rhs.qualifier_path()); } bool operator==(const AttributePattern& lhs, const AttributePattern& rhs) { diff --git a/base/attribute.h b/base/attribute.h index 521391c68..7e9e98c67 100644 --- a/base/attribute.h +++ b/base/attribute.h @@ -32,6 +32,7 @@ #include "absl/log/absl_check.h" #include "absl/status/statusor.h" #include "absl/strings/string_view.h" +#include "absl/types/compare.h" #include "absl/types/optional_ref.h" #include "absl/types/span.h" #include "base/kind.h" @@ -245,6 +246,15 @@ class AttributeQualifier { [[nodiscard]] bool IsMatch(absl::string_view other_key) const; + [[nodiscard]] + absl::strong_ordering Compare(const AttributeQualifier& other) const; + + [[nodiscard]] + absl::strong_ordering Compare(const AttributeQualifierView& other) const; + + [[nodiscard]] + absl::strong_ordering Compare(const AttributeQualifierPattern& other) const; + private: friend const common_internal::AttributeQualifierVariant& common_internal::AsVariant(const AttributeQualifier& qualifier); @@ -441,6 +451,15 @@ class AttributeQualifierView { std::string* absl_nonnull out, absl::Span qualifiers); + [[nodiscard]] + absl::strong_ordering Compare(const AttributeQualifier& other) const; + + [[nodiscard]] + absl::strong_ordering Compare(const AttributeQualifierView& other) const; + + [[nodiscard]] + absl::strong_ordering Compare(const AttributeQualifierPattern& other) const; + private: friend const common_internal::AttributeQualifierViewVariant& common_internal::AsVariant(const AttributeQualifierView& qualifier); @@ -729,6 +748,15 @@ class AttributeQualifierPattern { [[nodiscard]] bool IsMatch(absl::string_view other_key) const; + [[nodiscard]] + absl::strong_ordering Compare(const AttributeQualifier& other) const; + + [[nodiscard]] + absl::strong_ordering Compare(const AttributeQualifierView& other) const; + + [[nodiscard]] + absl::strong_ordering Compare(const AttributeQualifierPattern& other) const; + private: friend const common_internal::AttributeQualifierPatternVariant& common_internal::AsVariant(const AttributeQualifierPattern& qualifier); @@ -782,6 +810,62 @@ bool operator==(const AttributeQualifierPattern& lhs, bool operator==(const AttributeQualifierPattern& lhs, const AttributeQualifierView& rhs); +#if defined(__cpp_impl_three_way_comparison) && \ + defined(__cpp_lib_three_way_comparison) +[[nodiscard]] +inline absl::strong_ordering operator<=>(const AttributeQualifier& lhs, + const AttributeQualifier& rhs) { + return lhs.Compare(rhs); +} + +[[nodiscard]] +inline absl::strong_ordering operator<=>(const AttributeQualifier& lhs, + const AttributeQualifierView& rhs) { + return lhs.Compare(rhs); +} + +[[nodiscard]] +inline absl::strong_ordering operator<=>(const AttributeQualifier& lhs, + const AttributeQualifierPattern& rhs) { + return lhs.Compare(rhs); +} + +[[nodiscard]] +inline absl::strong_ordering operator<=>(const AttributeQualifierView& lhs, + const AttributeQualifier& rhs) { + return lhs.Compare(rhs); +} + +[[nodiscard]] +inline absl::strong_ordering operator<=>(const AttributeQualifierView& lhs, + const AttributeQualifierView& rhs) { + return lhs.Compare(rhs); +} + +[[nodiscard]] +inline absl::strong_ordering operator<=>(const AttributeQualifierView& lhs, + const AttributeQualifierPattern& rhs) { + return lhs.Compare(rhs); +} + +[[nodiscard]] +inline absl::strong_ordering operator<=>(const AttributeQualifierPattern& lhs, + const AttributeQualifier& rhs) { + return lhs.Compare(rhs); +} + +[[nodiscard]] +inline absl::strong_ordering operator<=>(const AttributeQualifierPattern& lhs, + const AttributeQualifierView& rhs) { + return lhs.Compare(rhs); +} + +[[nodiscard]] +inline absl::strong_ordering operator<=>(const AttributeQualifierPattern& lhs, + const AttributeQualifierPattern& rhs) { + return lhs.Compare(rhs); +} +#else [[nodiscard]] inline bool operator!=(const AttributeQualifier& lhs, const AttributeQualifier& rhs) { @@ -837,39 +921,59 @@ inline bool operator!=(const AttributeQualifierPattern& lhs, } [[nodiscard]] -bool operator<(const AttributeQualifier& lhs, const AttributeQualifier& rhs); +inline bool operator<(const AttributeQualifier& lhs, + const AttributeQualifier& rhs) { + return lhs.Compare(rhs) < 0; +} [[nodiscard]] -bool operator<(const AttributeQualifierView& lhs, - const AttributeQualifierView& rhs); +inline bool operator<(const AttributeQualifierView& lhs, + const AttributeQualifierView& rhs) { + return lhs.Compare(rhs) < 0; +} [[nodiscard]] -bool operator<(const AttributeQualifierPattern& lhs, - const AttributeQualifierPattern& rhs); +inline bool operator<(const AttributeQualifierPattern& lhs, + const AttributeQualifierPattern& rhs) { + return lhs.Compare(rhs) < 0; +} [[nodiscard]] -bool operator<(const AttributeQualifier& lhs, - const AttributeQualifierView& rhs); +inline bool operator<(const AttributeQualifier& lhs, + const AttributeQualifierView& rhs) { + return lhs.Compare(rhs) < 0; +} [[nodiscard]] -bool operator<(const AttributeQualifier& lhs, - const AttributeQualifierPattern& rhs); +inline bool operator<(const AttributeQualifier& lhs, + const AttributeQualifierPattern& rhs) { + return lhs.Compare(rhs) < 0; +} [[nodiscard]] -bool operator<(const AttributeQualifierView& lhs, - const AttributeQualifier& rhs); +inline bool operator<(const AttributeQualifierView& lhs, + const AttributeQualifier& rhs) { + return lhs.Compare(rhs) < 0; +} [[nodiscard]] -bool operator<(const AttributeQualifierView& lhs, - const AttributeQualifierPattern& rhs); +inline bool operator<(const AttributeQualifierView& lhs, + const AttributeQualifierPattern& rhs) { + return lhs.Compare(rhs) < 0; +} [[nodiscard]] -bool operator<(const AttributeQualifierPattern& lhs, - const AttributeQualifier& rhs); +inline bool operator<(const AttributeQualifierPattern& lhs, + const AttributeQualifier& rhs) { + return lhs.Compare(rhs) < 0; +} [[nodiscard]] -bool operator<(const AttributeQualifierPattern& lhs, - const AttributeQualifierView& rhs); +inline bool operator<(const AttributeQualifierPattern& lhs, + const AttributeQualifierView& rhs) { + return lhs.Compare(rhs) < 0; +} +#endif namespace common_internal { @@ -930,15 +1034,14 @@ class Attribute { return impl_->qualifier_path; } - bool operator==(const Attribute& other) const; - - bool operator<(const Attribute& other) const; - absl::StatusOr AsString() const; [[nodiscard]] std::string ToString() const; + [[nodiscard]] + absl::strong_ordering Compare(const Attribute& other) const; + private: struct Impl final { Impl(std::string variable_name, @@ -953,6 +1056,28 @@ class Attribute { std::shared_ptr impl_; }; +[[nodiscard]] +bool operator==(const Attribute& lhs, const Attribute& rhs); + +#if defined(__cpp_impl_three_way_comparison) && \ + defined(__cpp_lib_three_way_comparison) +[[nodiscard]] +inline absl::strong_ordering operator<=>(const Attribute& lhs, + const Attribute& rhs) { + return lhs.Compare(rhs); +} +#else +[[nodiscard]] +inline bool operator!=(const Attribute& lhs, const Attribute& rhs) { + return !operator==(lhs, rhs); +} + +[[nodiscard]] +inline bool operator<(const Attribute& lhs, const Attribute& rhs) { + return lhs.Compare(rhs) < 0; +} +#endif + template void AbslStringify(S& sink, const Attribute& attribute) { sink.Append(attribute.ToString());