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 AAPT_BIG_BUFFER_H 18 #define AAPT_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 aapt { 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 136 inline BigBuffer::BigBuffer(size_t block_size) 137 : block_size_(block_size), size_(0) {} 138 139 inline BigBuffer::BigBuffer(BigBuffer&& rhs) noexcept 140 : block_size_(rhs.block_size_), 141 size_(rhs.size_), 142 blocks_(std::move(rhs.blocks_)) {} 143 144 inline size_t BigBuffer::size() const { return size_; } 145 146 inline size_t BigBuffer::block_size() const { return block_size_; } 147 148 template <typename T> 149 inline T* BigBuffer::NextBlock(size_t count) { 150 static_assert(std::is_standard_layout<T>::value, 151 "T must be standard_layout type"); 152 CHECK(count != 0); 153 return reinterpret_cast<T*>(NextBlockImpl(sizeof(T) * count)); 154 } 155 156 inline void BigBuffer::BackUp(size_t count) { 157 Block& block = blocks_.back(); 158 block.size -= count; 159 size_ -= count; 160 } 161 162 inline void BigBuffer::AppendBuffer(BigBuffer&& buffer) { 163 std::move(buffer.blocks_.begin(), buffer.blocks_.end(), 164 std::back_inserter(blocks_)); 165 size_ += buffer.size_; 166 buffer.blocks_.clear(); 167 buffer.size_ = 0; 168 } 169 170 inline void BigBuffer::Pad(size_t bytes) { NextBlock<char>(bytes); } 171 172 inline void BigBuffer::Align4() { 173 const size_t unaligned = size_ % 4; 174 if (unaligned != 0) { 175 Pad(4 - unaligned); 176 } 177 } 178 179 inline BigBuffer::const_iterator BigBuffer::begin() const { 180 return blocks_.begin(); 181 } 182 183 inline BigBuffer::const_iterator BigBuffer::end() const { 184 return blocks_.end(); 185 } 186 187 } // namespace aapt 188 189 #endif // AAPT_BIG_BUFFER_H 190