Home | History | Annotate | Download | only in util
      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 <cassert>
     21 #include <cstring>
     22 #include <memory>
     23 #include <type_traits>
     24 #include <vector>
     25 
     26 namespace aapt {
     27 
     28 /**
     29  * Inspired by protobuf's ZeroCopyOutputStream, offers blocks of memory
     30  * in which to write without knowing the full size of the entire payload.
     31  * This is essentially a list of memory blocks. As one fills up, another
     32  * block is allocated and appended to the end of the list.
     33  */
     34 class BigBuffer {
     35 public:
     36     /**
     37      * A contiguous block of allocated memory.
     38      */
     39     struct Block {
     40         /**
     41          * Pointer to the memory.
     42          */
     43         std::unique_ptr<uint8_t[]> buffer;
     44 
     45         /**
     46          * Size of memory that is currently occupied. The actual
     47          * allocation may be larger.
     48          */
     49         size_t size;
     50 
     51     private:
     52         friend class BigBuffer;
     53 
     54         /**
     55          * The size of the memory block allocation.
     56          */
     57         size_t mBlockSize;
     58     };
     59 
     60     typedef std::vector<Block>::const_iterator const_iterator;
     61 
     62     /**
     63      * Create a BigBuffer with block allocation sizes
     64      * of blockSize.
     65      */
     66     BigBuffer(size_t blockSize);
     67 
     68     BigBuffer(const BigBuffer&) = delete; // No copying.
     69 
     70     BigBuffer(BigBuffer&& rhs);
     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      * Moves the specified BigBuffer into this one. When this method
     86      * returns, buffer is empty.
     87      */
     88     void appendBuffer(BigBuffer&& buffer);
     89 
     90     /**
     91      * Pads the block with 'bytes' bytes of zero values.
     92      */
     93     void pad(size_t bytes);
     94 
     95     /**
     96      * Pads the block so that it aligns on a 4 byte boundary.
     97      */
     98     void align4();
     99 
    100     const_iterator begin() const;
    101     const_iterator end() const;
    102 
    103 private:
    104     /**
    105      * Returns a pointer to a buffer of the requested size.
    106      * The buffer is zero-initialized.
    107      */
    108     void* nextBlockImpl(size_t size);
    109 
    110     size_t mBlockSize;
    111     size_t mSize;
    112     std::vector<Block> mBlocks;
    113 };
    114 
    115 inline BigBuffer::BigBuffer(size_t blockSize) : mBlockSize(blockSize), mSize(0) {
    116 }
    117 
    118 inline BigBuffer::BigBuffer(BigBuffer&& rhs) :
    119         mBlockSize(rhs.mBlockSize), mSize(rhs.mSize), mBlocks(std::move(rhs.mBlocks)) {
    120 }
    121 
    122 inline size_t BigBuffer::size() const {
    123     return mSize;
    124 }
    125 
    126 template <typename T>
    127 inline T* BigBuffer::nextBlock(size_t count) {
    128     static_assert(std::is_standard_layout<T>::value, "T must be standard_layout type");
    129     assert(count != 0);
    130     return reinterpret_cast<T*>(nextBlockImpl(sizeof(T) * count));
    131 }
    132 
    133 inline void BigBuffer::appendBuffer(BigBuffer&& buffer) {
    134     std::move(buffer.mBlocks.begin(), buffer.mBlocks.end(), std::back_inserter(mBlocks));
    135     mSize += buffer.mSize;
    136     buffer.mBlocks.clear();
    137     buffer.mSize = 0;
    138 }
    139 
    140 inline void BigBuffer::pad(size_t bytes) {
    141     nextBlock<char>(bytes);
    142 }
    143 
    144 inline void BigBuffer::align4() {
    145     const size_t unaligned = mSize % 4;
    146     if (unaligned != 0) {
    147         pad(4 - unaligned);
    148     }
    149 }
    150 
    151 inline BigBuffer::const_iterator BigBuffer::begin() const {
    152     return mBlocks.begin();
    153 }
    154 
    155 inline BigBuffer::const_iterator BigBuffer::end() const {
    156     return mBlocks.end();
    157 }
    158 
    159 } // namespace aapt
    160 
    161 #endif // AAPT_BIG_BUFFER_H
    162