16f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/*
26f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Copyright (C) 2015 The Android Open Source Project
36f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *
46f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
56f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * you may not use this file except in compliance with the License.
66f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * You may obtain a copy of the License at
76f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *
86f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
96f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski *
106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Unless required by applicable law or agreed to in writing, software
116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * See the License for the specific language governing permissions and
146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * limitations under the License.
156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */
166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#ifndef AAPT_BIG_BUFFER_H
186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#define AAPT_BIG_BUFFER_H
196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <cstring>
216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <memory>
22c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski#include <string>
231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <type_traits>
246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <vector>
256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
26ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "android-base/logging.h"
27ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "android-base/macros.h"
28ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt {
306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/**
326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Inspired by protobuf's ZeroCopyOutputStream, offers blocks of memory
336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * in which to write without knowing the full size of the entire payload.
346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * This is essentially a list of memory blocks. As one fills up, another
356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * block is allocated and appended to the end of the list.
366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */
376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskiclass BigBuffer {
38cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski public:
39cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  /**
40cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   * A contiguous block of allocated memory.
41cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   */
42cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  struct Block {
436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    /**
44cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski     * Pointer to the memory.
456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski     */
46cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    std::unique_ptr<uint8_t[]> buffer;
4721efb6827cede06c2ab708de6cdb64d052dddcceAdam Lesinski
4821efb6827cede06c2ab708de6cdb64d052dddcceAdam Lesinski    /**
49cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski     * Size of memory that is currently occupied. The actual
50cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski     * allocation may be larger.
5121efb6827cede06c2ab708de6cdb64d052dddcceAdam Lesinski     */
52cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    size_t size;
5321efb6827cede06c2ab708de6cdb64d052dddcceAdam Lesinski
54cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   private:
55cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    friend class BigBuffer;
566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    /**
58cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski     * The size of the memory block allocation.
596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski     */
60ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    size_t block_size_;
61cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  };
62cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
63cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  typedef std::vector<Block>::const_iterator const_iterator;
64cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
65cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  /**
66cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   * Create a BigBuffer with block allocation sizes
67ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski   * of block_size.
68cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   */
69ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  explicit BigBuffer(size_t block_size);
70cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
71cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  BigBuffer(BigBuffer&& rhs);
72cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
73cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  /**
74cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   * Number of occupied bytes in all the allocated blocks.
75cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   */
76cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  size_t size() const;
77cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
78cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  /**
79cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   * Returns a pointer to an array of T, where T is
80cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   * a POD type. The elements are zero-initialized.
81cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   */
82cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  template <typename T>
83ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  T* NextBlock(size_t count = 1);
84cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
85cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  /**
86ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski   * Returns the next block available and puts the size in out_count.
87cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   * This is useful for grabbing blocks where the size doesn't matter.
88ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski   * Use BackUp() to give back any bytes that were not used.
89cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   */
90ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void* NextBlock(size_t* out_count);
91cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
92cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  /**
93ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski   * Backs up count bytes. This must only be called after NextBlock()
94ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski   * and can not be larger than sizeof(T) * count of the last NextBlock()
95cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   * call.
96cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   */
97ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void BackUp(size_t count);
98cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
99cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  /**
100cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   * Moves the specified BigBuffer into this one. When this method
101cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   * returns, buffer is empty.
102cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   */
103ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void AppendBuffer(BigBuffer&& buffer);
104cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
105cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  /**
106cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   * Pads the block with 'bytes' bytes of zero values.
107cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   */
108ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void Pad(size_t bytes);
109cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
110cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  /**
111cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   * Pads the block so that it aligns on a 4 byte boundary.
112cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   */
113ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void Align4();
114cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
115ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  size_t block_size() const;
116cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
117cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const_iterator begin() const;
118cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const_iterator end() const;
119cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
120c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski  std::string to_string() const;
121c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski
122cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski private:
123ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  DISALLOW_COPY_AND_ASSIGN(BigBuffer);
124ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
125cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  /**
126cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   * Returns a pointer to a buffer of the requested size.
127cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   * The buffer is zero-initialized.
128cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   */
129ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void* NextBlockImpl(size_t size);
130cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
131ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  size_t block_size_;
132ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  size_t size_;
133ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::vector<Block> blocks_;
1346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski};
1356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
136ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiinline BigBuffer::BigBuffer(size_t block_size)
137ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    : block_size_(block_size), size_(0) {}
1386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
139cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinskiinline BigBuffer::BigBuffer(BigBuffer&& rhs)
140ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    : block_size_(rhs.block_size_),
141ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      size_(rhs.size_),
142ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      blocks_(std::move(rhs.blocks_)) {}
1436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
144ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiinline size_t BigBuffer::size() const { return size_; }
1456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
146ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiinline size_t BigBuffer::block_size() const { return block_size_; }
14721efb6827cede06c2ab708de6cdb64d052dddcceAdam Lesinski
1486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskitemplate <typename T>
149ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiinline T* BigBuffer::NextBlock(size_t count) {
150cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  static_assert(std::is_standard_layout<T>::value,
151cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                "T must be standard_layout type");
152ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  CHECK(count != 0);
153ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  return reinterpret_cast<T*>(NextBlockImpl(sizeof(T) * count));
1546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
1556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
156ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiinline void BigBuffer::BackUp(size_t count) {
157ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Block& block = blocks_.back();
158cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  block.size -= count;
159ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  size_ -= count;
16021efb6827cede06c2ab708de6cdb64d052dddcceAdam Lesinski}
16121efb6827cede06c2ab708de6cdb64d052dddcceAdam Lesinski
162ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiinline void BigBuffer::AppendBuffer(BigBuffer&& buffer) {
163ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::move(buffer.blocks_.begin(), buffer.blocks_.end(),
164ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            std::back_inserter(blocks_));
165ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  size_ += buffer.size_;
166ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  buffer.blocks_.clear();
167ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  buffer.size_ = 0;
1686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
1696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
170ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiinline void BigBuffer::Pad(size_t bytes) { NextBlock<char>(bytes); }
1716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
172ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiinline void BigBuffer::Align4() {
173ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  const size_t unaligned = size_ % 4;
174cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (unaligned != 0) {
175ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    Pad(4 - unaligned);
176cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
1776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
1786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
1796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskiinline BigBuffer::const_iterator BigBuffer::begin() const {
180ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  return blocks_.begin();
1816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
1826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
1836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskiinline BigBuffer::const_iterator BigBuffer::end() const {
184ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  return blocks_.end();
1856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
1866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
187cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}  // namespace aapt
1886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
189cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski#endif  // AAPT_BIG_BUFFER_H
190