1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef SRC_TRACE_PROCESSOR_TRACE_BLOB_VIEW_H_ 18 #define SRC_TRACE_PROCESSOR_TRACE_BLOB_VIEW_H_ 19 20 #include <stddef.h> 21 #include <stdint.h> 22 23 #include <limits> 24 #include <memory> 25 26 #include "perfetto/base/logging.h" 27 28 namespace perfetto { 29 namespace trace_processor { 30 31 // This class is an equivalent of std::string_view for trace binary data. 32 // The main difference is that this class has also shared ownership of a portion 33 // of the raw trace. 34 // The underlying buffer will be freed once all the TraceBlobViews that refer 35 // to the same buffer have passed through the pipeline and been parsed. 36 class TraceBlobView { 37 public: 38 TraceBlobView(std::unique_ptr<uint8_t[]> buffer, size_t offset, size_t length) 39 : shbuf_(SharedBuf(std::move(buffer))), 40 offset_(static_cast<uint32_t>(offset)), 41 length_(static_cast<uint32_t>(length)) { 42 PERFETTO_DCHECK(offset <= std::numeric_limits<uint32_t>::max()); 43 PERFETTO_DCHECK(length <= std::numeric_limits<uint32_t>::max()); 44 } 45 46 // Allow std::move(). 47 TraceBlobView(TraceBlobView&&) noexcept = default; 48 TraceBlobView& operator=(TraceBlobView&&) = default; 49 50 // Disable implicit copy. 51 TraceBlobView(const TraceBlobView&) = delete; 52 TraceBlobView& operator=(const TraceBlobView&) = delete; 53 54 TraceBlobView slice(size_t offset, size_t length) { 55 PERFETTO_DCHECK(offset + length <= offset_ + length_); 56 return TraceBlobView(shbuf_, offset, length); 57 } 58 59 bool operator==(const TraceBlobView& rhs) const { 60 return (shbuf_ == rhs.shbuf_) && (offset_ == rhs.offset_) && 61 (length_ == rhs.length_); 62 } 63 bool operator!=(const TraceBlobView& rhs) const { return !(*this == rhs); } 64 65 inline const uint8_t* data() const { return start() + offset_; } 66 67 size_t offset_of(const uint8_t* data) const { 68 // When a field is size 0, data can be equal to start() + offset_ + length_. 69 PERFETTO_DCHECK(data >= start() && data <= (start() + offset_ + length_)); 70 return static_cast<size_t>(data - start()); 71 } 72 73 size_t length() const { return length_; } 74 size_t offset() const { return offset_; } 75 76 private: 77 // An equivalent to std::shared_ptr<uint8_t>, with the differnce that: 78 // - Supports array types, available for shared_ptr only in C++17. 79 // - Is not thread safe, which is not needed for our purposes. 80 class SharedBuf { 81 public: 82 explicit SharedBuf(std::unique_ptr<uint8_t[]> mem) { 83 rcbuf_ = new RefCountedBuf(std::move(mem)); 84 } 85 86 SharedBuf(const SharedBuf& copy) : rcbuf_(copy.rcbuf_) { 87 PERFETTO_DCHECK(rcbuf_->refcount > 0); 88 rcbuf_->refcount++; 89 } 90 91 ~SharedBuf() { 92 if (!rcbuf_) 93 return; 94 PERFETTO_DCHECK(rcbuf_->refcount > 0); 95 if (--rcbuf_->refcount == 0) { 96 RefCountedBuf* rcbuf = rcbuf_; 97 rcbuf_ = nullptr; 98 delete rcbuf; 99 } 100 } 101 102 SharedBuf(SharedBuf&& other) noexcept { 103 rcbuf_ = other.rcbuf_; 104 other.rcbuf_ = nullptr; 105 } 106 107 SharedBuf& operator=(SharedBuf&& other) { 108 if (this != &other) { 109 // A bit of a ugly but pragmatic pattern to implement move assignment. 110 // First invoke the distructor and then invoke the move constructor 111 // inline via placement-new. 112 this->~SharedBuf(); 113 new (this) SharedBuf(std::move(other)); 114 } 115 return *this; 116 } 117 118 bool operator==(const SharedBuf& x) const { return x.rcbuf_ == rcbuf_; } 119 bool operator!=(const SharedBuf& x) const { return !(x == *this); } 120 const uint8_t* data() const { return rcbuf_->mem.get(); } 121 122 private: 123 struct RefCountedBuf { 124 explicit RefCountedBuf(std::unique_ptr<uint8_t[]> buf) 125 : refcount(1), mem(std::move(buf)) {} 126 int refcount; 127 std::unique_ptr<uint8_t[]> mem; 128 }; 129 130 RefCountedBuf* rcbuf_ = nullptr; 131 }; 132 133 inline const uint8_t* start() const { return shbuf_.data(); } 134 135 TraceBlobView(SharedBuf b, size_t o, size_t l) 136 : shbuf_(b), 137 offset_(static_cast<uint32_t>(o)), 138 length_(static_cast<uint32_t>(l)) {} 139 140 SharedBuf shbuf_; 141 uint32_t offset_; 142 uint32_t length_; // Measured from |offset_|, not from |data()|. 143 }; 144 145 } // namespace trace_processor 146 } // namespace perfetto 147 148 #endif // SRC_TRACE_PROCESSOR_TRACE_BLOB_VIEW_H_ 149