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