summaryrefslogtreecommitdiffstats
path: root/lib/ngtcp2_vec.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ngtcp2_vec.c')
-rw-r--r--lib/ngtcp2_vec.c243
1 files changed, 243 insertions, 0 deletions
diff --git a/lib/ngtcp2_vec.c b/lib/ngtcp2_vec.c
new file mode 100644
index 0000000..257332e
--- /dev/null
+++ b/lib/ngtcp2_vec.c
@@ -0,0 +1,243 @@
+/*
+ * ngtcp2
+ *
+ * Copyright (c) 2018 ngtcp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "ngtcp2_vec.h"
+
+#include <string.h>
+#include <assert.h>
+
+#include "ngtcp2_str.h"
+
+ngtcp2_vec *ngtcp2_vec_init(ngtcp2_vec *vec, const uint8_t *base, size_t len) {
+ vec->base = (uint8_t *)base;
+ vec->len = len;
+ return vec;
+}
+
+int ngtcp2_vec_new(ngtcp2_vec **pvec, const uint8_t *data, size_t datalen,
+ const ngtcp2_mem *mem) {
+ size_t len;
+ uint8_t *p;
+
+ len = sizeof(ngtcp2_vec) + datalen;
+
+ *pvec = ngtcp2_mem_malloc(mem, len);
+ if (*pvec == NULL) {
+ return NGTCP2_ERR_NOMEM;
+ }
+
+ p = (uint8_t *)(*pvec) + sizeof(ngtcp2_vec);
+ (*pvec)->base = p;
+ (*pvec)->len = datalen;
+ if (datalen) {
+ /* p = */ ngtcp2_cpymem(p, data, datalen);
+ }
+
+ return 0;
+}
+
+void ngtcp2_vec_del(ngtcp2_vec *vec, const ngtcp2_mem *mem) {
+ ngtcp2_mem_free(mem, vec);
+}
+
+uint64_t ngtcp2_vec_len(const ngtcp2_vec *vec, size_t n) {
+ size_t i;
+ size_t res = 0;
+
+ for (i = 0; i < n; ++i) {
+ res += vec[i].len;
+ }
+
+ return res;
+}
+
+int64_t ngtcp2_vec_len_varint(const ngtcp2_vec *vec, size_t n) {
+ uint64_t res = 0;
+ size_t len;
+ size_t i;
+
+ for (i = 0; i < n; ++i) {
+ len = vec[i].len;
+ if (len > NGTCP2_MAX_VARINT - res) {
+ return -1;
+ }
+
+ res += len;
+ }
+
+ return (int64_t)res;
+}
+
+ngtcp2_ssize ngtcp2_vec_split(ngtcp2_vec *src, size_t *psrccnt, ngtcp2_vec *dst,
+ size_t *pdstcnt, size_t left, size_t maxcnt) {
+ size_t i;
+ size_t srccnt = *psrccnt;
+ size_t nmove;
+ size_t extra = 0;
+
+ for (i = 0; i < srccnt; ++i) {
+ if (left >= src[i].len) {
+ left -= src[i].len;
+ continue;
+ }
+
+ if (*pdstcnt && src[srccnt - 1].base + src[srccnt - 1].len == dst[0].base) {
+ if (*pdstcnt + srccnt - i - 1 > maxcnt) {
+ return -1;
+ }
+
+ dst[0].len += src[srccnt - 1].len;
+ dst[0].base = src[srccnt - 1].base;
+ extra = src[srccnt - 1].len;
+ --srccnt;
+ } else if (*pdstcnt + srccnt - i > maxcnt) {
+ return -1;
+ }
+
+ if (left == 0) {
+ *psrccnt = i;
+ } else {
+ *psrccnt = i + 1;
+ }
+
+ nmove = srccnt - i;
+ if (nmove) {
+ memmove(dst + nmove, dst, sizeof(ngtcp2_vec) * (*pdstcnt));
+ *pdstcnt += nmove;
+ memcpy(dst, src + i, sizeof(ngtcp2_vec) * nmove);
+ }
+
+ dst[0].len -= left;
+ dst[0].base += left;
+ src[i].len = left;
+
+ if (nmove == 0) {
+ extra -= left;
+ }
+
+ return (ngtcp2_ssize)(ngtcp2_vec_len(dst, nmove) + extra);
+ }
+
+ return 0;
+}
+
+size_t ngtcp2_vec_merge(ngtcp2_vec *dst, size_t *pdstcnt, ngtcp2_vec *src,
+ size_t *psrccnt, size_t left, size_t maxcnt) {
+ size_t orig_left = left;
+ size_t i;
+ ngtcp2_vec *a, *b;
+
+ assert(maxcnt);
+
+ if (*pdstcnt == 0) {
+ if (*psrccnt == 0) {
+ return 0;
+ }
+
+ a = &dst[0];
+ b = &src[0];
+
+ if (left >= b->len) {
+ *a = *b;
+ ++*pdstcnt;
+ left -= b->len;
+ i = 1;
+ } else {
+ a->len = left;
+ a->base = b->base;
+
+ b->len -= left;
+ b->base += left;
+
+ return left;
+ }
+ } else {
+ i = 0;
+ }
+
+ for (; left && i < *psrccnt; ++i) {
+ a = &dst[*pdstcnt - 1];
+ b = &src[i];
+
+ if (left >= b->len) {
+ if (a->base + a->len == b->base) {
+ a->len += b->len;
+ } else if (*pdstcnt == maxcnt) {
+ break;
+ } else {
+ dst[(*pdstcnt)++] = *b;
+ }
+ left -= b->len;
+ continue;
+ }
+
+ if (a->base + a->len == b->base) {
+ a->len += left;
+ } else if (*pdstcnt == maxcnt) {
+ break;
+ } else {
+ dst[*pdstcnt].len = left;
+ dst[*pdstcnt].base = b->base;
+ ++*pdstcnt;
+ }
+
+ b->len -= left;
+ b->base += left;
+ left = 0;
+
+ break;
+ }
+
+ memmove(src, src + i, sizeof(ngtcp2_vec) * (*psrccnt - i));
+ *psrccnt -= i;
+
+ return orig_left - left;
+}
+
+size_t ngtcp2_vec_copy_at_most(ngtcp2_vec *dst, size_t dstcnt,
+ const ngtcp2_vec *src, size_t srccnt,
+ size_t left) {
+ size_t i, j;
+
+ for (i = 0, j = 0; left > 0 && i < srccnt && j < dstcnt;) {
+ if (src[i].len == 0) {
+ ++i;
+ continue;
+ }
+ dst[j] = src[i];
+ if (dst[j].len > left) {
+ dst[j].len = left;
+ return j + 1;
+ }
+ left -= dst[j].len;
+ ++i;
+ ++j;
+ }
+
+ return j;
+}
+
+void ngtcp2_vec_copy(ngtcp2_vec *dst, const ngtcp2_vec *src, size_t cnt) {
+ memcpy(dst, src, sizeof(ngtcp2_vec) * cnt);
+}