Skip to content
Merged
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
25 changes: 25 additions & 0 deletions base/attribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ class AttributeQualifier {
AttributeQualifier& operator=(const AttributeQualifier&) = default;
AttributeQualifier& operator=(AttributeQualifier&&) = default;

explicit AttributeQualifier(const AttributeQualifierView& other);

Kind kind() const;

ABSL_DEPRECATE_AND_INLINE()
Expand Down Expand Up @@ -324,6 +326,10 @@ class AttributeQualifierView {

AttributeQualifierView& operator=(AttributeQualifier&&) = delete;

explicit operator bool() const {
return !std::holds_alternative<std::monostate>(value_);
}

ABSL_DEPRECATE_AND_INLINE()
std::optional<int64_t> GetInt64Key() const { return AsInt(); }

Expand Down Expand Up @@ -450,6 +456,25 @@ class AttributeQualifierView {
Variant value_;
};

inline AttributeQualifier::AttributeQualifier(
const AttributeQualifierView& other)
: value_(std::visit(
absl::Overload([](std::monostate) -> Variant { return Variant(); },
[](int64_t value) -> Variant {
return Variant(std::in_place_type<int64_t>, value);
},
[](uint64_t value) -> Variant {
return Variant(std::in_place_type<uint64_t>, value);
},
[](absl::string_view value) -> Variant {
return Variant(std::in_place_type<std::string>,
value);
},
[](bool value) -> Variant {
return Variant(std::in_place_type<bool>, value);
}),
common_internal::AsVariant(other))) {}

// AttributeQualifierPattern matches a segment in
// attribute resolution path. AttributeQualifierPattern is capable of
// matching path elements of types string/int64/uint64/bool.
Expand Down
97 changes: 93 additions & 4 deletions base/attribute_matcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <vector>

#include "absl/base/attributes.h"
#include "absl/base/optimization.h"
#include "absl/functional/function_ref.h"
#include "absl/log/absl_check.h"
#include "absl/status/status.h"
Expand Down Expand Up @@ -78,6 +79,32 @@ class AttributeMatcherNode {
const AttributeMatcherNode& rhs) const {
return lhs < rhs.key();
}

bool operator()(absl::string_view lhs,
const AttributeQualifierPattern& rhs) const {
// Fast path for top-level variable matching, should only be called in
// that context.
ABSL_DCHECK(rhs.IsString());
return lhs < rhs.GetString();
}

bool operator()(const AttributeQualifierPattern& lhs,
absl::string_view rhs) const {
// Fast path for top-level variable matching, should only be called in
// that context.
ABSL_DCHECK(lhs.IsString());
return lhs.GetString() < rhs;
}

bool operator()(absl::string_view lhs,
const AttributeMatcherNode& rhs) const {
return (*this)(lhs, rhs.key());
}

bool operator()(const AttributeMatcherNode& lhs,
absl::string_view rhs) const {
return (*this)(lhs.key(), rhs);
}
};

AttributeMatcherNode(AttributeMatcherNode* parent,
Expand Down Expand Up @@ -113,7 +140,21 @@ class AttributeMatcherNode {

[[nodiscard]]
const AttributeMatcherNode* MatchQualifier(
const cel::AttributeQualifierView& qualifier) const {
const AttributeQualifierView& qualifier) const {
if (children_ != nullptr) {
auto it = children_->find(qualifier);
if (it != children_->end()) {
return &*it;
}
} else if (wildcard_ != nullptr) {
return wildcard_.get();
}
return nullptr;
}

[[nodiscard]]
const AttributeMatcherNode* MatchQualifier(
const AttributeQualifier& qualifier) const {
if (children_ != nullptr) {
auto it = children_->find(qualifier);
if (it != children_->end()) {
Expand Down Expand Up @@ -199,18 +240,27 @@ class [[nodiscard]] AttributeMatch {
// match should be handled.
AttributeMatch MatchQualifier(const AttributeQualifierView& qualifier) const {
ABSL_DCHECK(!IsFull());
ABSL_DCHECK(qualifier);
if (IsNone()) {
return AttributeMatch();
}
return AttributeMatch(node_->MatchQualifier(qualifier));
}

private:
friend class AttributeMatcher;
friend AttributeMatch common_internal::MakeAttributeMatch(
const common_internal::AttributeMatcherNode* node);
friend const common_internal::AttributeMatcherNode*
common_internal::GetAttributeMatcherNode(const AttributeMatch& match);

AttributeMatch NotNoneMatchQualifier(
const AttributeQualifierView& qualifier) const {
ABSL_DCHECK(!IsNone());
ABSL_DCHECK(qualifier);
return AttributeMatch(node_->MatchQualifier(qualifier));
}

explicit AttributeMatch(const common_internal::AttributeMatcherNode* node)
: node_(node) {}

Expand Down Expand Up @@ -273,13 +323,52 @@ class AttributeMatcher {

AttributeMatch MatchVariable(absl::string_view variable) const
ABSL_ATTRIBUTE_LIFETIME_BOUND {
auto it = children_.find(AttributeQualifierView::OfString(variable));
if (it != children_.end()) {
return common_internal::MakeAttributeMatch(&*it);
if (!variable.empty()) {
auto it = children_.find(variable);
if (it != children_.end()) {
return common_internal::MakeAttributeMatch(&*it);
}
}
return AttributeMatch();
}

AttributeMatch MatchAttribute(
absl::string_view variable,
absl::Span<const AttributeQualifierView> qualifiers) const {
AttributeMatch match = MatchVariable(variable);
for (const auto& qualifier : qualifiers) {
if (ABSL_PREDICT_FALSE(!qualifier)) {
return AttributeMatch();
}
if (match.IsNone()) {
break;
}
match = match.NotNoneMatchQualifier(qualifier);
}
return match;
}

AttributeMatch MatchAttribute(
absl::string_view variable,
absl::Span<const AttributeQualifier> qualifiers) const {
AttributeMatch match = MatchVariable(variable);
for (const auto& qualifier : qualifiers) {
if (ABSL_PREDICT_FALSE(!qualifier)) {
return AttributeMatch();
}
if (match.IsNone()) {
break;
}
match = match.NotNoneMatchQualifier(qualifier);
}
return match;
}

AttributeMatch MatchAttribute(const Attribute& attribute) const {
return MatchAttribute(attribute.variable_name(),
attribute.qualifier_path());
}

// Returns an array of attribute patterns corresponding to the
// previously added attribute patterns. The order of the attribute
// patterns in the array is not guaranteed.
Expand Down
28 changes: 28 additions & 0 deletions base/attribute_matcher_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -423,5 +423,33 @@ TEST(AttributeMatcher, PastFullMatch) {
_);
}

TEST(AttributeMatcher, MatchAttribute) {
AttributeMatcher matcher;
EXPECT_THAT(matcher.InsertAttribute(
Attribute("foo", {AttributeQualifier::OfString("bar"),
AttributeQualifier::OfString("baz")})),
IsOk());
EXPECT_THAT(matcher.MatchAttribute(
Attribute("foo", {AttributeQualifier::OfString("bar"),
AttributeQualifier::OfString("baz")})),
AttributeMatchIs(MatchType::FULL));
EXPECT_THAT(
matcher.MatchAttribute("foo", {AttributeQualifierView::OfString("bar"),
AttributeQualifierView::OfString("baz")}),
AttributeMatchIs(MatchType::FULL));
EXPECT_THAT(matcher.MatchAttribute(
Attribute("foo", {AttributeQualifier::OfString("bar")})),
AttributeMatchIs(MatchType::PARTIAL));
EXPECT_THAT(
matcher.MatchAttribute("foo", {AttributeQualifierView::OfString("bar")}),
AttributeMatchIs(MatchType::PARTIAL));
EXPECT_THAT(matcher.MatchAttribute(
Attribute("bar", {AttributeQualifier::OfString("baz")})),
AttributeMatchIs(MatchType::NONE));
EXPECT_THAT(
matcher.MatchAttribute("bar", {AttributeQualifierView::OfString("baz")}),
AttributeMatchIs(MatchType::NONE));
}

} // namespace
} // namespace cel
17 changes: 17 additions & 0 deletions base/attribute_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -148,5 +148,22 @@ TEST(AttributeQualifierView, TransparentOrder) {
AttributeQualifierView::OfBool(true));
}

template <typename From, typename To>
void TestAttributeQualifierConversion() {
EXPECT_EQ(To(From::OfInt(1)), To::OfInt(1));
EXPECT_EQ(To(From::OfUint(1)), To::OfUint(1));
EXPECT_EQ(To(From::OfString("foo")), To::OfString("foo"));
EXPECT_EQ(To(From::OfBool(true)), To::OfBool(true));
}

TEST(AttributeQualifier, Conversion) {
TestAttributeQualifierConversion<AttributeQualifier,
AttributeQualifierView>();
TestAttributeQualifierConversion<AttributeQualifierView,
AttributeQualifier>();
TestAttributeQualifierConversion<AttributeQualifier,
AttributeQualifierPattern>();
}

} // namespace
} // namespace cel
Loading