1
#pragma once
2

            
3
#include "source/common/common/radix_tree.h"
4
#include "source/common/matcher/map_matcher.h"
5
#include "source/common/runtime/runtime_features.h"
6

            
7
namespace Envoy {
8
namespace Matcher {
9

            
10
/**
11
 * Implementation of a trie match tree which resolves to the OnMatch with the longest matching
12
 * prefix.
13
 */
14
template <class DataType> class PrefixMapMatcher : public MapMatcher<DataType> {
15
public:
16
  static absl::StatusOr<std::unique_ptr<PrefixMapMatcher>>
17
21
  create(DataInputPtr<DataType>&& data_input, absl::optional<OnMatch<DataType>> on_no_match) {
18
21
    absl::Status creation_status = absl::OkStatus();
19
21
    auto ret = std::unique_ptr<PrefixMapMatcher<DataType>>(
20
21
        new PrefixMapMatcher<DataType>(std::move(data_input), on_no_match, creation_status));
21
21
    RETURN_IF_NOT_OK_REF(creation_status);
22
20
    return ret;
23
21
  }
24

            
25
23
  void addChild(std::string value, OnMatch<DataType>&& on_match) override {
26
23
    children_.add(value, std::make_shared<OnMatch<DataType>>(std::move(on_match)));
27
23
  }
28

            
29
protected:
30
  PrefixMapMatcher(DataInputPtr<DataType>&& data_input,
31
                   absl::optional<OnMatch<DataType>> on_no_match, absl::Status& creation_status)
32
21
      : MapMatcher<DataType>(std::move(data_input), std::move(on_no_match), creation_status) {}
33

            
34
  ActionMatchResult doMatch(const DataType& data, absl::string_view key,
35
23
                            SkippedMatchCb skipped_match_cb) override {
36
23
    const absl::InlinedVector<std::shared_ptr<OnMatch<DataType>>, 4> results =
37
23
        children_.findMatchingPrefixes(key);
38
23
    bool retry_shorter = Runtime::runtimeFeatureEnabled(
39
23
        "envoy.reloadable_features.prefix_map_matcher_resume_after_subtree_miss");
40
26
    for (auto it = results.rbegin(); it != results.rend(); ++it) {
41
20
      const std::shared_ptr<OnMatch<DataType>>& on_match = *it;
42
20
      ActionMatchResult result =
43
20
          MatchTree<DataType>::handleRecursionAndSkips(*on_match, data, skipped_match_cb);
44
20
      if (!result.isNoMatch() || !retry_shorter) {
45
        // If the match failed to complete, or if it matched, or
46
        // if we're doing the legacy "don't try additional matchers"
47
        // behavior, return whatever the first match's result was.
48
17
        return result;
49
17
      }
50
20
    }
51
6
    return this->doNoMatch(data, skipped_match_cb);
52
23
  }
53

            
54
private:
55
  RadixTree<std::shared_ptr<OnMatch<DataType>>> children_;
56
};
57

            
58
} // namespace Matcher
59
} // namespace Envoy