1 /*
2 * ngtcp2
3 *
4 * Copyright (c) 2017 ngtcp2 contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 #include "ngtcp2_ringbuf.h"
26
27 #include <assert.h>
28 #ifdef WIN32
29 # include <intrin.h>
30 #endif
31
32 #include "ngtcp2_macro.h"
33
34 #if defined(_MSC_VER) && defined(_M_ARM64)
__popcnt(unsigned int x)35 unsigned int __popcnt(unsigned int x) {
36 unsigned int c = 0;
37 for (; x; ++c) {
38 x &= x - 1;
39 }
40 return c;
41 }
42 #endif
43
ngtcp2_ringbuf_init(ngtcp2_ringbuf * rb,size_t nmemb,size_t size,const ngtcp2_mem * mem)44 int ngtcp2_ringbuf_init(ngtcp2_ringbuf *rb, size_t nmemb, size_t size,
45 const ngtcp2_mem *mem) {
46 #ifdef WIN32
47 assert(1 == __popcnt((unsigned int)nmemb));
48 #else
49 assert(1 == __builtin_popcount((unsigned int)nmemb));
50 #endif
51
52 rb->buf = ngtcp2_mem_malloc(mem, nmemb * size);
53 if (rb->buf == NULL) {
54 return NGTCP2_ERR_NOMEM;
55 }
56
57 rb->mem = mem;
58 rb->nmemb = nmemb;
59 rb->size = size;
60 rb->first = 0;
61 rb->len = 0;
62
63 return 0;
64 }
65
ngtcp2_ringbuf_free(ngtcp2_ringbuf * rb)66 void ngtcp2_ringbuf_free(ngtcp2_ringbuf *rb) {
67 if (rb == NULL) {
68 return;
69 }
70
71 ngtcp2_mem_free(rb->mem, rb->buf);
72 }
73
ngtcp2_ringbuf_push_front(ngtcp2_ringbuf * rb)74 void *ngtcp2_ringbuf_push_front(ngtcp2_ringbuf *rb) {
75 rb->first = (rb->first - 1) & (rb->nmemb - 1);
76 rb->len = ngtcp2_min(rb->nmemb, rb->len + 1);
77
78 return (void *)&rb->buf[rb->first * rb->size];
79 }
80
ngtcp2_ringbuf_push_back(ngtcp2_ringbuf * rb)81 void *ngtcp2_ringbuf_push_back(ngtcp2_ringbuf *rb) {
82 size_t offset = (rb->first + rb->len) & (rb->nmemb - 1);
83
84 if (rb->len == rb->nmemb) {
85 rb->first = (rb->first + 1) & (rb->nmemb - 1);
86 } else {
87 ++rb->len;
88 }
89
90 return (void *)&rb->buf[offset * rb->size];
91 }
92
ngtcp2_ringbuf_pop_front(ngtcp2_ringbuf * rb)93 void ngtcp2_ringbuf_pop_front(ngtcp2_ringbuf *rb) {
94 rb->first = (rb->first + 1) & (rb->nmemb - 1);
95 --rb->len;
96 }
97
ngtcp2_ringbuf_pop_back(ngtcp2_ringbuf * rb)98 void ngtcp2_ringbuf_pop_back(ngtcp2_ringbuf *rb) {
99 assert(rb->len);
100 --rb->len;
101 }
102
ngtcp2_ringbuf_resize(ngtcp2_ringbuf * rb,size_t len)103 void ngtcp2_ringbuf_resize(ngtcp2_ringbuf *rb, size_t len) {
104 assert(len <= rb->nmemb);
105 rb->len = len;
106 }
107
ngtcp2_ringbuf_get(ngtcp2_ringbuf * rb,size_t offset)108 void *ngtcp2_ringbuf_get(ngtcp2_ringbuf *rb, size_t offset) {
109 assert(offset < rb->len);
110 offset = (rb->first + offset) & (rb->nmemb - 1);
111 return &rb->buf[offset * rb->size];
112 }
113
ngtcp2_ringbuf_full(ngtcp2_ringbuf * rb)114 int ngtcp2_ringbuf_full(ngtcp2_ringbuf *rb) { return rb->len == rb->nmemb; }
115