• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_PACKED_REPEATED_FIELDS_H_
18 #define INCLUDE_PERFETTO_PROTOZERO_PACKED_REPEATED_FIELDS_H_
19 
20 #include <stdint.h>
21 
22 #include <array>
23 #include <memory>
24 #include <type_traits>
25 
26 #include "perfetto/base/logging.h"
27 #include "perfetto/protozero/proto_utils.h"
28 
29 namespace protozero {
30 
31 // This file contains classes used when encoding packed repeated fields.
32 // To encode such a field, the caller is first expected to accumulate all of the
33 // values in one of the following types (depending on the wire type of the
34 // individual elements), defined below:
35 // * protozero::PackedVarInt
36 // * protozero::PackedFixedSizeInt</*element_type=*/ uint32_t>
37 // Then that buffer is passed to the protozero-generated setters as an argument.
38 // After calling the setter, the buffer can be destroyed.
39 //
40 // An example of encoding a packed field:
41 //   protozero::HeapBuffered<protozero::Message> msg;
42 //   protozero::PackedVarInt buf;
43 //   buf.Append(42);
44 //   buf.Append(-1);
45 //   msg->set_fieldname(buf);
46 //   msg.SerializeAsString();
47 
48 class PackedBufferBase {
49  public:
PackedBufferBase()50   PackedBufferBase() { Reset(); }
51 
52   // Copy or move is disabled due to pointers to stack addresses.
53   PackedBufferBase(const PackedBufferBase&) = delete;
54   PackedBufferBase(PackedBufferBase&&) = delete;
55   PackedBufferBase& operator=(const PackedBufferBase&) = delete;
56   PackedBufferBase& operator=(PackedBufferBase&&) = delete;
57 
58   void Reset();
59 
data()60   const uint8_t* data() const { return storage_begin_; }
61 
size()62   size_t size() const {
63     return static_cast<size_t>(write_ptr_ - storage_begin_);
64   }
65 
66  protected:
GrowIfNeeded()67   void GrowIfNeeded() {
68     PERFETTO_DCHECK(write_ptr_ >= storage_begin_ && write_ptr_ <= storage_end_);
69     if (PERFETTO_UNLIKELY(write_ptr_ + kMaxElementSize > storage_end_)) {
70       GrowSlowpath();
71     }
72   }
73 
74   void GrowSlowpath();
75 
76   // max(uint64_t varint encoding, biggest fixed type (uint64)).
77   static constexpr size_t kMaxElementSize = 10;
78 
79   // So sizeof(this) == 8k.
80   static constexpr size_t kOnStackStorageSize = 8192 - 32;
81 
82   uint8_t* storage_begin_;
83   uint8_t* storage_end_;
84   uint8_t* write_ptr_;
85   std::unique_ptr<uint8_t[]> heap_buf_;
86   alignas(uint64_t) uint8_t stack_buf_[kOnStackStorageSize];
87 };
88 
89 class PackedVarInt : public PackedBufferBase {
90  public:
91   template <typename T>
Append(T value)92   void Append(T value) {
93     GrowIfNeeded();
94     write_ptr_ = proto_utils::WriteVarInt(value, write_ptr_);
95   }
96 };
97 
98 template <typename T /* e.g. uint32_t for Fixed32 */>
99 class PackedFixedSizeInt : public PackedBufferBase {
100  public:
Append(T value)101   void Append(T value) {
102     static_assert(sizeof(T) == 4 || sizeof(T) == 8,
103                   "PackedFixedSizeInt should be used only with 32/64-bit ints");
104     static_assert(sizeof(T) <= kMaxElementSize,
105                   "kMaxElementSize needs to be updated");
106     GrowIfNeeded();
107     PERFETTO_DCHECK(reinterpret_cast<size_t>(write_ptr_) % alignof(T) == 0);
108     memcpy(reinterpret_cast<T*>(write_ptr_), &value, sizeof(T));
109     write_ptr_ += sizeof(T);
110   }
111 };
112 
113 }  // namespace protozero
114 
115 #endif  // INCLUDE_PERFETTO_PROTOZERO_PACKED_REPEATED_FIELDS_H_
116