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