1 /*
2  * nghttp3
3  *
4  * Copyright (c) 2019 nghttp3 contributors
5  * Copyright (c) 2017 ngtcp2 contributors
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  */
26 #include "nghttp3_ringbuf.h"
27 
28 #include <assert.h>
29 #include <string.h>
30 #ifdef WIN32
31 #  include <intrin.h>
32 #endif
33 
34 #include "nghttp3_macro.h"
35 
36 #if defined(_MSC_VER) && defined(_M_ARM64)
__popcnt(unsigned int x)37 unsigned int __popcnt(unsigned int x) {
38   unsigned int c = 0;
39   for (; x; ++c) {
40     x &= x - 1;
41   }
42   return c;
43 }
44 #endif
45 
nghttp3_ringbuf_init(nghttp3_ringbuf * rb,size_t nmemb,size_t size,const nghttp3_mem * mem)46 int nghttp3_ringbuf_init(nghttp3_ringbuf *rb, size_t nmemb, size_t size,
47                          const nghttp3_mem *mem) {
48   if (nmemb) {
49 #ifdef WIN32
50     assert(1 == __popcnt((unsigned int)nmemb));
51 #else
52     assert(1 == __builtin_popcount((unsigned int)nmemb));
53 #endif
54 
55     rb->buf = nghttp3_mem_malloc(mem, nmemb * size);
56     if (rb->buf == NULL) {
57       return NGHTTP3_ERR_NOMEM;
58     }
59   } else {
60     rb->buf = NULL;
61   }
62 
63   rb->mem = mem;
64   rb->nmemb = nmemb;
65   rb->size = size;
66   rb->first = 0;
67   rb->len = 0;
68 
69   return 0;
70 }
71 
nghttp3_ringbuf_free(nghttp3_ringbuf * rb)72 void nghttp3_ringbuf_free(nghttp3_ringbuf *rb) {
73   if (rb == NULL) {
74     return;
75   }
76 
77   nghttp3_mem_free(rb->mem, rb->buf);
78 }
79 
nghttp3_ringbuf_push_front(nghttp3_ringbuf * rb)80 void *nghttp3_ringbuf_push_front(nghttp3_ringbuf *rb) {
81   rb->first = (rb->first - 1) & (rb->nmemb - 1);
82   rb->len = nghttp3_min(rb->nmemb, rb->len + 1);
83 
84   return (void *)&rb->buf[rb->first * rb->size];
85 }
86 
nghttp3_ringbuf_push_back(nghttp3_ringbuf * rb)87 void *nghttp3_ringbuf_push_back(nghttp3_ringbuf *rb) {
88   size_t offset = (rb->first + rb->len) & (rb->nmemb - 1);
89 
90   if (rb->len == rb->nmemb) {
91     rb->first = (rb->first + 1) & (rb->nmemb - 1);
92   } else {
93     ++rb->len;
94   }
95 
96   return (void *)&rb->buf[offset * rb->size];
97 }
98 
nghttp3_ringbuf_pop_front(nghttp3_ringbuf * rb)99 void nghttp3_ringbuf_pop_front(nghttp3_ringbuf *rb) {
100   rb->first = (rb->first + 1) & (rb->nmemb - 1);
101   --rb->len;
102 }
103 
nghttp3_ringbuf_pop_back(nghttp3_ringbuf * rb)104 void nghttp3_ringbuf_pop_back(nghttp3_ringbuf *rb) {
105   assert(rb->len);
106   --rb->len;
107 }
108 
nghttp3_ringbuf_resize(nghttp3_ringbuf * rb,size_t len)109 void nghttp3_ringbuf_resize(nghttp3_ringbuf *rb, size_t len) {
110   assert(len <= rb->nmemb);
111   rb->len = len;
112 }
113 
nghttp3_ringbuf_get(nghttp3_ringbuf * rb,size_t offset)114 void *nghttp3_ringbuf_get(nghttp3_ringbuf *rb, size_t offset) {
115   assert(offset < rb->len);
116   offset = (rb->first + offset) & (rb->nmemb - 1);
117   return &rb->buf[offset * rb->size];
118 }
119 
nghttp3_ringbuf_full(nghttp3_ringbuf * rb)120 int nghttp3_ringbuf_full(nghttp3_ringbuf *rb) { return rb->len == rb->nmemb; }
121 
nghttp3_ringbuf_reserve(nghttp3_ringbuf * rb,size_t nmemb)122 int nghttp3_ringbuf_reserve(nghttp3_ringbuf *rb, size_t nmemb) {
123   uint8_t *buf;
124 
125   if (rb->nmemb >= nmemb) {
126     return 0;
127   }
128 
129 #ifdef WIN32
130   assert(1 == __popcnt((unsigned int)nmemb));
131 #else
132   assert(1 == __builtin_popcount((unsigned int)nmemb));
133 #endif
134 
135   buf = nghttp3_mem_malloc(rb->mem, nmemb * rb->size);
136   if (buf == NULL) {
137     return NGHTTP3_ERR_NOMEM;
138   }
139 
140   if (rb->buf != NULL) {
141     if (rb->first + rb->len <= rb->nmemb) {
142       memcpy(buf, rb->buf + rb->first * rb->size, rb->len * rb->size);
143       rb->first = 0;
144     } else {
145       memcpy(buf, rb->buf + rb->first * rb->size,
146              (rb->nmemb - rb->first) * rb->size);
147       memcpy(buf + (rb->nmemb - rb->first) * rb->size, rb->buf,
148              (rb->len - (rb->nmemb - rb->first)) * rb->size);
149       rb->first = 0;
150     }
151 
152     nghttp3_mem_free(rb->mem, rb->buf);
153   }
154 
155   rb->buf = buf;
156   rb->nmemb = nmemb;
157 
158   return 0;
159 }
160