1 | /* |
2 | * Copyright (C) 2019 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 INCLUDE_PERFETTO_PROTOZERO_STATIC_BUFFER_H_ |
18 | #define INCLUDE_PERFETTO_PROTOZERO_STATIC_BUFFER_H_ |
19 | |
20 | #include <memory> |
21 | #include <string> |
22 | #include <vector> |
23 | |
24 | #include "perfetto/base/export.h" |
25 | #include "perfetto/protozero/root_message.h" |
26 | #include "perfetto/protozero/scattered_stream_writer.h" |
27 | |
28 | namespace protozero { |
29 | |
30 | class Message; |
31 | |
32 | // A simple implementation of ScatteredStreamWriter::Delegate backed by a |
33 | // fixed-size buffer. It doesn't support expansion. The caller needs to ensure |
34 | // to never write more than the size of the buffer. Will CHECK() otherwise. |
35 | class PERFETTO_EXPORT_COMPONENT StaticBufferDelegate |
36 | : public ScatteredStreamWriter::Delegate { |
37 | public: |
38 | StaticBufferDelegate(uint8_t* buf, size_t len) : range_{buf, buf + len} {} |
39 | ~StaticBufferDelegate() override; |
40 | |
41 | // ScatteredStreamWriter::Delegate implementation. |
42 | ContiguousMemoryRange GetNewBuffer() override; |
43 | |
44 | ContiguousMemoryRange const range_; |
45 | bool get_new_buffer_called_once_ = false; |
46 | }; |
47 | |
48 | // Helper function to create protozero messages backed by a fixed-size buffer |
49 | // in one line. You can write: |
50 | // protozero::Static<protozero::MyMessage> msg(buf.data(), buf.size()); |
51 | // msg->set_stuff(...); |
52 | // size_t bytes_encoded = msg.Finalize(); |
53 | template <typename T /* protozero::Message */> |
54 | class StaticBuffered { |
55 | public: |
56 | StaticBuffered(void* buf, size_t len) |
57 | : delegate_(reinterpret_cast<uint8_t*>(buf), len), writer_(&delegate_) { |
58 | msg_.Reset(&writer_); |
59 | } |
60 | |
61 | // This can't be neither copied nor moved because Message hands out pointers |
62 | // to itself when creating submessages. |
63 | StaticBuffered(const StaticBuffered&) = delete; |
64 | StaticBuffered& operator=(const StaticBuffered&) = delete; |
65 | StaticBuffered(StaticBuffered&&) = delete; |
66 | StaticBuffered& operator=(StaticBuffered&&) = delete; |
67 | |
68 | T* get() { return &msg_; } |
69 | T* operator->() { return &msg_; } |
70 | |
71 | // The lack of a size() method is deliberate. It's to prevent that one |
72 | // accidentally calls size() before Finalize(). |
73 | |
74 | // Returns the number of encoded bytes (<= the size passed in the ctor). |
75 | size_t Finalize() { |
76 | msg_.Finalize(); |
77 | return static_cast<size_t>(writer_.write_ptr() - delegate_.range_.begin); |
78 | } |
79 | |
80 | private: |
81 | StaticBufferDelegate delegate_; |
82 | ScatteredStreamWriter writer_; |
83 | RootMessage<T> msg_; |
84 | }; |
85 | |
86 | // Helper function to create stack-based protozero messages in one line. |
87 | // You can write: |
88 | // protozero::StackBuffered<protozero::MyMessage, 16> msg; |
89 | // msg->set_stuff(...); |
90 | // size_t bytes_encoded = msg.Finalize(); |
91 | template <typename T /* protozero::Message */, size_t N> |
92 | class StackBuffered : public StaticBuffered<T> { |
93 | public: |
94 | StackBuffered() : StaticBuffered<T>(&buf_[0], N) {} |
95 | |
96 | private: |
97 | uint8_t buf_[N]; // Deliberately not initialized. |
98 | }; |
99 | |
100 | } // namespace protozero |
101 | |
102 | #endif // INCLUDE_PERFETTO_PROTOZERO_STATIC_BUFFER_H_ |
103 | |