protozero/filtering: Extract MessageFilter::Config class

The MessageFilter stores the configuration of the filter and some
runtime state about the messages that are being parsed.

This commit moves all the configuration into a separate class, to make
the copy constuctor easier to maintain. Now the fields do not need to be
listed explicitly anymore.

Change-Id: I9305f50ab624ad96f57b3aac7e8da40767141e7a
diff --git a/src/protozero/filtering/message_filter.cc b/src/protozero/filtering/message_filter.cc
index 44c9851..8461938 100644
--- a/src/protozero/filtering/message_filter.cc
+++ b/src/protozero/filtering/message_filter.cc
@@ -75,19 +75,19 @@
 }
 
 MessageFilter::MessageFilter(const MessageFilter& other)
-    : root_msg_index_(other.root_msg_index_),
-      filter_(other.filter_),
-      string_filter_(other.string_filter_) {
+    : config_(other.config_) {
   stack_.emplace_back();
 }
 
 MessageFilter::~MessageFilter() = default;
 
-bool MessageFilter::LoadFilterBytecode(const void* filter_data, size_t len) {
+bool MessageFilter::Config::LoadFilterBytecode(const void* filter_data,
+                                               size_t len) {
   return filter_.Load(filter_data, len);
 }
 
-bool MessageFilter::SetFilterRoot(std::initializer_list<uint32_t> field_ids) {
+bool MessageFilter::Config::SetFilterRoot(
+    std::initializer_list<uint32_t> field_ids) {
   uint32_t root_msg_idx = 0;
   for (uint32_t field_id : field_ids) {
     auto res = filter_.Query(root_msg_idx, field_id);
@@ -123,7 +123,7 @@
   stack_[0].eat_next_bytes = UINT32_MAX;
   // stack_[1] is the actual root message.
   stack_[1].in_bytes_limit = total_len;
-  stack_[1].msg_index = root_msg_index_;
+  stack_[1].msg_index = config_.root_msg_index();
 
   // Process the input data and write the output.
   for (size_t slice_idx = 0; slice_idx < num_slices; ++slice_idx) {
@@ -163,7 +163,7 @@
     } else if (state->action == StackState::kFilterString) {
       *(out_++) = octet;
       if (state->eat_next_bytes == 0) {
-        string_filter_.MaybeFilter(
+        config_.string_filter().MaybeFilter(
             reinterpret_cast<char*>(state->filter_string_ptr),
             static_cast<size_t>(out_ - state->filter_string_ptr));
       }
@@ -174,7 +174,7 @@
     // a varint field, only the last byte yields a token, all the other bytes
     // return an invalid token, they just update the internal tokenizer state.
     if (token.valid()) {
-      auto filter = filter_.Query(state->msg_index, token.field_id);
+      auto filter = config_.filter().Query(state->msg_index, token.field_id);
       switch (token.type) {
         case proto_utils::ProtoWireType::kVarInt:
           if (filter.allowed && filter.simple_field())
diff --git a/src/protozero/filtering/message_filter.h b/src/protozero/filtering/message_filter.h
index 6daf77f..2fc09ef 100644
--- a/src/protozero/filtering/message_filter.h
+++ b/src/protozero/filtering/message_filter.h
@@ -53,6 +53,21 @@
 // intended only on host tools.
 class MessageFilter {
  public:
+  class Config {
+   public:
+    bool LoadFilterBytecode(const void* filter_data, size_t len);
+    bool SetFilterRoot(std::initializer_list<uint32_t> field_ids);
+
+    const FilterBytecodeParser& filter() const { return filter_; }
+    const StringFilter& string_filter() const { return string_filter_; }
+    StringFilter& string_filter() { return string_filter_; }
+    uint32_t root_msg_index() const { return root_msg_index_; }
+
+   private:
+    FilterBytecodeParser filter_;
+    StringFilter string_filter_;
+    uint32_t root_msg_index_ = 0;
+  };
   MessageFilter();
   explicit MessageFilter(const MessageFilter&);
   ~MessageFilter();
@@ -74,7 +89,9 @@
   // message. Must be called before the first call to FilterMessage*().
   // |filter_data| must point to a byte buffer for a proto-encoded ProtoFilter
   // message (see proto_filter.proto).
-  bool LoadFilterBytecode(const void* filter_data, size_t len);
+  bool LoadFilterBytecode(const void* filter_data, size_t len) {
+    return config_.LoadFilterBytecode(filter_data, len);
+  }
 
   // This affects the filter starting point of the subsequent FilterMessage*()
   // calls. By default the filtering process starts from the message @ index 0,
@@ -88,7 +105,9 @@
   // will identify the sub-message for the field "root.1.2.3" and use that.
   // In order for this to succeed all the fields in the path must be allowed
   // in the filter and must be a nested message type.
-  bool SetFilterRoot(std::initializer_list<uint32_t> field_ids);
+  bool SetFilterRoot(std::initializer_list<uint32_t> field_ids) {
+    return config_.SetFilterRoot(field_ids);
+  }
 
   // Takes an input message, fragmented in arbitrary slices, and returns a
   // filtered message in output.
@@ -115,11 +134,10 @@
     return field_usage_;
   }
 
-  // Exposed only for DCHECKS in TracingServiceImpl.
-  uint32_t root_msg_index() { return root_msg_index_; }
+  const Config& config() const { return config_; }
 
   // Retuns the helper class used to perform string filtering.
-  StringFilter& string_filter() { return string_filter_; }
+  StringFilter& string_filter() { return config_.string_filter(); }
 
  private:
   // This is called by FilterMessageFragments().
@@ -204,14 +222,13 @@
   uint32_t out_written() { return static_cast<uint32_t>(out_ - &out_buf_[0]); }
 
   // WARNING: Some of these fields should be in the copy constructor.
+  Config config_;
+
   std::unique_ptr<uint8_t[]> out_buf_;
   uint8_t* out_ = nullptr;
   uint8_t* out_end_ = nullptr;
-  uint32_t root_msg_index_ = 0;
 
-  FilterBytecodeParser filter_;
   MessageTokenizer tokenizer_;
-  StringFilter string_filter_;
   std::vector<StackState> stack_;
 
   bool error_ = false;
diff --git a/src/tracing/core/tracing_service_impl.cc b/src/tracing/core/tracing_service_impl.cc
index 5960a24..257accb 100644
--- a/src/tracing/core/tracing_service_impl.cc
+++ b/src/tracing/core/tracing_service_impl.cc
@@ -2402,7 +2402,7 @@
   protozero::MessageFilter& trace_filter = *tracing_session->trace_filter;
   // The filter root shoud be reset from protos.Trace to protos.TracePacket
   // by the earlier call to SetFilterRoot() in EnableTracing().
-  PERFETTO_DCHECK(trace_filter.root_msg_index() != 0);
+  PERFETTO_DCHECK(trace_filter.config().root_msg_index() != 0);
   std::vector<protozero::MessageFilter::InputSlice> filter_input;
   auto start = base::GetWallTimeNs();
   for (TracePacket& packet : *packets) {