Introduce DebugAnnotationParser

Refactor the debug annotation parsing logic into a standalone class,
which later will be used to parse debug annotations for console
interceptor.

R=eseckler@google.com,lalitm@google.com

Change-Id: I6b53706c4b63d455f4df1600b30029b02cc92139
diff --git a/src/trace_processor/util/trace_blob_view.h b/src/trace_processor/util/trace_blob_view.h
new file mode 100644
index 0000000..7d9c1a4
--- /dev/null
+++ b/src/trace_processor/util/trace_blob_view.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_UTIL_TRACE_BLOB_VIEW_H_
+#define SRC_TRACE_PROCESSOR_UTIL_TRACE_BLOB_VIEW_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <limits>
+#include <memory>
+
+#include "perfetto/base/logging.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+// This class is an equivalent of std::string_view for trace binary data.
+// The main difference is that this class has also shared ownership of a portion
+// of the raw trace.
+// The underlying buffer will be freed once all the TraceBlobViews that refer
+// to the same buffer have passed through the pipeline and been parsed.
+class TraceBlobView {
+ public:
+  TraceBlobView(std::unique_ptr<uint8_t[]> buffer, size_t offset, size_t length)
+      : shbuf_(SharedBuf(std::move(buffer))),
+        offset_(static_cast<uint32_t>(offset)),
+        length_(static_cast<uint32_t>(length)) {
+    PERFETTO_DCHECK(offset <= std::numeric_limits<uint32_t>::max());
+    PERFETTO_DCHECK(length <= std::numeric_limits<uint32_t>::max());
+  }
+
+  // Allow std::move().
+  TraceBlobView(TraceBlobView&&) noexcept = default;
+  TraceBlobView& operator=(TraceBlobView&&) = default;
+
+  // Disable implicit copy.
+  TraceBlobView(const TraceBlobView&) = delete;
+  TraceBlobView& operator=(const TraceBlobView&) = delete;
+
+  TraceBlobView slice(size_t offset, size_t length) const {
+    PERFETTO_DCHECK(offset + length <= offset_ + length_);
+    return TraceBlobView(shbuf_, offset, length);
+  }
+
+  bool operator==(const TraceBlobView& rhs) const {
+    return (shbuf_ == rhs.shbuf_) && (offset_ == rhs.offset_) &&
+           (length_ == rhs.length_);
+  }
+  bool operator!=(const TraceBlobView& rhs) const { return !(*this == rhs); }
+
+  inline const uint8_t* data() const { return start() + offset_; }
+
+  size_t offset_of(const uint8_t* data) const {
+    // When a field is size 0, data can be equal to start() + offset_ + length_.
+    PERFETTO_DCHECK(data >= start() && data <= (start() + offset_ + length_));
+    return static_cast<size_t>(data - start());
+  }
+
+  size_t length() const { return length_; }
+  size_t offset() const { return offset_; }
+
+ private:
+  // An equivalent to std::shared_ptr<uint8_t>, with the differnce that:
+  // - Supports array types, available for shared_ptr only in C++17.
+  // - Is not thread safe, which is not needed for our purposes.
+  class SharedBuf {
+   public:
+    explicit SharedBuf(std::unique_ptr<uint8_t[]> mem) {
+      rcbuf_ = new RefCountedBuf(std::move(mem));
+    }
+
+    SharedBuf(const SharedBuf& copy) : rcbuf_(copy.rcbuf_) {
+      PERFETTO_DCHECK(rcbuf_->refcount > 0);
+      rcbuf_->refcount++;
+    }
+
+    ~SharedBuf() {
+      if (!rcbuf_)
+        return;
+      PERFETTO_DCHECK(rcbuf_->refcount > 0);
+      if (--rcbuf_->refcount == 0) {
+        RefCountedBuf* rcbuf = rcbuf_;
+        rcbuf_ = nullptr;
+        delete rcbuf;
+      }
+    }
+
+    SharedBuf(SharedBuf&& other) noexcept {
+      rcbuf_ = other.rcbuf_;
+      other.rcbuf_ = nullptr;
+    }
+
+    SharedBuf& operator=(SharedBuf&& other) {
+      if (this != &other) {
+        // A bit of a ugly but pragmatic pattern to implement move assignment.
+        // First invoke the distructor and then invoke the move constructor
+        // inline via placement-new.
+        this->~SharedBuf();
+        new (this) SharedBuf(std::move(other));
+      }
+      return *this;
+    }
+
+    bool operator==(const SharedBuf& x) const { return x.rcbuf_ == rcbuf_; }
+    bool operator!=(const SharedBuf& x) const { return !(x == *this); }
+    const uint8_t* data() const { return rcbuf_->mem.get(); }
+
+   private:
+    struct RefCountedBuf {
+      explicit RefCountedBuf(std::unique_ptr<uint8_t[]> buf)
+          : refcount(1), mem(std::move(buf)) {}
+      int refcount;
+      std::unique_ptr<uint8_t[]> mem;
+    };
+
+    RefCountedBuf* rcbuf_ = nullptr;
+  };
+
+  inline const uint8_t* start() const { return shbuf_.data(); }
+
+  TraceBlobView(SharedBuf b, size_t o, size_t l)
+      : shbuf_(b),
+        offset_(static_cast<uint32_t>(o)),
+        length_(static_cast<uint32_t>(l)) {}
+
+  SharedBuf shbuf_;
+  uint32_t offset_;
+  uint32_t length_;  // Measured from |offset_|, not from |data()|.
+};
+
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_UTIL_TRACE_BLOB_VIEW_H_