12c593315Sopenharmony_ci/*
22c593315Sopenharmony_ci * nghttp2 - HTTP/2 C Library
32c593315Sopenharmony_ci *
42c593315Sopenharmony_ci * Copyright (c) 2014 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 MEMCHUNK_H
262c593315Sopenharmony_ci#define MEMCHUNK_H
272c593315Sopenharmony_ci
282c593315Sopenharmony_ci#include "nghttp2_config.h"
292c593315Sopenharmony_ci
302c593315Sopenharmony_ci#include <limits.h>
312c593315Sopenharmony_ci#ifdef _WIN32
322c593315Sopenharmony_ci/* Structure for scatter/gather I/O.  */
332c593315Sopenharmony_cistruct iovec {
342c593315Sopenharmony_ci  void *iov_base; /* Pointer to data.  */
352c593315Sopenharmony_ci  size_t iov_len; /* Length of data.  */
362c593315Sopenharmony_ci};
372c593315Sopenharmony_ci#else // !_WIN32
382c593315Sopenharmony_ci#  include <sys/uio.h>
392c593315Sopenharmony_ci#endif // !_WIN32
402c593315Sopenharmony_ci
412c593315Sopenharmony_ci#include <cassert>
422c593315Sopenharmony_ci#include <cstring>
432c593315Sopenharmony_ci#include <memory>
442c593315Sopenharmony_ci#include <array>
452c593315Sopenharmony_ci#include <algorithm>
462c593315Sopenharmony_ci#include <string>
472c593315Sopenharmony_ci#include <utility>
482c593315Sopenharmony_ci
492c593315Sopenharmony_ci#include "template.h"
502c593315Sopenharmony_ci
512c593315Sopenharmony_cinamespace nghttp2 {
522c593315Sopenharmony_ci
532c593315Sopenharmony_ci#define DEFAULT_WR_IOVCNT 16
542c593315Sopenharmony_ci
552c593315Sopenharmony_ci#if defined(IOV_MAX) && IOV_MAX < DEFAULT_WR_IOVCNT
562c593315Sopenharmony_ci#  define MAX_WR_IOVCNT IOV_MAX
572c593315Sopenharmony_ci#else // !defined(IOV_MAX) || IOV_MAX >= DEFAULT_WR_IOVCNT
582c593315Sopenharmony_ci#  define MAX_WR_IOVCNT DEFAULT_WR_IOVCNT
592c593315Sopenharmony_ci#endif // !defined(IOV_MAX) || IOV_MAX >= DEFAULT_WR_IOVCNT
602c593315Sopenharmony_ci
612c593315Sopenharmony_citemplate <size_t N> struct Memchunk {
622c593315Sopenharmony_ci  Memchunk(Memchunk *next_chunk)
632c593315Sopenharmony_ci      : pos(std::begin(buf)), last(pos), knext(next_chunk), next(nullptr) {}
642c593315Sopenharmony_ci  size_t len() const { return last - pos; }
652c593315Sopenharmony_ci  size_t left() const { return std::end(buf) - last; }
662c593315Sopenharmony_ci  void reset() { pos = last = std::begin(buf); }
672c593315Sopenharmony_ci  std::array<uint8_t, N> buf;
682c593315Sopenharmony_ci  uint8_t *pos, *last;
692c593315Sopenharmony_ci  Memchunk *knext;
702c593315Sopenharmony_ci  Memchunk *next;
712c593315Sopenharmony_ci  static const size_t size = N;
722c593315Sopenharmony_ci};
732c593315Sopenharmony_ci
742c593315Sopenharmony_citemplate <typename T> struct Pool {
752c593315Sopenharmony_ci  Pool() : pool(nullptr), freelist(nullptr), poolsize(0), freelistsize(0) {}
762c593315Sopenharmony_ci  ~Pool() { clear(); }
772c593315Sopenharmony_ci  T *get() {
782c593315Sopenharmony_ci    if (freelist) {
792c593315Sopenharmony_ci      auto m = freelist;
802c593315Sopenharmony_ci      freelist = freelist->next;
812c593315Sopenharmony_ci      m->next = nullptr;
822c593315Sopenharmony_ci      m->reset();
832c593315Sopenharmony_ci      freelistsize -= T::size;
842c593315Sopenharmony_ci      return m;
852c593315Sopenharmony_ci    }
862c593315Sopenharmony_ci
872c593315Sopenharmony_ci    pool = new T{pool};
882c593315Sopenharmony_ci    poolsize += T::size;
892c593315Sopenharmony_ci    return pool;
902c593315Sopenharmony_ci  }
912c593315Sopenharmony_ci  void recycle(T *m) {
922c593315Sopenharmony_ci    m->next = freelist;
932c593315Sopenharmony_ci    freelist = m;
942c593315Sopenharmony_ci    freelistsize += T::size;
952c593315Sopenharmony_ci  }
962c593315Sopenharmony_ci  void clear() {
972c593315Sopenharmony_ci    freelist = nullptr;
982c593315Sopenharmony_ci    freelistsize = 0;
992c593315Sopenharmony_ci    for (auto p = pool; p;) {
1002c593315Sopenharmony_ci      auto knext = p->knext;
1012c593315Sopenharmony_ci      delete p;
1022c593315Sopenharmony_ci      p = knext;
1032c593315Sopenharmony_ci    }
1042c593315Sopenharmony_ci    pool = nullptr;
1052c593315Sopenharmony_ci    poolsize = 0;
1062c593315Sopenharmony_ci  }
1072c593315Sopenharmony_ci  using value_type = T;
1082c593315Sopenharmony_ci  T *pool;
1092c593315Sopenharmony_ci  T *freelist;
1102c593315Sopenharmony_ci  size_t poolsize;
1112c593315Sopenharmony_ci  size_t freelistsize;
1122c593315Sopenharmony_ci};
1132c593315Sopenharmony_ci
1142c593315Sopenharmony_citemplate <typename Memchunk> struct Memchunks {
1152c593315Sopenharmony_ci  Memchunks(Pool<Memchunk> *pool)
1162c593315Sopenharmony_ci      : pool(pool),
1172c593315Sopenharmony_ci        head(nullptr),
1182c593315Sopenharmony_ci        tail(nullptr),
1192c593315Sopenharmony_ci        len(0),
1202c593315Sopenharmony_ci        mark(nullptr),
1212c593315Sopenharmony_ci        mark_pos(nullptr),
1222c593315Sopenharmony_ci        mark_offset(0) {}
1232c593315Sopenharmony_ci  Memchunks(const Memchunks &) = delete;
1242c593315Sopenharmony_ci  Memchunks(Memchunks &&other) noexcept
1252c593315Sopenharmony_ci      : pool{other.pool}, // keep other.pool
1262c593315Sopenharmony_ci        head{std::exchange(other.head, nullptr)},
1272c593315Sopenharmony_ci        tail{std::exchange(other.tail, nullptr)},
1282c593315Sopenharmony_ci        len{std::exchange(other.len, 0)},
1292c593315Sopenharmony_ci        mark{std::exchange(other.mark, nullptr)},
1302c593315Sopenharmony_ci        mark_pos{std::exchange(other.mark_pos, nullptr)},
1312c593315Sopenharmony_ci        mark_offset{std::exchange(other.mark_offset, 0)} {}
1322c593315Sopenharmony_ci  Memchunks &operator=(const Memchunks &) = delete;
1332c593315Sopenharmony_ci  Memchunks &operator=(Memchunks &&other) noexcept {
1342c593315Sopenharmony_ci    if (this == &other) {
1352c593315Sopenharmony_ci      return *this;
1362c593315Sopenharmony_ci    }
1372c593315Sopenharmony_ci
1382c593315Sopenharmony_ci    reset();
1392c593315Sopenharmony_ci
1402c593315Sopenharmony_ci    pool = other.pool;
1412c593315Sopenharmony_ci    head = std::exchange(other.head, nullptr);
1422c593315Sopenharmony_ci    tail = std::exchange(other.tail, nullptr);
1432c593315Sopenharmony_ci    len = std::exchange(other.len, 0);
1442c593315Sopenharmony_ci    mark = std::exchange(other.mark, nullptr);
1452c593315Sopenharmony_ci    mark_pos = std::exchange(other.mark_pos, nullptr);
1462c593315Sopenharmony_ci    mark_offset = std::exchange(other.mark_offset, 0);
1472c593315Sopenharmony_ci
1482c593315Sopenharmony_ci    return *this;
1492c593315Sopenharmony_ci  }
1502c593315Sopenharmony_ci  ~Memchunks() {
1512c593315Sopenharmony_ci    if (!pool) {
1522c593315Sopenharmony_ci      return;
1532c593315Sopenharmony_ci    }
1542c593315Sopenharmony_ci    for (auto m = head; m;) {
1552c593315Sopenharmony_ci      auto next = m->next;
1562c593315Sopenharmony_ci      pool->recycle(m);
1572c593315Sopenharmony_ci      m = next;
1582c593315Sopenharmony_ci    }
1592c593315Sopenharmony_ci  }
1602c593315Sopenharmony_ci  size_t append(char c) {
1612c593315Sopenharmony_ci    if (!tail) {
1622c593315Sopenharmony_ci      head = tail = pool->get();
1632c593315Sopenharmony_ci    } else if (tail->left() == 0) {
1642c593315Sopenharmony_ci      tail->next = pool->get();
1652c593315Sopenharmony_ci      tail = tail->next;
1662c593315Sopenharmony_ci    }
1672c593315Sopenharmony_ci    *tail->last++ = c;
1682c593315Sopenharmony_ci    ++len;
1692c593315Sopenharmony_ci    return 1;
1702c593315Sopenharmony_ci  }
1712c593315Sopenharmony_ci  size_t append(const void *src, size_t count) {
1722c593315Sopenharmony_ci    if (count == 0) {
1732c593315Sopenharmony_ci      return 0;
1742c593315Sopenharmony_ci    }
1752c593315Sopenharmony_ci
1762c593315Sopenharmony_ci    auto first = static_cast<const uint8_t *>(src);
1772c593315Sopenharmony_ci    auto last = first + count;
1782c593315Sopenharmony_ci
1792c593315Sopenharmony_ci    if (!tail) {
1802c593315Sopenharmony_ci      head = tail = pool->get();
1812c593315Sopenharmony_ci    }
1822c593315Sopenharmony_ci
1832c593315Sopenharmony_ci    for (;;) {
1842c593315Sopenharmony_ci      auto n = std::min(static_cast<size_t>(last - first), tail->left());
1852c593315Sopenharmony_ci      tail->last = std::copy_n(first, n, tail->last);
1862c593315Sopenharmony_ci      first += n;
1872c593315Sopenharmony_ci      len += n;
1882c593315Sopenharmony_ci      if (first == last) {
1892c593315Sopenharmony_ci        break;
1902c593315Sopenharmony_ci      }
1912c593315Sopenharmony_ci
1922c593315Sopenharmony_ci      tail->next = pool->get();
1932c593315Sopenharmony_ci      tail = tail->next;
1942c593315Sopenharmony_ci    }
1952c593315Sopenharmony_ci
1962c593315Sopenharmony_ci    return count;
1972c593315Sopenharmony_ci  }
1982c593315Sopenharmony_ci  template <size_t N> size_t append(const char (&s)[N]) {
1992c593315Sopenharmony_ci    return append(s, N - 1);
2002c593315Sopenharmony_ci  }
2012c593315Sopenharmony_ci  size_t append(const std::string &s) { return append(s.c_str(), s.size()); }
2022c593315Sopenharmony_ci  size_t append(const StringRef &s) { return append(s.c_str(), s.size()); }
2032c593315Sopenharmony_ci  size_t append(const ImmutableString &s) {
2042c593315Sopenharmony_ci    return append(s.c_str(), s.size());
2052c593315Sopenharmony_ci  }
2062c593315Sopenharmony_ci  size_t copy(Memchunks &dest) {
2072c593315Sopenharmony_ci    auto m = head;
2082c593315Sopenharmony_ci    while (m) {
2092c593315Sopenharmony_ci      dest.append(m->pos, m->len());
2102c593315Sopenharmony_ci      m = m->next;
2112c593315Sopenharmony_ci    }
2122c593315Sopenharmony_ci    return len;
2132c593315Sopenharmony_ci  }
2142c593315Sopenharmony_ci  size_t remove(void *dest, size_t count) {
2152c593315Sopenharmony_ci    assert(mark == nullptr);
2162c593315Sopenharmony_ci
2172c593315Sopenharmony_ci    if (!tail || count == 0) {
2182c593315Sopenharmony_ci      return 0;
2192c593315Sopenharmony_ci    }
2202c593315Sopenharmony_ci
2212c593315Sopenharmony_ci    auto first = static_cast<uint8_t *>(dest);
2222c593315Sopenharmony_ci    auto last = first + count;
2232c593315Sopenharmony_ci
2242c593315Sopenharmony_ci    auto m = head;
2252c593315Sopenharmony_ci
2262c593315Sopenharmony_ci    while (m) {
2272c593315Sopenharmony_ci      auto next = m->next;
2282c593315Sopenharmony_ci      auto n = std::min(static_cast<size_t>(last - first), m->len());
2292c593315Sopenharmony_ci
2302c593315Sopenharmony_ci      assert(m->len());
2312c593315Sopenharmony_ci      first = std::copy_n(m->pos, n, first);
2322c593315Sopenharmony_ci      m->pos += n;
2332c593315Sopenharmony_ci      len -= n;
2342c593315Sopenharmony_ci      if (m->len() > 0) {
2352c593315Sopenharmony_ci        break;
2362c593315Sopenharmony_ci      }
2372c593315Sopenharmony_ci      pool->recycle(m);
2382c593315Sopenharmony_ci      m = next;
2392c593315Sopenharmony_ci    }
2402c593315Sopenharmony_ci    head = m;
2412c593315Sopenharmony_ci    if (head == nullptr) {
2422c593315Sopenharmony_ci      tail = nullptr;
2432c593315Sopenharmony_ci    }
2442c593315Sopenharmony_ci
2452c593315Sopenharmony_ci    return first - static_cast<uint8_t *>(dest);
2462c593315Sopenharmony_ci  }
2472c593315Sopenharmony_ci  size_t remove(Memchunks &dest, size_t count) {
2482c593315Sopenharmony_ci    assert(mark == nullptr);
2492c593315Sopenharmony_ci
2502c593315Sopenharmony_ci    if (!tail || count == 0) {
2512c593315Sopenharmony_ci      return 0;
2522c593315Sopenharmony_ci    }
2532c593315Sopenharmony_ci
2542c593315Sopenharmony_ci    auto left = count;
2552c593315Sopenharmony_ci    auto m = head;
2562c593315Sopenharmony_ci
2572c593315Sopenharmony_ci    while (m) {
2582c593315Sopenharmony_ci      auto next = m->next;
2592c593315Sopenharmony_ci      auto n = std::min(left, m->len());
2602c593315Sopenharmony_ci
2612c593315Sopenharmony_ci      assert(m->len());
2622c593315Sopenharmony_ci      dest.append(m->pos, n);
2632c593315Sopenharmony_ci      m->pos += n;
2642c593315Sopenharmony_ci      len -= n;
2652c593315Sopenharmony_ci      left -= n;
2662c593315Sopenharmony_ci      if (m->len() > 0) {
2672c593315Sopenharmony_ci        break;
2682c593315Sopenharmony_ci      }
2692c593315Sopenharmony_ci      pool->recycle(m);
2702c593315Sopenharmony_ci      m = next;
2712c593315Sopenharmony_ci    }
2722c593315Sopenharmony_ci    head = m;
2732c593315Sopenharmony_ci    if (head == nullptr) {
2742c593315Sopenharmony_ci      tail = nullptr;
2752c593315Sopenharmony_ci    }
2762c593315Sopenharmony_ci
2772c593315Sopenharmony_ci    return count - left;
2782c593315Sopenharmony_ci  }
2792c593315Sopenharmony_ci  size_t remove(Memchunks &dest) {
2802c593315Sopenharmony_ci    assert(pool == dest.pool);
2812c593315Sopenharmony_ci    assert(mark == nullptr);
2822c593315Sopenharmony_ci
2832c593315Sopenharmony_ci    if (head == nullptr) {
2842c593315Sopenharmony_ci      return 0;
2852c593315Sopenharmony_ci    }
2862c593315Sopenharmony_ci
2872c593315Sopenharmony_ci    auto n = len;
2882c593315Sopenharmony_ci
2892c593315Sopenharmony_ci    if (dest.tail == nullptr) {
2902c593315Sopenharmony_ci      dest.head = head;
2912c593315Sopenharmony_ci    } else {
2922c593315Sopenharmony_ci      dest.tail->next = head;
2932c593315Sopenharmony_ci    }
2942c593315Sopenharmony_ci
2952c593315Sopenharmony_ci    dest.tail = tail;
2962c593315Sopenharmony_ci    dest.len += len;
2972c593315Sopenharmony_ci
2982c593315Sopenharmony_ci    head = tail = nullptr;
2992c593315Sopenharmony_ci    len = 0;
3002c593315Sopenharmony_ci
3012c593315Sopenharmony_ci    return n;
3022c593315Sopenharmony_ci  }
3032c593315Sopenharmony_ci  size_t drain(size_t count) {
3042c593315Sopenharmony_ci    assert(mark == nullptr);
3052c593315Sopenharmony_ci
3062c593315Sopenharmony_ci    auto ndata = count;
3072c593315Sopenharmony_ci    auto m = head;
3082c593315Sopenharmony_ci    while (m) {
3092c593315Sopenharmony_ci      auto next = m->next;
3102c593315Sopenharmony_ci      auto n = std::min(count, m->len());
3112c593315Sopenharmony_ci      m->pos += n;
3122c593315Sopenharmony_ci      count -= n;
3132c593315Sopenharmony_ci      len -= n;
3142c593315Sopenharmony_ci      if (m->len() > 0) {
3152c593315Sopenharmony_ci        break;
3162c593315Sopenharmony_ci      }
3172c593315Sopenharmony_ci
3182c593315Sopenharmony_ci      pool->recycle(m);
3192c593315Sopenharmony_ci      m = next;
3202c593315Sopenharmony_ci    }
3212c593315Sopenharmony_ci    head = m;
3222c593315Sopenharmony_ci    if (head == nullptr) {
3232c593315Sopenharmony_ci      tail = nullptr;
3242c593315Sopenharmony_ci    }
3252c593315Sopenharmony_ci    return ndata - count;
3262c593315Sopenharmony_ci  }
3272c593315Sopenharmony_ci  size_t drain_mark(size_t count) {
3282c593315Sopenharmony_ci    auto ndata = count;
3292c593315Sopenharmony_ci    auto m = head;
3302c593315Sopenharmony_ci    while (m) {
3312c593315Sopenharmony_ci      auto next = m->next;
3322c593315Sopenharmony_ci      auto n = std::min(count, m->len());
3332c593315Sopenharmony_ci      m->pos += n;
3342c593315Sopenharmony_ci      count -= n;
3352c593315Sopenharmony_ci      len -= n;
3362c593315Sopenharmony_ci      mark_offset -= n;
3372c593315Sopenharmony_ci
3382c593315Sopenharmony_ci      if (m->len() > 0) {
3392c593315Sopenharmony_ci        assert(mark != m || m->pos <= mark_pos);
3402c593315Sopenharmony_ci        break;
3412c593315Sopenharmony_ci      }
3422c593315Sopenharmony_ci      if (mark == m) {
3432c593315Sopenharmony_ci        assert(m->pos <= mark_pos);
3442c593315Sopenharmony_ci
3452c593315Sopenharmony_ci        mark = nullptr;
3462c593315Sopenharmony_ci        mark_pos = nullptr;
3472c593315Sopenharmony_ci        mark_offset = 0;
3482c593315Sopenharmony_ci      }
3492c593315Sopenharmony_ci
3502c593315Sopenharmony_ci      pool->recycle(m);
3512c593315Sopenharmony_ci      m = next;
3522c593315Sopenharmony_ci    }
3532c593315Sopenharmony_ci    head = m;
3542c593315Sopenharmony_ci    if (head == nullptr) {
3552c593315Sopenharmony_ci      tail = nullptr;
3562c593315Sopenharmony_ci    }
3572c593315Sopenharmony_ci    return ndata - count;
3582c593315Sopenharmony_ci  }
3592c593315Sopenharmony_ci  int riovec(struct iovec *iov, int iovcnt) const {
3602c593315Sopenharmony_ci    if (!head) {
3612c593315Sopenharmony_ci      return 0;
3622c593315Sopenharmony_ci    }
3632c593315Sopenharmony_ci    auto m = head;
3642c593315Sopenharmony_ci    int i;
3652c593315Sopenharmony_ci    for (i = 0; i < iovcnt && m; ++i, m = m->next) {
3662c593315Sopenharmony_ci      iov[i].iov_base = m->pos;
3672c593315Sopenharmony_ci      iov[i].iov_len = m->len();
3682c593315Sopenharmony_ci    }
3692c593315Sopenharmony_ci    return i;
3702c593315Sopenharmony_ci  }
3712c593315Sopenharmony_ci  int riovec_mark(struct iovec *iov, int iovcnt) {
3722c593315Sopenharmony_ci    if (!head || iovcnt == 0) {
3732c593315Sopenharmony_ci      return 0;
3742c593315Sopenharmony_ci    }
3752c593315Sopenharmony_ci
3762c593315Sopenharmony_ci    int i = 0;
3772c593315Sopenharmony_ci    Memchunk *m;
3782c593315Sopenharmony_ci    if (mark) {
3792c593315Sopenharmony_ci      if (mark_pos != mark->last) {
3802c593315Sopenharmony_ci        iov[0].iov_base = mark_pos;
3812c593315Sopenharmony_ci        iov[0].iov_len = mark->len() - (mark_pos - mark->pos);
3822c593315Sopenharmony_ci
3832c593315Sopenharmony_ci        mark_pos = mark->last;
3842c593315Sopenharmony_ci        mark_offset += iov[0].iov_len;
3852c593315Sopenharmony_ci        i = 1;
3862c593315Sopenharmony_ci      }
3872c593315Sopenharmony_ci      m = mark->next;
3882c593315Sopenharmony_ci    } else {
3892c593315Sopenharmony_ci      i = 0;
3902c593315Sopenharmony_ci      m = head;
3912c593315Sopenharmony_ci    }
3922c593315Sopenharmony_ci
3932c593315Sopenharmony_ci    for (; i < iovcnt && m; ++i, m = m->next) {
3942c593315Sopenharmony_ci      iov[i].iov_base = m->pos;
3952c593315Sopenharmony_ci      iov[i].iov_len = m->len();
3962c593315Sopenharmony_ci
3972c593315Sopenharmony_ci      mark = m;
3982c593315Sopenharmony_ci      mark_pos = m->last;
3992c593315Sopenharmony_ci      mark_offset += m->len();
4002c593315Sopenharmony_ci    }
4012c593315Sopenharmony_ci
4022c593315Sopenharmony_ci    return i;
4032c593315Sopenharmony_ci  }
4042c593315Sopenharmony_ci  size_t rleft() const { return len; }
4052c593315Sopenharmony_ci  size_t rleft_mark() const { return len - mark_offset; }
4062c593315Sopenharmony_ci  void reset() {
4072c593315Sopenharmony_ci    for (auto m = head; m;) {
4082c593315Sopenharmony_ci      auto next = m->next;
4092c593315Sopenharmony_ci      pool->recycle(m);
4102c593315Sopenharmony_ci      m = next;
4112c593315Sopenharmony_ci    }
4122c593315Sopenharmony_ci    len = 0;
4132c593315Sopenharmony_ci    head = tail = mark = nullptr;
4142c593315Sopenharmony_ci    mark_pos = nullptr;
4152c593315Sopenharmony_ci    mark_offset = 0;
4162c593315Sopenharmony_ci  }
4172c593315Sopenharmony_ci
4182c593315Sopenharmony_ci  Pool<Memchunk> *pool;
4192c593315Sopenharmony_ci  Memchunk *head, *tail;
4202c593315Sopenharmony_ci  size_t len;
4212c593315Sopenharmony_ci  Memchunk *mark;
4222c593315Sopenharmony_ci  uint8_t *mark_pos;
4232c593315Sopenharmony_ci  size_t mark_offset;
4242c593315Sopenharmony_ci};
4252c593315Sopenharmony_ci
4262c593315Sopenharmony_ci// Wrapper around Memchunks to offer "peeking" functionality.
4272c593315Sopenharmony_citemplate <typename Memchunk> struct PeekMemchunks {
4282c593315Sopenharmony_ci  PeekMemchunks(Pool<Memchunk> *pool)
4292c593315Sopenharmony_ci      : memchunks(pool),
4302c593315Sopenharmony_ci        cur(nullptr),
4312c593315Sopenharmony_ci        cur_pos(nullptr),
4322c593315Sopenharmony_ci        cur_last(nullptr),
4332c593315Sopenharmony_ci        len(0),
4342c593315Sopenharmony_ci        peeking(true) {}
4352c593315Sopenharmony_ci  PeekMemchunks(const PeekMemchunks &) = delete;
4362c593315Sopenharmony_ci  PeekMemchunks(PeekMemchunks &&other) noexcept
4372c593315Sopenharmony_ci      : memchunks{std::move(other.memchunks)},
4382c593315Sopenharmony_ci        cur{std::exchange(other.cur, nullptr)},
4392c593315Sopenharmony_ci        cur_pos{std::exchange(other.cur_pos, nullptr)},
4402c593315Sopenharmony_ci        cur_last{std::exchange(other.cur_last, nullptr)},
4412c593315Sopenharmony_ci        len{std::exchange(other.len, 0)},
4422c593315Sopenharmony_ci        peeking{std::exchange(other.peeking, true)} {}
4432c593315Sopenharmony_ci  PeekMemchunks &operator=(const PeekMemchunks &) = delete;
4442c593315Sopenharmony_ci  PeekMemchunks &operator=(PeekMemchunks &&other) noexcept {
4452c593315Sopenharmony_ci    if (this == &other) {
4462c593315Sopenharmony_ci      return *this;
4472c593315Sopenharmony_ci    }
4482c593315Sopenharmony_ci
4492c593315Sopenharmony_ci    memchunks = std::move(other.memchunks);
4502c593315Sopenharmony_ci    cur = std::exchange(other.cur, nullptr);
4512c593315Sopenharmony_ci    cur_pos = std::exchange(other.cur_pos, nullptr);
4522c593315Sopenharmony_ci    cur_last = std::exchange(other.cur_last, nullptr);
4532c593315Sopenharmony_ci    len = std::exchange(other.len, 0);
4542c593315Sopenharmony_ci    peeking = std::exchange(other.peeking, true);
4552c593315Sopenharmony_ci
4562c593315Sopenharmony_ci    return *this;
4572c593315Sopenharmony_ci  }
4582c593315Sopenharmony_ci  size_t append(const void *src, size_t count) {
4592c593315Sopenharmony_ci    count = memchunks.append(src, count);
4602c593315Sopenharmony_ci    len += count;
4612c593315Sopenharmony_ci    return count;
4622c593315Sopenharmony_ci  }
4632c593315Sopenharmony_ci  size_t remove(void *dest, size_t count) {
4642c593315Sopenharmony_ci    if (!peeking) {
4652c593315Sopenharmony_ci      count = memchunks.remove(dest, count);
4662c593315Sopenharmony_ci      len -= count;
4672c593315Sopenharmony_ci      return count;
4682c593315Sopenharmony_ci    }
4692c593315Sopenharmony_ci
4702c593315Sopenharmony_ci    if (count == 0 || len == 0) {
4712c593315Sopenharmony_ci      return 0;
4722c593315Sopenharmony_ci    }
4732c593315Sopenharmony_ci
4742c593315Sopenharmony_ci    if (!cur) {
4752c593315Sopenharmony_ci      cur = memchunks.head;
4762c593315Sopenharmony_ci      cur_pos = cur->pos;
4772c593315Sopenharmony_ci    }
4782c593315Sopenharmony_ci
4792c593315Sopenharmony_ci    // cur_last could be updated in append
4802c593315Sopenharmony_ci    cur_last = cur->last;
4812c593315Sopenharmony_ci
4822c593315Sopenharmony_ci    if (cur_pos == cur_last) {
4832c593315Sopenharmony_ci      assert(cur->next);
4842c593315Sopenharmony_ci      cur = cur->next;
4852c593315Sopenharmony_ci    }
4862c593315Sopenharmony_ci
4872c593315Sopenharmony_ci    auto first = static_cast<uint8_t *>(dest);
4882c593315Sopenharmony_ci    auto last = first + count;
4892c593315Sopenharmony_ci
4902c593315Sopenharmony_ci    for (;;) {
4912c593315Sopenharmony_ci      auto n = std::min(last - first, cur_last - cur_pos);
4922c593315Sopenharmony_ci
4932c593315Sopenharmony_ci      first = std::copy_n(cur_pos, n, first);
4942c593315Sopenharmony_ci      cur_pos += n;
4952c593315Sopenharmony_ci      len -= n;
4962c593315Sopenharmony_ci
4972c593315Sopenharmony_ci      if (first == last) {
4982c593315Sopenharmony_ci        break;
4992c593315Sopenharmony_ci      }
5002c593315Sopenharmony_ci      assert(cur_pos == cur_last);
5012c593315Sopenharmony_ci      if (!cur->next) {
5022c593315Sopenharmony_ci        break;
5032c593315Sopenharmony_ci      }
5042c593315Sopenharmony_ci      cur = cur->next;
5052c593315Sopenharmony_ci      cur_pos = cur->pos;
5062c593315Sopenharmony_ci      cur_last = cur->last;
5072c593315Sopenharmony_ci    }
5082c593315Sopenharmony_ci    return first - static_cast<uint8_t *>(dest);
5092c593315Sopenharmony_ci  }
5102c593315Sopenharmony_ci  size_t rleft() const { return len; }
5112c593315Sopenharmony_ci  size_t rleft_buffered() const { return memchunks.rleft(); }
5122c593315Sopenharmony_ci  void disable_peek(bool drain) {
5132c593315Sopenharmony_ci    if (!peeking) {
5142c593315Sopenharmony_ci      return;
5152c593315Sopenharmony_ci    }
5162c593315Sopenharmony_ci    if (drain) {
5172c593315Sopenharmony_ci      auto n = rleft_buffered() - rleft();
5182c593315Sopenharmony_ci      memchunks.drain(n);
5192c593315Sopenharmony_ci      assert(len == memchunks.rleft());
5202c593315Sopenharmony_ci    } else {
5212c593315Sopenharmony_ci      len = memchunks.rleft();
5222c593315Sopenharmony_ci    }
5232c593315Sopenharmony_ci    cur = nullptr;
5242c593315Sopenharmony_ci    cur_pos = cur_last = nullptr;
5252c593315Sopenharmony_ci    peeking = false;
5262c593315Sopenharmony_ci  }
5272c593315Sopenharmony_ci  void reset() {
5282c593315Sopenharmony_ci    memchunks.reset();
5292c593315Sopenharmony_ci    cur = nullptr;
5302c593315Sopenharmony_ci    cur_pos = cur_last = nullptr;
5312c593315Sopenharmony_ci    len = 0;
5322c593315Sopenharmony_ci    peeking = true;
5332c593315Sopenharmony_ci  }
5342c593315Sopenharmony_ci  Memchunks<Memchunk> memchunks;
5352c593315Sopenharmony_ci  // Pointer to the Memchunk currently we are reading/writing.
5362c593315Sopenharmony_ci  Memchunk *cur;
5372c593315Sopenharmony_ci  // Region inside cur, we have processed to cur_pos.
5382c593315Sopenharmony_ci  uint8_t *cur_pos, *cur_last;
5392c593315Sopenharmony_ci  // This is the length we have left unprocessed.  len <=
5402c593315Sopenharmony_ci  // memchunk.rleft() must hold.
5412c593315Sopenharmony_ci  size_t len;
5422c593315Sopenharmony_ci  // true if peeking is enabled.  Initially it is true.
5432c593315Sopenharmony_ci  bool peeking;
5442c593315Sopenharmony_ci};
5452c593315Sopenharmony_ci
5462c593315Sopenharmony_ciusing Memchunk16K = Memchunk<16_k>;
5472c593315Sopenharmony_ciusing MemchunkPool = Pool<Memchunk16K>;
5482c593315Sopenharmony_ciusing DefaultMemchunks = Memchunks<Memchunk16K>;
5492c593315Sopenharmony_ciusing DefaultPeekMemchunks = PeekMemchunks<Memchunk16K>;
5502c593315Sopenharmony_ci
5512c593315Sopenharmony_ciinline int limit_iovec(struct iovec *iov, int iovcnt, size_t max) {
5522c593315Sopenharmony_ci  if (max == 0) {
5532c593315Sopenharmony_ci    return 0;
5542c593315Sopenharmony_ci  }
5552c593315Sopenharmony_ci  for (int i = 0; i < iovcnt; ++i) {
5562c593315Sopenharmony_ci    auto d = std::min(max, iov[i].iov_len);
5572c593315Sopenharmony_ci    iov[i].iov_len = d;
5582c593315Sopenharmony_ci    max -= d;
5592c593315Sopenharmony_ci    if (max == 0) {
5602c593315Sopenharmony_ci      return i + 1;
5612c593315Sopenharmony_ci    }
5622c593315Sopenharmony_ci  }
5632c593315Sopenharmony_ci  return iovcnt;
5642c593315Sopenharmony_ci}
5652c593315Sopenharmony_ci
5662c593315Sopenharmony_ci// MemchunkBuffer is similar to Buffer, but it uses pooled Memchunk
5672c593315Sopenharmony_ci// for its underlying buffer.
5682c593315Sopenharmony_citemplate <typename Memchunk> struct MemchunkBuffer {
5692c593315Sopenharmony_ci  MemchunkBuffer(Pool<Memchunk> *pool) : pool(pool), chunk(nullptr) {}
5702c593315Sopenharmony_ci  MemchunkBuffer(const MemchunkBuffer &) = delete;
5712c593315Sopenharmony_ci  MemchunkBuffer(MemchunkBuffer &&other) noexcept
5722c593315Sopenharmony_ci      : pool(other.pool), chunk(other.chunk) {
5732c593315Sopenharmony_ci    other.chunk = nullptr;
5742c593315Sopenharmony_ci  }
5752c593315Sopenharmony_ci  MemchunkBuffer &operator=(const MemchunkBuffer &) = delete;
5762c593315Sopenharmony_ci  MemchunkBuffer &operator=(MemchunkBuffer &&other) noexcept {
5772c593315Sopenharmony_ci    if (this == &other) {
5782c593315Sopenharmony_ci      return *this;
5792c593315Sopenharmony_ci    }
5802c593315Sopenharmony_ci
5812c593315Sopenharmony_ci    pool = other.pool;
5822c593315Sopenharmony_ci    chunk = other.chunk;
5832c593315Sopenharmony_ci
5842c593315Sopenharmony_ci    other.chunk = nullptr;
5852c593315Sopenharmony_ci
5862c593315Sopenharmony_ci    return *this;
5872c593315Sopenharmony_ci  }
5882c593315Sopenharmony_ci
5892c593315Sopenharmony_ci  ~MemchunkBuffer() {
5902c593315Sopenharmony_ci    if (!pool || !chunk) {
5912c593315Sopenharmony_ci      return;
5922c593315Sopenharmony_ci    }
5932c593315Sopenharmony_ci    pool->recycle(chunk);
5942c593315Sopenharmony_ci  }
5952c593315Sopenharmony_ci
5962c593315Sopenharmony_ci  // Ensures that the underlying buffer is allocated.
5972c593315Sopenharmony_ci  void ensure_chunk() {
5982c593315Sopenharmony_ci    if (chunk) {
5992c593315Sopenharmony_ci      return;
6002c593315Sopenharmony_ci    }
6012c593315Sopenharmony_ci    chunk = pool->get();
6022c593315Sopenharmony_ci  }
6032c593315Sopenharmony_ci
6042c593315Sopenharmony_ci  // Releases the underlying buffer.
6052c593315Sopenharmony_ci  void release_chunk() {
6062c593315Sopenharmony_ci    if (!chunk) {
6072c593315Sopenharmony_ci      return;
6082c593315Sopenharmony_ci    }
6092c593315Sopenharmony_ci    pool->recycle(chunk);
6102c593315Sopenharmony_ci    chunk = nullptr;
6112c593315Sopenharmony_ci  }
6122c593315Sopenharmony_ci
6132c593315Sopenharmony_ci  // Returns true if the underlying buffer is allocated.
6142c593315Sopenharmony_ci  bool chunk_avail() const { return chunk != nullptr; }
6152c593315Sopenharmony_ci
6162c593315Sopenharmony_ci  // The functions below must be called after the underlying buffer is
6172c593315Sopenharmony_ci  // allocated (use ensure_chunk).
6182c593315Sopenharmony_ci
6192c593315Sopenharmony_ci  // MemchunkBuffer provides the same interface functions with Buffer.
6202c593315Sopenharmony_ci  // Since we has chunk as a member variable, pos and last are
6212c593315Sopenharmony_ci  // implemented as wrapper functions.
6222c593315Sopenharmony_ci
6232c593315Sopenharmony_ci  uint8_t *pos() const { return chunk->pos; }
6242c593315Sopenharmony_ci  uint8_t *last() const { return chunk->last; }
6252c593315Sopenharmony_ci
6262c593315Sopenharmony_ci  size_t rleft() const { return chunk->len(); }
6272c593315Sopenharmony_ci  size_t wleft() const { return chunk->left(); }
6282c593315Sopenharmony_ci  size_t write(const void *src, size_t count) {
6292c593315Sopenharmony_ci    count = std::min(count, wleft());
6302c593315Sopenharmony_ci    auto p = static_cast<const uint8_t *>(src);
6312c593315Sopenharmony_ci    chunk->last = std::copy_n(p, count, chunk->last);
6322c593315Sopenharmony_ci    return count;
6332c593315Sopenharmony_ci  }
6342c593315Sopenharmony_ci  size_t write(size_t count) {
6352c593315Sopenharmony_ci    count = std::min(count, wleft());
6362c593315Sopenharmony_ci    chunk->last += count;
6372c593315Sopenharmony_ci    return count;
6382c593315Sopenharmony_ci  }
6392c593315Sopenharmony_ci  size_t drain(size_t count) {
6402c593315Sopenharmony_ci    count = std::min(count, rleft());
6412c593315Sopenharmony_ci    chunk->pos += count;
6422c593315Sopenharmony_ci    return count;
6432c593315Sopenharmony_ci  }
6442c593315Sopenharmony_ci  size_t drain_reset(size_t count) {
6452c593315Sopenharmony_ci    count = std::min(count, rleft());
6462c593315Sopenharmony_ci    std::copy(chunk->pos + count, chunk->last, std::begin(chunk->buf));
6472c593315Sopenharmony_ci    chunk->last = std::begin(chunk->buf) + (chunk->last - (chunk->pos + count));
6482c593315Sopenharmony_ci    chunk->pos = std::begin(chunk->buf);
6492c593315Sopenharmony_ci    return count;
6502c593315Sopenharmony_ci  }
6512c593315Sopenharmony_ci  void reset() { chunk->reset(); }
6522c593315Sopenharmony_ci  uint8_t *begin() { return std::begin(chunk->buf); }
6532c593315Sopenharmony_ci  uint8_t &operator[](size_t n) { return chunk->buf[n]; }
6542c593315Sopenharmony_ci  const uint8_t &operator[](size_t n) const { return chunk->buf[n]; }
6552c593315Sopenharmony_ci
6562c593315Sopenharmony_ci  Pool<Memchunk> *pool;
6572c593315Sopenharmony_ci  Memchunk *chunk;
6582c593315Sopenharmony_ci};
6592c593315Sopenharmony_ci
6602c593315Sopenharmony_ciusing DefaultMemchunkBuffer = MemchunkBuffer<Memchunk16K>;
6612c593315Sopenharmony_ci
6622c593315Sopenharmony_ci} // namespace nghttp2
6632c593315Sopenharmony_ci
6642c593315Sopenharmony_ci#endif // MEMCHUNK_H
665