xref: /aosp_15_r20/frameworks/base/libs/androidfw/include/androidfw/BigBuffer.h (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
2  * Copyright (C) 2015 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 #pragma once
18 
19 #include <memory>
20 #include <string>
21 #include <type_traits>
22 #include <utility>
23 #include <vector>
24 
25 #include "android-base/logging.h"
26 #include "android-base/macros.h"
27 
28 namespace android {
29 
30 /**
31  * Inspired by protobuf's ZeroCopyOutputStream, offers blocks of memory
32  * in which to write without knowing the full size of the entire payload.
33  * This is essentially a list of memory blocks. As one fills up, another
34  * block is allocated and appended to the end of the list.
35  */
36 class BigBuffer {
37  public:
38   /**
39    * A contiguous block of allocated memory.
40    */
41   struct Block {
42     /**
43      * Pointer to the memory.
44      */
45     std::unique_ptr<uint8_t[]> buffer;
46 
47     /**
48      * Size of memory that is currently occupied. The actual
49      * allocation may be larger.
50      */
51     size_t size;
52 
53    private:
54     friend class BigBuffer;
55 
56     /**
57      * The size of the memory block allocation.
58      */
59     size_t block_size_;
60   };
61 
62   typedef std::vector<Block>::const_iterator const_iterator;
63 
64   /**
65    * Create a BigBuffer with block allocation sizes
66    * of block_size.
67    */
68   explicit BigBuffer(size_t block_size);
69 
70   BigBuffer(BigBuffer&& rhs) noexcept;
71 
72   /**
73    * Number of occupied bytes in all the allocated blocks.
74    */
75   size_t size() const;
76 
77   /**
78    * Returns a pointer to an array of T, where T is
79    * a POD type. The elements are zero-initialized.
80    */
81   template <typename T>
82   T* NextBlock(size_t count = 1);
83 
84   /**
85    * Returns the next block available and puts the size in out_count.
86    * This is useful for grabbing blocks where the size doesn't matter.
87    * Use BackUp() to give back any bytes that were not used.
88    */
89   void* NextBlock(size_t* out_count);
90 
91   /**
92    * Backs up count bytes. This must only be called after NextBlock()
93    * and can not be larger than sizeof(T) * count of the last NextBlock()
94    * call.
95    */
96   void BackUp(size_t count);
97 
98   /**
99    * Moves the specified BigBuffer into this one. When this method
100    * returns, buffer is empty.
101    */
102   void AppendBuffer(BigBuffer&& buffer);
103 
104   /**
105    * Pads the block with 'bytes' bytes of zero values.
106    */
107   void Pad(size_t bytes);
108 
109   /**
110    * Pads the block so that it aligns on a 4 byte boundary.
111    */
112   void Align4();
113 
114   size_t block_size() const;
115 
116   const_iterator begin() const;
117   const_iterator end() const;
118 
119   std::string to_string() const;
120 
121  private:
122   DISALLOW_COPY_AND_ASSIGN(BigBuffer);
123 
124   /**
125    * Returns a pointer to a buffer of the requested size.
126    * The buffer is zero-initialized.
127    */
128   void* NextBlockImpl(size_t size);
129 
130   size_t block_size_;
131   size_t size_;
132   std::vector<Block> blocks_;
133 };
134 
BigBuffer(size_t block_size)135 inline BigBuffer::BigBuffer(size_t block_size) : block_size_(block_size), size_(0) {
136 }
137 
BigBuffer(BigBuffer && rhs)138 inline BigBuffer::BigBuffer(BigBuffer&& rhs) noexcept
139     : block_size_(rhs.block_size_), size_(rhs.size_), blocks_(std::move(rhs.blocks_)) {
140 }
141 
size()142 inline size_t BigBuffer::size() const {
143   return size_;
144 }
145 
block_size()146 inline size_t BigBuffer::block_size() const {
147   return block_size_;
148 }
149 
150 template <typename T>
NextBlock(size_t count)151 inline T* BigBuffer::NextBlock(size_t count) {
152   static_assert(std::is_standard_layout_v<T>, "T must be standard_layout type");
153   CHECK(count != 0);
154   return reinterpret_cast<T*>(NextBlockImpl(sizeof(T) * count));
155 }
156 
Pad(size_t bytes)157 inline void BigBuffer::Pad(size_t bytes) {
158   NextBlock<char>(bytes);
159 }
160 
Align4()161 inline void BigBuffer::Align4() {
162   const size_t unaligned = size_ % 4;
163   if (unaligned != 0) {
164     Pad(4 - unaligned);
165   }
166 }
167 
begin()168 inline BigBuffer::const_iterator BigBuffer::begin() const {
169   return blocks_.begin();
170 }
171 
end()172 inline BigBuffer::const_iterator BigBuffer::end() const {
173   return blocks_.end();
174 }
175 
176 }  // namespace android
177