12c593315Sopenharmony_ci/*
22c593315Sopenharmony_ci * nghttp2 - HTTP/2 C Library
32c593315Sopenharmony_ci *
42c593315Sopenharmony_ci * Copyright (c) 2016 Tatsuhiro Tsujikawa
52c593315Sopenharmony_ci *
62c593315Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining
72c593315Sopenharmony_ci * a copy of this software and associated documentation files (the
82c593315Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
92c593315Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
102c593315Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to
112c593315Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
122c593315Sopenharmony_ci * the following conditions:
132c593315Sopenharmony_ci *
142c593315Sopenharmony_ci * The above copyright notice and this permission notice shall be
152c593315Sopenharmony_ci * included in all copies or substantial portions of the Software.
162c593315Sopenharmony_ci *
172c593315Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
182c593315Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
192c593315Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
202c593315Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
212c593315Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
222c593315Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
232c593315Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
242c593315Sopenharmony_ci */
252c593315Sopenharmony_ci#ifndef ALLOCATOR_H
262c593315Sopenharmony_ci#define ALLOCATOR_H
272c593315Sopenharmony_ci
282c593315Sopenharmony_ci#include "nghttp2_config.h"
292c593315Sopenharmony_ci
302c593315Sopenharmony_ci#ifndef _WIN32
312c593315Sopenharmony_ci#  include <sys/uio.h>
322c593315Sopenharmony_ci#endif // !_WIN32
332c593315Sopenharmony_ci
342c593315Sopenharmony_ci#include <cassert>
352c593315Sopenharmony_ci#include <utility>
362c593315Sopenharmony_ci
372c593315Sopenharmony_ci#include "template.h"
382c593315Sopenharmony_ci
392c593315Sopenharmony_cinamespace nghttp2 {
402c593315Sopenharmony_ci
412c593315Sopenharmony_cistruct MemBlock {
422c593315Sopenharmony_ci  // The next MemBlock to chain them.  This is for book keeping
432c593315Sopenharmony_ci  // purpose to free them later.
442c593315Sopenharmony_ci  MemBlock *next;
452c593315Sopenharmony_ci  // begin is the pointer to the beginning of buffer.  last is the
462c593315Sopenharmony_ci  // location of next write.  end is the one beyond of the end of the
472c593315Sopenharmony_ci  // buffer.
482c593315Sopenharmony_ci  uint8_t *begin, *last, *end;
492c593315Sopenharmony_ci};
502c593315Sopenharmony_ci
512c593315Sopenharmony_ci// BlockAllocator allocates memory block with given size at once, and
522c593315Sopenharmony_ci// cuts the region from it when allocation is requested.  If the
532c593315Sopenharmony_ci// requested size is larger than given threshold (plus small internal
542c593315Sopenharmony_ci// overhead), it will be allocated in a distinct buffer on demand.
552c593315Sopenharmony_ci// The |isolation_threshold| must be less than or equal to
562c593315Sopenharmony_ci// |block_size|.
572c593315Sopenharmony_cistruct BlockAllocator {
582c593315Sopenharmony_ci  BlockAllocator(size_t block_size, size_t isolation_threshold)
592c593315Sopenharmony_ci      : retain(nullptr),
602c593315Sopenharmony_ci        head(nullptr),
612c593315Sopenharmony_ci        block_size(block_size),
622c593315Sopenharmony_ci        isolation_threshold(std::min(block_size, isolation_threshold)) {
632c593315Sopenharmony_ci    assert(isolation_threshold <= block_size);
642c593315Sopenharmony_ci  }
652c593315Sopenharmony_ci
662c593315Sopenharmony_ci  ~BlockAllocator() { reset(); }
672c593315Sopenharmony_ci
682c593315Sopenharmony_ci  BlockAllocator(BlockAllocator &&other) noexcept
692c593315Sopenharmony_ci      : retain{std::exchange(other.retain, nullptr)},
702c593315Sopenharmony_ci        head{std::exchange(other.head, nullptr)},
712c593315Sopenharmony_ci        block_size(other.block_size),
722c593315Sopenharmony_ci        isolation_threshold(other.isolation_threshold) {}
732c593315Sopenharmony_ci
742c593315Sopenharmony_ci  BlockAllocator &operator=(BlockAllocator &&other) noexcept {
752c593315Sopenharmony_ci    reset();
762c593315Sopenharmony_ci
772c593315Sopenharmony_ci    retain = std::exchange(other.retain, nullptr);
782c593315Sopenharmony_ci    head = std::exchange(other.head, nullptr);
792c593315Sopenharmony_ci    block_size = other.block_size;
802c593315Sopenharmony_ci    isolation_threshold = other.isolation_threshold;
812c593315Sopenharmony_ci
822c593315Sopenharmony_ci    return *this;
832c593315Sopenharmony_ci  }
842c593315Sopenharmony_ci
852c593315Sopenharmony_ci  BlockAllocator(const BlockAllocator &) = delete;
862c593315Sopenharmony_ci  BlockAllocator &operator=(const BlockAllocator &) = delete;
872c593315Sopenharmony_ci
882c593315Sopenharmony_ci  void reset() {
892c593315Sopenharmony_ci    for (auto mb = retain; mb;) {
902c593315Sopenharmony_ci      auto next = mb->next;
912c593315Sopenharmony_ci      delete[] reinterpret_cast<uint8_t *>(mb);
922c593315Sopenharmony_ci      mb = next;
932c593315Sopenharmony_ci    }
942c593315Sopenharmony_ci
952c593315Sopenharmony_ci    retain = nullptr;
962c593315Sopenharmony_ci    head = nullptr;
972c593315Sopenharmony_ci  }
982c593315Sopenharmony_ci
992c593315Sopenharmony_ci  MemBlock *alloc_mem_block(size_t size) {
1002c593315Sopenharmony_ci    auto block = new uint8_t[sizeof(MemBlock) + size];
1012c593315Sopenharmony_ci    auto mb = reinterpret_cast<MemBlock *>(block);
1022c593315Sopenharmony_ci
1032c593315Sopenharmony_ci    mb->next = retain;
1042c593315Sopenharmony_ci    mb->begin = mb->last = block + sizeof(MemBlock);
1052c593315Sopenharmony_ci    mb->end = mb->begin + size;
1062c593315Sopenharmony_ci    retain = mb;
1072c593315Sopenharmony_ci    return mb;
1082c593315Sopenharmony_ci  }
1092c593315Sopenharmony_ci
1102c593315Sopenharmony_ci  void *alloc(size_t size) {
1112c593315Sopenharmony_ci    if (size + sizeof(size_t) >= isolation_threshold) {
1122c593315Sopenharmony_ci      auto len = std::max(static_cast<size_t>(16), size);
1132c593315Sopenharmony_ci      // We will store the allocated size in size_t field.
1142c593315Sopenharmony_ci      auto mb = alloc_mem_block(len + sizeof(size_t));
1152c593315Sopenharmony_ci      auto sp = reinterpret_cast<size_t *>(mb->begin);
1162c593315Sopenharmony_ci      *sp = len;
1172c593315Sopenharmony_ci      mb->last = mb->end;
1182c593315Sopenharmony_ci      return mb->begin + sizeof(size_t);
1192c593315Sopenharmony_ci    }
1202c593315Sopenharmony_ci
1212c593315Sopenharmony_ci    if (!head ||
1222c593315Sopenharmony_ci        head->end - head->last < static_cast<ssize_t>(size + sizeof(size_t))) {
1232c593315Sopenharmony_ci      head = alloc_mem_block(block_size);
1242c593315Sopenharmony_ci    }
1252c593315Sopenharmony_ci
1262c593315Sopenharmony_ci    // We will store the allocated size in size_t field.
1272c593315Sopenharmony_ci    auto res = head->last + sizeof(size_t);
1282c593315Sopenharmony_ci    auto sp = reinterpret_cast<size_t *>(head->last);
1292c593315Sopenharmony_ci    *sp = size;
1302c593315Sopenharmony_ci
1312c593315Sopenharmony_ci    head->last = reinterpret_cast<uint8_t *>(
1322c593315Sopenharmony_ci        (reinterpret_cast<intptr_t>(res + size) + 0xf) & ~0xf);
1332c593315Sopenharmony_ci
1342c593315Sopenharmony_ci    return res;
1352c593315Sopenharmony_ci  }
1362c593315Sopenharmony_ci
1372c593315Sopenharmony_ci  // Returns allocated size for memory pointed by |ptr|.  We assume
1382c593315Sopenharmony_ci  // that |ptr| was returned from alloc() or realloc().
1392c593315Sopenharmony_ci  size_t get_alloc_length(void *ptr) {
1402c593315Sopenharmony_ci    return *reinterpret_cast<size_t *>(static_cast<uint8_t *>(ptr) -
1412c593315Sopenharmony_ci                                       sizeof(size_t));
1422c593315Sopenharmony_ci  }
1432c593315Sopenharmony_ci
1442c593315Sopenharmony_ci  // Allocates memory of at least |size| bytes.  If |ptr| is nullptr,
1452c593315Sopenharmony_ci  // this is equivalent to alloc(size).  If |ptr| is not nullptr,
1462c593315Sopenharmony_ci  // obtain the allocated size for |ptr|, assuming that |ptr| was
1472c593315Sopenharmony_ci  // returned from alloc() or realloc().  If the allocated size is
1482c593315Sopenharmony_ci  // greater than or equal to size, |ptr| is returned.  Otherwise,
1492c593315Sopenharmony_ci  // allocates at least |size| bytes of memory, and the original
1502c593315Sopenharmony_ci  // content pointed by |ptr| is copied to the newly allocated memory.
1512c593315Sopenharmony_ci  void *realloc(void *ptr, size_t size) {
1522c593315Sopenharmony_ci    if (!ptr) {
1532c593315Sopenharmony_ci      return alloc(size);
1542c593315Sopenharmony_ci    }
1552c593315Sopenharmony_ci    auto alloclen = get_alloc_length(ptr);
1562c593315Sopenharmony_ci    auto p = reinterpret_cast<uint8_t *>(ptr);
1572c593315Sopenharmony_ci    if (size <= alloclen) {
1582c593315Sopenharmony_ci      return ptr;
1592c593315Sopenharmony_ci    }
1602c593315Sopenharmony_ci
1612c593315Sopenharmony_ci    auto nalloclen = std::max(size + 1, alloclen * 2);
1622c593315Sopenharmony_ci
1632c593315Sopenharmony_ci    auto res = alloc(nalloclen);
1642c593315Sopenharmony_ci    std::copy_n(p, alloclen, static_cast<uint8_t *>(res));
1652c593315Sopenharmony_ci
1662c593315Sopenharmony_ci    return res;
1672c593315Sopenharmony_ci  }
1682c593315Sopenharmony_ci
1692c593315Sopenharmony_ci  // This holds live memory block to free them in dtor.
1702c593315Sopenharmony_ci  MemBlock *retain;
1712c593315Sopenharmony_ci  // Current memory block to use.
1722c593315Sopenharmony_ci  MemBlock *head;
1732c593315Sopenharmony_ci  // size of single memory block
1742c593315Sopenharmony_ci  size_t block_size;
1752c593315Sopenharmony_ci  // if allocation greater or equal to isolation_threshold bytes is
1762c593315Sopenharmony_ci  // requested, allocate dedicated block.
1772c593315Sopenharmony_ci  size_t isolation_threshold;
1782c593315Sopenharmony_ci};
1792c593315Sopenharmony_ci
1802c593315Sopenharmony_ci// Makes a copy of |src|.  The resulting string will be
1812c593315Sopenharmony_ci// NULL-terminated.
1822c593315Sopenharmony_citemplate <typename BlockAllocator>
1832c593315Sopenharmony_ciStringRef make_string_ref(BlockAllocator &alloc, const StringRef &src) {
1842c593315Sopenharmony_ci  auto dst = static_cast<uint8_t *>(alloc.alloc(src.size() + 1));
1852c593315Sopenharmony_ci  auto p = dst;
1862c593315Sopenharmony_ci  p = std::copy(std::begin(src), std::end(src), p);
1872c593315Sopenharmony_ci  *p = '\0';
1882c593315Sopenharmony_ci  return StringRef{dst, src.size()};
1892c593315Sopenharmony_ci}
1902c593315Sopenharmony_ci
1912c593315Sopenharmony_ci// private function used in concat_string_ref.  this is the base
1922c593315Sopenharmony_ci// function of concat_string_ref_count().
1932c593315Sopenharmony_ciinline constexpr size_t concat_string_ref_count(size_t acc) { return acc; }
1942c593315Sopenharmony_ci
1952c593315Sopenharmony_ci// private function used in concat_string_ref.  This function counts
1962c593315Sopenharmony_ci// the sum of length of given arguments.  The calculated length is
1972c593315Sopenharmony_ci// accumulated, and passed to the next function.
1982c593315Sopenharmony_citemplate <typename... Args>
1992c593315Sopenharmony_ciconstexpr size_t concat_string_ref_count(size_t acc, const StringRef &value,
2002c593315Sopenharmony_ci                                         Args &&...args) {
2012c593315Sopenharmony_ci  return concat_string_ref_count(acc + value.size(),
2022c593315Sopenharmony_ci                                 std::forward<Args>(args)...);
2032c593315Sopenharmony_ci}
2042c593315Sopenharmony_ci
2052c593315Sopenharmony_ci// private function used in concat_string_ref.  this is the base
2062c593315Sopenharmony_ci// function of concat_string_ref_copy().
2072c593315Sopenharmony_ciinline uint8_t *concat_string_ref_copy(uint8_t *p) { return p; }
2082c593315Sopenharmony_ci
2092c593315Sopenharmony_ci// private function used in concat_string_ref.  This function copies
2102c593315Sopenharmony_ci// given strings into |p|.  |p| is incremented by the copied length,
2112c593315Sopenharmony_ci// and returned.  In the end, return value points to the location one
2122c593315Sopenharmony_ci// beyond the last byte written.
2132c593315Sopenharmony_citemplate <typename... Args>
2142c593315Sopenharmony_ciuint8_t *concat_string_ref_copy(uint8_t *p, const StringRef &value,
2152c593315Sopenharmony_ci                                Args &&...args) {
2162c593315Sopenharmony_ci  p = std::copy(std::begin(value), std::end(value), p);
2172c593315Sopenharmony_ci  return concat_string_ref_copy(p, std::forward<Args>(args)...);
2182c593315Sopenharmony_ci}
2192c593315Sopenharmony_ci
2202c593315Sopenharmony_ci// Returns the string which is the concatenation of |args| in the
2212c593315Sopenharmony_ci// given order.  The resulting string will be NULL-terminated.
2222c593315Sopenharmony_citemplate <typename BlockAllocator, typename... Args>
2232c593315Sopenharmony_ciStringRef concat_string_ref(BlockAllocator &alloc, Args &&...args) {
2242c593315Sopenharmony_ci  size_t len = concat_string_ref_count(0, std::forward<Args>(args)...);
2252c593315Sopenharmony_ci  auto dst = static_cast<uint8_t *>(alloc.alloc(len + 1));
2262c593315Sopenharmony_ci  auto p = dst;
2272c593315Sopenharmony_ci  p = concat_string_ref_copy(p, std::forward<Args>(args)...);
2282c593315Sopenharmony_ci  *p = '\0';
2292c593315Sopenharmony_ci  return StringRef{dst, len};
2302c593315Sopenharmony_ci}
2312c593315Sopenharmony_ci
2322c593315Sopenharmony_ci// Returns the string which is the concatenation of |value| and |args|
2332c593315Sopenharmony_ci// in the given order.  The resulting string will be NULL-terminated.
2342c593315Sopenharmony_ci// This function assumes that the pointer value value.c_str() was
2352c593315Sopenharmony_ci// obtained from alloc.alloc() or alloc.realloc(), and attempts to use
2362c593315Sopenharmony_ci// unused memory region by using alloc.realloc().  If value is empty,
2372c593315Sopenharmony_ci// then just call concat_string_ref().
2382c593315Sopenharmony_citemplate <typename BlockAllocator, typename... Args>
2392c593315Sopenharmony_ciStringRef realloc_concat_string_ref(BlockAllocator &alloc,
2402c593315Sopenharmony_ci                                    const StringRef &value, Args &&...args) {
2412c593315Sopenharmony_ci  if (value.empty()) {
2422c593315Sopenharmony_ci    return concat_string_ref(alloc, std::forward<Args>(args)...);
2432c593315Sopenharmony_ci  }
2442c593315Sopenharmony_ci
2452c593315Sopenharmony_ci  auto len =
2462c593315Sopenharmony_ci      value.size() + concat_string_ref_count(0, std::forward<Args>(args)...);
2472c593315Sopenharmony_ci  auto dst = static_cast<uint8_t *>(
2482c593315Sopenharmony_ci      alloc.realloc(const_cast<uint8_t *>(value.byte()), len + 1));
2492c593315Sopenharmony_ci  auto p = dst + value.size();
2502c593315Sopenharmony_ci  p = concat_string_ref_copy(p, std::forward<Args>(args)...);
2512c593315Sopenharmony_ci  *p = '\0';
2522c593315Sopenharmony_ci
2532c593315Sopenharmony_ci  return StringRef{dst, len};
2542c593315Sopenharmony_ci}
2552c593315Sopenharmony_ci
2562c593315Sopenharmony_cistruct ByteRef {
2572c593315Sopenharmony_ci  // The pointer to the beginning of the buffer.
2582c593315Sopenharmony_ci  uint8_t *base;
2592c593315Sopenharmony_ci  // The length of the buffer.
2602c593315Sopenharmony_ci  size_t len;
2612c593315Sopenharmony_ci};
2622c593315Sopenharmony_ci
2632c593315Sopenharmony_ci// Makes a buffer with given size.  The resulting byte string might
2642c593315Sopenharmony_ci// not be NULL-terminated.
2652c593315Sopenharmony_citemplate <typename BlockAllocator>
2662c593315Sopenharmony_ciByteRef make_byte_ref(BlockAllocator &alloc, size_t size) {
2672c593315Sopenharmony_ci  auto dst = static_cast<uint8_t *>(alloc.alloc(size));
2682c593315Sopenharmony_ci  return {dst, size};
2692c593315Sopenharmony_ci}
2702c593315Sopenharmony_ci
2712c593315Sopenharmony_ci} // namespace nghttp2
2722c593315Sopenharmony_ci
2732c593315Sopenharmony_ci#endif // ALLOCATOR_H
274