xref: /aosp_15_r20/external/perfetto/src/protozero/proto_decoder.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker  *
4*6dbdd20aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker  *
8*6dbdd20aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker  *
10*6dbdd20aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker  * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker  */
16*6dbdd20aSAndroid Build Coastguard Worker 
17*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/protozero/proto_decoder.h"
18*6dbdd20aSAndroid Build Coastguard Worker 
19*6dbdd20aSAndroid Build Coastguard Worker #include <string.h>
20*6dbdd20aSAndroid Build Coastguard Worker 
21*6dbdd20aSAndroid Build Coastguard Worker #include <cinttypes>
22*6dbdd20aSAndroid Build Coastguard Worker #include <limits>
23*6dbdd20aSAndroid Build Coastguard Worker #include <memory>
24*6dbdd20aSAndroid Build Coastguard Worker 
25*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/compiler.h"
26*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/logging.h"
27*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/utils.h"
28*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/protozero/proto_utils.h"
29*6dbdd20aSAndroid Build Coastguard Worker 
30*6dbdd20aSAndroid Build Coastguard Worker namespace protozero {
31*6dbdd20aSAndroid Build Coastguard Worker 
32*6dbdd20aSAndroid Build Coastguard Worker using namespace proto_utils;
33*6dbdd20aSAndroid Build Coastguard Worker 
34*6dbdd20aSAndroid Build Coastguard Worker #if !PERFETTO_IS_LITTLE_ENDIAN()
35*6dbdd20aSAndroid Build Coastguard Worker #error Unimplemented for big endian archs.
36*6dbdd20aSAndroid Build Coastguard Worker #endif
37*6dbdd20aSAndroid Build Coastguard Worker 
38*6dbdd20aSAndroid Build Coastguard Worker namespace {
39*6dbdd20aSAndroid Build Coastguard Worker 
40*6dbdd20aSAndroid Build Coastguard Worker struct ParseFieldResult {
41*6dbdd20aSAndroid Build Coastguard Worker   enum ParseResult { kAbort, kSkip, kOk };
42*6dbdd20aSAndroid Build Coastguard Worker   ParseResult parse_res;
43*6dbdd20aSAndroid Build Coastguard Worker   const uint8_t* next;
44*6dbdd20aSAndroid Build Coastguard Worker   Field field;
45*6dbdd20aSAndroid Build Coastguard Worker };
46*6dbdd20aSAndroid Build Coastguard Worker 
47*6dbdd20aSAndroid Build Coastguard Worker // Parses one field and returns the field itself and a pointer to the next
48*6dbdd20aSAndroid Build Coastguard Worker // field to parse. If parsing fails, the returned |next| == |buffer|.
ParseOneField(const uint8_t * const buffer,const uint8_t * const end)49*6dbdd20aSAndroid Build Coastguard Worker ParseFieldResult ParseOneField(const uint8_t* const buffer,
50*6dbdd20aSAndroid Build Coastguard Worker                                const uint8_t* const end) {
51*6dbdd20aSAndroid Build Coastguard Worker   ParseFieldResult res{ParseFieldResult::kAbort, buffer, Field{}};
52*6dbdd20aSAndroid Build Coastguard Worker 
53*6dbdd20aSAndroid Build Coastguard Worker   // The first byte of a proto field is structured as follows:
54*6dbdd20aSAndroid Build Coastguard Worker   // The least 3 significant bits determine the field type.
55*6dbdd20aSAndroid Build Coastguard Worker   // The most 5 significant bits determine the field id. If MSB == 1, the
56*6dbdd20aSAndroid Build Coastguard Worker   // field id continues on the next bytes following the VarInt encoding.
57*6dbdd20aSAndroid Build Coastguard Worker   const uint8_t kFieldTypeNumBits = 3;
58*6dbdd20aSAndroid Build Coastguard Worker   const uint64_t kFieldTypeMask = (1 << kFieldTypeNumBits) - 1;  // 0000 0111;
59*6dbdd20aSAndroid Build Coastguard Worker   const uint8_t* pos = buffer;
60*6dbdd20aSAndroid Build Coastguard Worker 
61*6dbdd20aSAndroid Build Coastguard Worker   // If we've already hit the end, just return an invalid field.
62*6dbdd20aSAndroid Build Coastguard Worker   if (PERFETTO_UNLIKELY(pos >= end))
63*6dbdd20aSAndroid Build Coastguard Worker     return res;
64*6dbdd20aSAndroid Build Coastguard Worker 
65*6dbdd20aSAndroid Build Coastguard Worker   uint64_t preamble = 0;
66*6dbdd20aSAndroid Build Coastguard Worker   if (PERFETTO_LIKELY(*pos < 0x80)) {  // Fastpath for fields with ID < 16.
67*6dbdd20aSAndroid Build Coastguard Worker     preamble = *(pos++);
68*6dbdd20aSAndroid Build Coastguard Worker   } else {
69*6dbdd20aSAndroid Build Coastguard Worker     const uint8_t* next = ParseVarInt(pos, end, &preamble);
70*6dbdd20aSAndroid Build Coastguard Worker     if (PERFETTO_UNLIKELY(pos == next))
71*6dbdd20aSAndroid Build Coastguard Worker       return res;
72*6dbdd20aSAndroid Build Coastguard Worker     pos = next;
73*6dbdd20aSAndroid Build Coastguard Worker   }
74*6dbdd20aSAndroid Build Coastguard Worker 
75*6dbdd20aSAndroid Build Coastguard Worker   uint32_t field_id = static_cast<uint32_t>(preamble >> kFieldTypeNumBits);
76*6dbdd20aSAndroid Build Coastguard Worker   if (field_id == 0 || pos >= end)
77*6dbdd20aSAndroid Build Coastguard Worker     return res;
78*6dbdd20aSAndroid Build Coastguard Worker 
79*6dbdd20aSAndroid Build Coastguard Worker   auto field_type = static_cast<uint8_t>(preamble & kFieldTypeMask);
80*6dbdd20aSAndroid Build Coastguard Worker   const uint8_t* new_pos = pos;
81*6dbdd20aSAndroid Build Coastguard Worker   uint64_t int_value = 0;
82*6dbdd20aSAndroid Build Coastguard Worker   uint64_t size = 0;
83*6dbdd20aSAndroid Build Coastguard Worker 
84*6dbdd20aSAndroid Build Coastguard Worker   switch (field_type) {
85*6dbdd20aSAndroid Build Coastguard Worker     case static_cast<uint8_t>(ProtoWireType::kVarInt): {
86*6dbdd20aSAndroid Build Coastguard Worker       new_pos = ParseVarInt(pos, end, &int_value);
87*6dbdd20aSAndroid Build Coastguard Worker 
88*6dbdd20aSAndroid Build Coastguard Worker       // new_pos not being greater than pos means ParseVarInt could not fully
89*6dbdd20aSAndroid Build Coastguard Worker       // parse the number. This is because we are out of space in the buffer.
90*6dbdd20aSAndroid Build Coastguard Worker       // Set the id to zero and return but don't update the offset so a future
91*6dbdd20aSAndroid Build Coastguard Worker       // read can read this field.
92*6dbdd20aSAndroid Build Coastguard Worker       if (PERFETTO_UNLIKELY(new_pos == pos))
93*6dbdd20aSAndroid Build Coastguard Worker         return res;
94*6dbdd20aSAndroid Build Coastguard Worker 
95*6dbdd20aSAndroid Build Coastguard Worker       break;
96*6dbdd20aSAndroid Build Coastguard Worker     }
97*6dbdd20aSAndroid Build Coastguard Worker 
98*6dbdd20aSAndroid Build Coastguard Worker     case static_cast<uint8_t>(ProtoWireType::kLengthDelimited): {
99*6dbdd20aSAndroid Build Coastguard Worker       uint64_t payload_length;
100*6dbdd20aSAndroid Build Coastguard Worker       new_pos = ParseVarInt(pos, end, &payload_length);
101*6dbdd20aSAndroid Build Coastguard Worker       if (PERFETTO_UNLIKELY(new_pos == pos))
102*6dbdd20aSAndroid Build Coastguard Worker         return res;
103*6dbdd20aSAndroid Build Coastguard Worker 
104*6dbdd20aSAndroid Build Coastguard Worker       // ParseVarInt guarantees that |new_pos| <= |end| when it succeeds;
105*6dbdd20aSAndroid Build Coastguard Worker       if (payload_length > static_cast<uint64_t>(end - new_pos))
106*6dbdd20aSAndroid Build Coastguard Worker         return res;
107*6dbdd20aSAndroid Build Coastguard Worker 
108*6dbdd20aSAndroid Build Coastguard Worker       const uintptr_t payload_start = reinterpret_cast<uintptr_t>(new_pos);
109*6dbdd20aSAndroid Build Coastguard Worker       int_value = payload_start;
110*6dbdd20aSAndroid Build Coastguard Worker       size = payload_length;
111*6dbdd20aSAndroid Build Coastguard Worker       new_pos += payload_length;
112*6dbdd20aSAndroid Build Coastguard Worker       break;
113*6dbdd20aSAndroid Build Coastguard Worker     }
114*6dbdd20aSAndroid Build Coastguard Worker 
115*6dbdd20aSAndroid Build Coastguard Worker     case static_cast<uint8_t>(ProtoWireType::kFixed64): {
116*6dbdd20aSAndroid Build Coastguard Worker       new_pos = pos + sizeof(uint64_t);
117*6dbdd20aSAndroid Build Coastguard Worker       if (PERFETTO_UNLIKELY(new_pos > end))
118*6dbdd20aSAndroid Build Coastguard Worker         return res;
119*6dbdd20aSAndroid Build Coastguard Worker       memcpy(&int_value, pos, sizeof(uint64_t));
120*6dbdd20aSAndroid Build Coastguard Worker       break;
121*6dbdd20aSAndroid Build Coastguard Worker     }
122*6dbdd20aSAndroid Build Coastguard Worker 
123*6dbdd20aSAndroid Build Coastguard Worker     case static_cast<uint8_t>(ProtoWireType::kFixed32): {
124*6dbdd20aSAndroid Build Coastguard Worker       new_pos = pos + sizeof(uint32_t);
125*6dbdd20aSAndroid Build Coastguard Worker       if (PERFETTO_UNLIKELY(new_pos > end))
126*6dbdd20aSAndroid Build Coastguard Worker         return res;
127*6dbdd20aSAndroid Build Coastguard Worker       memcpy(&int_value, pos, sizeof(uint32_t));
128*6dbdd20aSAndroid Build Coastguard Worker       break;
129*6dbdd20aSAndroid Build Coastguard Worker     }
130*6dbdd20aSAndroid Build Coastguard Worker 
131*6dbdd20aSAndroid Build Coastguard Worker     default:
132*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_DLOG("Invalid proto field type: %u", field_type);
133*6dbdd20aSAndroid Build Coastguard Worker       return res;
134*6dbdd20aSAndroid Build Coastguard Worker   }
135*6dbdd20aSAndroid Build Coastguard Worker 
136*6dbdd20aSAndroid Build Coastguard Worker   res.next = new_pos;
137*6dbdd20aSAndroid Build Coastguard Worker 
138*6dbdd20aSAndroid Build Coastguard Worker   if (PERFETTO_UNLIKELY(field_id > Field::kMaxId)) {
139*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_DLOG("Skipping field %" PRIu32 " because its id > %" PRIu32,
140*6dbdd20aSAndroid Build Coastguard Worker                   field_id, Field::kMaxId);
141*6dbdd20aSAndroid Build Coastguard Worker     res.parse_res = ParseFieldResult::kSkip;
142*6dbdd20aSAndroid Build Coastguard Worker     return res;
143*6dbdd20aSAndroid Build Coastguard Worker   }
144*6dbdd20aSAndroid Build Coastguard Worker 
145*6dbdd20aSAndroid Build Coastguard Worker   if (PERFETTO_UNLIKELY(size > proto_utils::kMaxMessageLength)) {
146*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_DLOG("Skipping field %" PRIu32 " because it's too big (%" PRIu64
147*6dbdd20aSAndroid Build Coastguard Worker                   " KB)",
148*6dbdd20aSAndroid Build Coastguard Worker                   field_id, size / 1024);
149*6dbdd20aSAndroid Build Coastguard Worker     res.parse_res = ParseFieldResult::kSkip;
150*6dbdd20aSAndroid Build Coastguard Worker     return res;
151*6dbdd20aSAndroid Build Coastguard Worker   }
152*6dbdd20aSAndroid Build Coastguard Worker 
153*6dbdd20aSAndroid Build Coastguard Worker   res.parse_res = ParseFieldResult::kOk;
154*6dbdd20aSAndroid Build Coastguard Worker   res.field.initialize(field_id, field_type, int_value,
155*6dbdd20aSAndroid Build Coastguard Worker                        static_cast<uint32_t>(size));
156*6dbdd20aSAndroid Build Coastguard Worker   return res;
157*6dbdd20aSAndroid Build Coastguard Worker }
158*6dbdd20aSAndroid Build Coastguard Worker 
159*6dbdd20aSAndroid Build Coastguard Worker }  // namespace
160*6dbdd20aSAndroid Build Coastguard Worker 
FindField(uint32_t field_id)161*6dbdd20aSAndroid Build Coastguard Worker Field ProtoDecoder::FindField(uint32_t field_id) {
162*6dbdd20aSAndroid Build Coastguard Worker   Field res{};
163*6dbdd20aSAndroid Build Coastguard Worker   auto old_position = read_ptr_;
164*6dbdd20aSAndroid Build Coastguard Worker   read_ptr_ = begin_;
165*6dbdd20aSAndroid Build Coastguard Worker   for (auto f = ReadField(); f.valid(); f = ReadField()) {
166*6dbdd20aSAndroid Build Coastguard Worker     if (f.id() == field_id) {
167*6dbdd20aSAndroid Build Coastguard Worker       res = f;
168*6dbdd20aSAndroid Build Coastguard Worker       break;
169*6dbdd20aSAndroid Build Coastguard Worker     }
170*6dbdd20aSAndroid Build Coastguard Worker   }
171*6dbdd20aSAndroid Build Coastguard Worker   read_ptr_ = old_position;
172*6dbdd20aSAndroid Build Coastguard Worker   return res;
173*6dbdd20aSAndroid Build Coastguard Worker }
174*6dbdd20aSAndroid Build Coastguard Worker 
ReadField()175*6dbdd20aSAndroid Build Coastguard Worker Field ProtoDecoder::ReadField() {
176*6dbdd20aSAndroid Build Coastguard Worker   ParseFieldResult res;
177*6dbdd20aSAndroid Build Coastguard Worker   do {
178*6dbdd20aSAndroid Build Coastguard Worker     res = ParseOneField(read_ptr_, end_);
179*6dbdd20aSAndroid Build Coastguard Worker     read_ptr_ = res.next;
180*6dbdd20aSAndroid Build Coastguard Worker   } while (PERFETTO_UNLIKELY(res.parse_res == ParseFieldResult::kSkip));
181*6dbdd20aSAndroid Build Coastguard Worker   return res.field;
182*6dbdd20aSAndroid Build Coastguard Worker }
183*6dbdd20aSAndroid Build Coastguard Worker 
ParseAllFields()184*6dbdd20aSAndroid Build Coastguard Worker void TypedProtoDecoderBase::ParseAllFields() {
185*6dbdd20aSAndroid Build Coastguard Worker   const uint8_t* cur = begin_;
186*6dbdd20aSAndroid Build Coastguard Worker   ParseFieldResult res;
187*6dbdd20aSAndroid Build Coastguard Worker   for (;;) {
188*6dbdd20aSAndroid Build Coastguard Worker     res = ParseOneField(cur, end_);
189*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_DCHECK(res.parse_res != ParseFieldResult::kOk || res.next != cur);
190*6dbdd20aSAndroid Build Coastguard Worker     cur = res.next;
191*6dbdd20aSAndroid Build Coastguard Worker     if (PERFETTO_UNLIKELY(res.parse_res == ParseFieldResult::kSkip))
192*6dbdd20aSAndroid Build Coastguard Worker       continue;
193*6dbdd20aSAndroid Build Coastguard Worker     if (PERFETTO_UNLIKELY(res.parse_res == ParseFieldResult::kAbort))
194*6dbdd20aSAndroid Build Coastguard Worker       break;
195*6dbdd20aSAndroid Build Coastguard Worker 
196*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_DCHECK(res.parse_res == ParseFieldResult::kOk);
197*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_DCHECK(res.field.valid());
198*6dbdd20aSAndroid Build Coastguard Worker     auto field_id = res.field.id();
199*6dbdd20aSAndroid Build Coastguard Worker     if (PERFETTO_UNLIKELY(field_id >= num_fields_))
200*6dbdd20aSAndroid Build Coastguard Worker       continue;
201*6dbdd20aSAndroid Build Coastguard Worker 
202*6dbdd20aSAndroid Build Coastguard Worker     // There are two reasons why we might want to expand the heap capacity:
203*6dbdd20aSAndroid Build Coastguard Worker     // 1. We are writing a non-repeated field, which has an id >
204*6dbdd20aSAndroid Build Coastguard Worker     //    INITIAL_STACK_CAPACITY. In this case ExpandHeapStorage() ensures to
205*6dbdd20aSAndroid Build Coastguard Worker     //    allocate at least (num_fields_ + 1) slots.
206*6dbdd20aSAndroid Build Coastguard Worker     // 2. We are writing a repeated field but ran out of capacity.
207*6dbdd20aSAndroid Build Coastguard Worker     if (PERFETTO_UNLIKELY(field_id >= size_ || size_ >= capacity_))
208*6dbdd20aSAndroid Build Coastguard Worker       ExpandHeapStorage();
209*6dbdd20aSAndroid Build Coastguard Worker 
210*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_DCHECK(field_id < size_);
211*6dbdd20aSAndroid Build Coastguard Worker     Field* fld = &fields_[field_id];
212*6dbdd20aSAndroid Build Coastguard Worker     if (PERFETTO_LIKELY(!fld->valid())) {
213*6dbdd20aSAndroid Build Coastguard Worker       // This is the first time we see this field.
214*6dbdd20aSAndroid Build Coastguard Worker       *fld = std::move(res.field);
215*6dbdd20aSAndroid Build Coastguard Worker     } else {
216*6dbdd20aSAndroid Build Coastguard Worker       // Repeated field case.
217*6dbdd20aSAndroid Build Coastguard Worker       // In this case we need to:
218*6dbdd20aSAndroid Build Coastguard Worker       // 1. Append the last value of the field to end of the repeated field
219*6dbdd20aSAndroid Build Coastguard Worker       //    storage.
220*6dbdd20aSAndroid Build Coastguard Worker       // 2. Replace the default instance at offset |field_id| with the current
221*6dbdd20aSAndroid Build Coastguard Worker       //    value. This is because in case of repeated field a call to Get(X) is
222*6dbdd20aSAndroid Build Coastguard Worker       //    supposed to return the last value of X, not the first one.
223*6dbdd20aSAndroid Build Coastguard Worker       // This is so that the RepeatedFieldIterator will iterate in the right
224*6dbdd20aSAndroid Build Coastguard Worker       // order, see comments on RepeatedFieldIterator.
225*6dbdd20aSAndroid Build Coastguard Worker       if (num_fields_ > size_) {
226*6dbdd20aSAndroid Build Coastguard Worker         ExpandHeapStorage();
227*6dbdd20aSAndroid Build Coastguard Worker         fld = &fields_[field_id];
228*6dbdd20aSAndroid Build Coastguard Worker       }
229*6dbdd20aSAndroid Build Coastguard Worker 
230*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_DCHECK(size_ < capacity_);
231*6dbdd20aSAndroid Build Coastguard Worker       fields_[size_++] = *fld;
232*6dbdd20aSAndroid Build Coastguard Worker       *fld = std::move(res.field);
233*6dbdd20aSAndroid Build Coastguard Worker     }
234*6dbdd20aSAndroid Build Coastguard Worker   }
235*6dbdd20aSAndroid Build Coastguard Worker   read_ptr_ = res.next;
236*6dbdd20aSAndroid Build Coastguard Worker }
237*6dbdd20aSAndroid Build Coastguard Worker 
ExpandHeapStorage()238*6dbdd20aSAndroid Build Coastguard Worker void TypedProtoDecoderBase::ExpandHeapStorage() {
239*6dbdd20aSAndroid Build Coastguard Worker   // When we expand the heap we must ensure that we have at very last capacity
240*6dbdd20aSAndroid Build Coastguard Worker   // to deal with all known fields plus at least one repeated field. We go +2048
241*6dbdd20aSAndroid Build Coastguard Worker   // here based on observations on a large 4GB android trace. This is to avoid
242*6dbdd20aSAndroid Build Coastguard Worker   // trivial re-allocations when dealing with repeated fields of a message that
243*6dbdd20aSAndroid Build Coastguard Worker   // has > INITIAL_STACK_CAPACITY fields.
244*6dbdd20aSAndroid Build Coastguard Worker   const uint32_t min_capacity = num_fields_ + 2048;  // Any num >= +1 will do.
245*6dbdd20aSAndroid Build Coastguard Worker   const uint32_t new_capacity = std::max(capacity_ * 2, min_capacity);
246*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_CHECK(new_capacity > size_ && new_capacity > num_fields_);
247*6dbdd20aSAndroid Build Coastguard Worker   std::unique_ptr<Field[]> new_storage(new Field[new_capacity]);
248*6dbdd20aSAndroid Build Coastguard Worker 
249*6dbdd20aSAndroid Build Coastguard Worker   static_assert(std::is_trivially_constructible<Field>::value,
250*6dbdd20aSAndroid Build Coastguard Worker                 "Field must be trivially constructible");
251*6dbdd20aSAndroid Build Coastguard Worker   static_assert(std::is_trivially_copyable<Field>::value,
252*6dbdd20aSAndroid Build Coastguard Worker                 "Field must be trivially copyable");
253*6dbdd20aSAndroid Build Coastguard Worker 
254*6dbdd20aSAndroid Build Coastguard Worker   // Zero-initialize the slots for known field IDs slots, as they can be
255*6dbdd20aSAndroid Build Coastguard Worker   // randomly accessed. Instead, there is no need to initialize the repeated
256*6dbdd20aSAndroid Build Coastguard Worker   // slots, because they are written linearly with no gaps and are always
257*6dbdd20aSAndroid Build Coastguard Worker   // initialized before incrementing |size_|.
258*6dbdd20aSAndroid Build Coastguard Worker   const uint32_t new_size = std::max(size_, num_fields_);
259*6dbdd20aSAndroid Build Coastguard Worker   memset(&new_storage[size_], 0, sizeof(Field) * (new_size - size_));
260*6dbdd20aSAndroid Build Coastguard Worker 
261*6dbdd20aSAndroid Build Coastguard Worker   memcpy(&new_storage[0], fields_, sizeof(Field) * size_);
262*6dbdd20aSAndroid Build Coastguard Worker 
263*6dbdd20aSAndroid Build Coastguard Worker   heap_storage_ = std::move(new_storage);
264*6dbdd20aSAndroid Build Coastguard Worker   fields_ = &heap_storage_[0];
265*6dbdd20aSAndroid Build Coastguard Worker   capacity_ = new_capacity;
266*6dbdd20aSAndroid Build Coastguard Worker   size_ = new_size;
267*6dbdd20aSAndroid Build Coastguard Worker }
268*6dbdd20aSAndroid Build Coastguard Worker 
269*6dbdd20aSAndroid Build Coastguard Worker }  // namespace protozero
270