| /* |
| * Copyright (C) 2019 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 INCLUDE_PERFETTO_PROTOZERO_STATIC_BUFFER_H_ |
| #define INCLUDE_PERFETTO_PROTOZERO_STATIC_BUFFER_H_ |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "perfetto/base/export.h" |
| #include "perfetto/protozero/root_message.h" |
| #include "perfetto/protozero/scattered_stream_writer.h" |
| |
| namespace protozero { |
| |
| class Message; |
| |
| // A simple implementation of ScatteredStreamWriter::Delegate backed by a |
| // fixed-size buffer. It doesn't support expansion. The caller needs to ensure |
| // to never write more than the size of the buffer. Will CHECK() otherwise. |
| class PERFETTO_EXPORT_COMPONENT StaticBufferDelegate |
| : public ScatteredStreamWriter::Delegate { |
| public: |
| StaticBufferDelegate(uint8_t* buf, size_t len) : range_{buf, buf + len} {} |
| ~StaticBufferDelegate() override; |
| |
| // ScatteredStreamWriter::Delegate implementation. |
| ContiguousMemoryRange GetNewBuffer() override; |
| |
| ContiguousMemoryRange const range_; |
| bool get_new_buffer_called_once_ = false; |
| }; |
| |
| // Helper function to create protozero messages backed by a fixed-size buffer |
| // in one line. You can write: |
| // protozero::Static<protozero::MyMessage> msg(buf.data(), buf.size()); |
| // msg->set_stuff(...); |
| // size_t bytes_encoded = msg.Finalize(); |
| template <typename T /* protozero::Message */> |
| class StaticBuffered { |
| public: |
| StaticBuffered(void* buf, size_t len) |
| : delegate_(reinterpret_cast<uint8_t*>(buf), len), writer_(&delegate_) { |
| msg_.Reset(&writer_); |
| } |
| |
| // This can't be neither copied nor moved because Message hands out pointers |
| // to itself when creating submessages. |
| StaticBuffered(const StaticBuffered&) = delete; |
| StaticBuffered& operator=(const StaticBuffered&) = delete; |
| StaticBuffered(StaticBuffered&&) = delete; |
| StaticBuffered& operator=(StaticBuffered&&) = delete; |
| |
| T* get() { return &msg_; } |
| T* operator->() { return &msg_; } |
| |
| // The lack of a size() method is deliberate. It's to prevent that one |
| // accidentally calls size() before Finalize(). |
| |
| // Returns the number of encoded bytes (<= the size passed in the ctor). |
| size_t Finalize() { |
| msg_.Finalize(); |
| return static_cast<size_t>(writer_.write_ptr() - delegate_.range_.begin); |
| } |
| |
| private: |
| StaticBufferDelegate delegate_; |
| ScatteredStreamWriter writer_; |
| RootMessage<T> msg_; |
| }; |
| |
| // Helper function to create stack-based protozero messages in one line. |
| // You can write: |
| // protozero::StackBuffered<protozero::MyMessage, 16> msg; |
| // msg->set_stuff(...); |
| // size_t bytes_encoded = msg.Finalize(); |
| template <typename T /* protozero::Message */, size_t N> |
| class StackBuffered : public StaticBuffered<T> { |
| public: |
| StackBuffered() : StaticBuffered<T>(&buf_[0], N) {} |
| |
| private: |
| uint8_t buf_[N]; // Deliberately not initialized. |
| }; |
| |
| } // namespace protozero |
| |
| #endif // INCLUDE_PERFETTO_PROTOZERO_STATIC_BUFFER_H_ |