1 /*
2 * Copyright (c) 2014,2015 DeNA Co., Ltd., Kazuho Oku, Justin Zhu
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 * IN THE SOFTWARE.
21 */
22 #ifndef h2o__memory_h
23 #define h2o__memory_h
24
25 #ifdef __sun__
26 #include <alloca.h>
27 #endif
28 #include <assert.h>
29 #include <inttypes.h>
30 #include <stddef.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35
36 #ifdef __cplusplus
37 extern "C" {
38 #endif
39
40 #define H2O_STRUCT_FROM_MEMBER(s, m, p) ((s *)((char *)(p)-offsetof(s, m)))
41 #define H2O_ALIGNOF(type) (__alignof__(type))
42
43 #if __GNUC__ >= 3
44 #define H2O_LIKELY(x) __builtin_expect(!!(x), 1)
45 #define H2O_UNLIKELY(x) __builtin_expect(!!(x), 0)
46 #else
47 #define H2O_LIKELY(x) (x)
48 #define H2O_UNLIKELY(x) (x)
49 #endif
50
51 #ifdef __GNUC__
52 #define H2O_GNUC_VERSION ((__GNUC__ << 16) | (__GNUC_MINOR__ << 8) | __GNUC_PATCHLEVEL__)
53 #else
54 #define H2O_GNUC_VERSION 0
55 #endif
56
57 #if __STDC_VERSION__ >= 201112L
58 #define H2O_NORETURN _Noreturn
59 #elif defined(__clang__) || defined(__GNUC__) && H2O_GNUC_VERSION >= 0x20500
60 // noreturn was not defined before gcc 2.5
61 #define H2O_NORETURN __attribute__((noreturn))
62 #else
63 #define H2O_NORETURN
64 #endif
65
66 #if !defined(__clang__) && defined(__GNUC__) && H2O_GNUC_VERSION >= 0x40900
67 // returns_nonnull was seemingly not defined before gcc 4.9 (exists in 4.9.1 but not in 4.8.2)
68 #define H2O_RETURNS_NONNULL __attribute__((returns_nonnull))
69 #else
70 #define H2O_RETURNS_NONNULL
71 #endif
72
73 #define H2O_TO__STR(n) #n
74 #define H2O_TO_STR(n) H2O_TO__STR(n)
75
76 #define H2O_BUILD_ASSERT(condition) ((void)sizeof(char[2 * !!(!__builtin_constant_p(condition) || (condition)) - 1]))
77
78 /**
79 * library users can use their own log method by define this macro
80 */
81 #ifndef h2o_error_printf
82 #define h2o_error_printf(...) fprintf(stderr, __VA_ARGS__)
83 #endif
84
85 typedef struct st_h2o_buffer_prototype_t h2o_buffer_prototype_t;
86
87 /**
88 * buffer structure compatible with iovec
89 */
90 typedef struct st_h2o_iovec_t {
91 char *base;
92 size_t len;
93 } h2o_iovec_t;
94
95 typedef struct st_h2o_mem_recycle_t {
96 size_t max;
97 size_t cnt;
98 struct st_h2o_mem_recycle_chunk_t *_link;
99 } h2o_mem_recycle_t;
100
101 struct st_h2o_mem_pool_shared_entry_t {
102 size_t refcnt;
103 void (*dispose)(void *);
104 char bytes[1];
105 };
106
107 /**
108 * the memory pool
109 */
110 union un_h2o_mem_pool_chunk_t;
111 typedef struct st_h2o_mem_pool_t {
112 union un_h2o_mem_pool_chunk_t *chunks;
113 size_t chunk_offset;
114 struct st_h2o_mem_pool_shared_ref_t *shared_refs;
115 struct st_h2o_mem_pool_direct_t *directs;
116 } h2o_mem_pool_t;
117
118 /**
119 * buffer used to store incoming / outgoing octets
120 */
121 typedef struct st_h2o_buffer_t {
122 /**
123 * when `bytes` != NULL (and therefore `size` != 0), the capacity of the buffer, or otherwise the minimum initial capacity in
124 * case of a prototype, or the desired next capacity if not a prototype.
125 */
126 size_t capacity;
127 /**
128 * amount of the data available
129 */
130 size_t size;
131 /**
132 * pointer to the start of the data (or NULL if is pointing to a prototype)
133 */
134 char *bytes;
135 /**
136 * prototype (or NULL if the instance is part of the prototype)
137 */
138 h2o_buffer_prototype_t *_prototype;
139 /**
140 * file descriptor (if not -1, h2o_buffer_t is a memory map of the contents of this file descriptor)
141 */
142 int _fd;
143 /**
144 * memory used to store data
145 */
146 char _buf[1];
147 } h2o_buffer_t;
148
149 #define H2O_TMP_FILE_TEMPLATE_MAX 256
150 typedef struct st_h2o_buffer_mmap_settings_t {
151 size_t threshold;
152 char fn_template[H2O_TMP_FILE_TEMPLATE_MAX];
153 } h2o_buffer_mmap_settings_t;
154
155 struct st_h2o_buffer_prototype_t {
156 h2o_buffer_t _initial_buf;
157 h2o_buffer_mmap_settings_t *mmap_settings;
158 };
159
160 typedef struct st_h2o_doublebuffer_t {
161 h2o_buffer_t *buf;
162 unsigned char inflight : 1;
163 size_t _bytes_inflight;
164 } h2o_doublebuffer_t;
165
166 #define H2O_VECTOR(type) \
167 struct { \
168 type *entries; \
169 size_t size; \
170 size_t capacity; \
171 }
172
173 typedef H2O_VECTOR(void) h2o_vector_t;
174 typedef H2O_VECTOR(uint8_t) h2o_byte_vector_t;
175 typedef H2O_VECTOR(h2o_iovec_t) h2o_iovec_vector_t;
176
177 extern void *(*volatile h2o_mem__set_secure)(void *, int, size_t);
178
179 /**
180 * prints an error message and aborts
181 */
182 H2O_NORETURN void h2o__fatal(const char *file, int line, const char *msg, ...) __attribute__((format(printf, 3, 4)));
183 #ifndef h2o_fatal
184 #define h2o_fatal(...) h2o__fatal(__FILE__, __LINE__, __VA_ARGS__)
185 #endif
186
187 void h2o_perror(const char *msg);
188 char *h2o_strerror_r(int err, char *buf, size_t len);
189
190 /**
191 * A version of memcpy that can take a NULL @src to avoid UB
192 */
193 static void *h2o_memcpy(void *dst, const void *src, size_t n);
194 /**
195 * constructor for h2o_iovec_t
196 */
197 static h2o_iovec_t h2o_iovec_init(const void *base, size_t len);
198 /**
199 * wrapper of malloc; allocates given size of memory or dies if impossible
200 */
201 H2O_RETURNS_NONNULL static void *h2o_mem_alloc(size_t sz);
202 /**
203 * warpper of realloc; reallocs the given chunk or dies if impossible
204 */
205 static void *h2o_mem_realloc(void *oldp, size_t sz);
206
207 /**
208 * allocates memory using the reusing allocator
209 */
210 void *h2o_mem_alloc_recycle(h2o_mem_recycle_t *allocator, size_t sz);
211 /**
212 * returns the memory to the reusing allocator
213 */
214 void h2o_mem_free_recycle(h2o_mem_recycle_t *allocator, void *p);
215 /**
216 * release all the memory chunks cached in input allocator to system
217 */
218 void h2o_mem_clear_recycle(h2o_mem_recycle_t *allocator, int full);
219
220 /**
221 * initializes the memory pool.
222 */
223 void h2o_mem_init_pool(h2o_mem_pool_t *pool);
224 /**
225 * clears the memory pool.
226 * Applications may dispose the pool after calling the function or reuse it without calling h2o_mem_init_pool.
227 */
228 void h2o_mem_clear_pool(h2o_mem_pool_t *pool);
229 /**
230 * allocates given size of memory from the memory pool, or dies if impossible
231 */
232 #define h2o_mem_alloc_pool(pool, type, cnt) h2o_mem_alloc_pool_aligned(pool, H2O_ALIGNOF(type), sizeof(type) * (cnt))
233 /**
234 * allocates given size of memory from pool using given alignment
235 */
236 static void *h2o_mem_alloc_pool_aligned(h2o_mem_pool_t *pool, size_t alignment, size_t size);
237 void *h2o_mem__do_alloc_pool_aligned(h2o_mem_pool_t *pool, size_t alignment, size_t size);
238 /**
239 * allocates a ref-counted chunk of given size from the memory pool, or dies if impossible.
240 * The ref-count of the returned chunk is 1 regardless of whether or not the chunk is linked to a pool.
241 * @param pool pool to which the allocated chunk should be linked (or NULL to allocate an orphan chunk)
242 */
243 void *h2o_mem_alloc_shared(h2o_mem_pool_t *pool, size_t sz, void (*dispose)(void *));
244 /**
245 * links a ref-counted chunk to a memory pool.
246 * The ref-count of the chunk will be decremented when the pool is cleared.
247 * It is permitted to link a chunk more than once to a single pool.
248 */
249 void h2o_mem_link_shared(h2o_mem_pool_t *pool, void *p);
250 /**
251 * increments the reference count of a ref-counted chunk.
252 */
253 static void h2o_mem_addref_shared(void *p);
254 /**
255 * decrements the reference count of a ref-counted chunk.
256 * The chunk gets freed when the ref-count reaches zero.
257 */
258 static int h2o_mem_release_shared(void *p);
259 /**
260 * frees unused memory being pooled for recycling
261 */
262 void h2o_buffer_clear_recycle(int full);
263 /**
264 * initialize the buffer using given prototype.
265 */
266 static void h2o_buffer_init(h2o_buffer_t **buffer, h2o_buffer_prototype_t *prototype);
267 /**
268 * calls the appropriate function to free the resources associated with the buffer
269 */
270 void h2o_buffer__do_free(h2o_buffer_t *buffer);
271 /**
272 * disposes of the buffer
273 */
274 static void h2o_buffer_dispose(h2o_buffer_t **buffer);
275 /**
276 * allocates a buffer with h2o_buffer_try_reserve. aborts on allocation failure.
277 * @return buffer to which the next data should be stored
278 */
279 h2o_iovec_t h2o_buffer_reserve(h2o_buffer_t **inbuf, size_t min_guarantee);
280 /**
281 * allocates a buffer.
282 * @param inbuf - pointer to a pointer pointing to the structure (set *inbuf to NULL to allocate a new buffer)
283 * @param min_guarantee minimum number of additional bytes to reserve
284 * @return buffer to which the next data should be stored
285 * @note When called against a new buffer, the function returns a buffer twice the size of requested guarantee. The function uses
286 * exponential backoff for already-allocated buffers.
287 */
288 h2o_iovec_t h2o_buffer_try_reserve(h2o_buffer_t **inbuf, size_t min_guarantee) __attribute__((warn_unused_result));
289 /**
290 * copies @len bytes from @src to @dst, calling h2o_buffer_reserve. aborts on allocation failure.
291 */
292 static void h2o_buffer_append(h2o_buffer_t **dst, const void *src, size_t len);
293 /**
294 * variant of h2o_buffer_append that does not abort on failure
295 * @return a boolean indicating if allocation has succeeded
296 */
297 static int h2o_buffer_try_append(h2o_buffer_t **dst, const void *src, size_t len) __attribute__((warn_unused_result));
298 /**
299 * throws away given size of the data from the buffer.
300 * @param delta number of octets to be drained from the buffer
301 */
302 void h2o_buffer_consume(h2o_buffer_t **inbuf, size_t delta);
303 /**
304 * throws away entire data being store in the buffer
305 * @param record_capacity if set to true, retains the current capacity of the buffer, and when memory reservation is requested the
306 * next time, allocates memory as large as the recorded capacity. Otherwise, memory would be reserved based
307 * on the value of `min_guarantee`, current size, and the prototype.
308 */
309 void h2o_buffer_consume_all(h2o_buffer_t **inbuf, int record_capacity);
310 /**
311 * resets the buffer prototype
312 */
313 static void h2o_buffer_set_prototype(h2o_buffer_t **buffer, h2o_buffer_prototype_t *prototype);
314 /**
315 * registers a buffer to memory pool, so that it would be freed when the pool is flushed. Note that the buffer cannot be resized
316 * after it is linked.
317 */
318 static void h2o_buffer_link_to_pool(h2o_buffer_t *buffer, h2o_mem_pool_t *pool);
319 void h2o_buffer__dispose_linked(void *p);
320 /**
321 *
322 */
323 static void h2o_doublebuffer_init(h2o_doublebuffer_t *db, h2o_buffer_prototype_t *prototype);
324 /**
325 *
326 */
327 static void h2o_doublebuffer_dispose(h2o_doublebuffer_t *db);
328 /**
329 * Given a double buffer and a pointer to a buffer to which the caller is writing data, returns a vector containing data to be sent
330 * (e.g., by calling `h2o_send`). `max_bytes` designates the maximum size of the vector to be returned. When the double buffer is
331 * empty, `*receiving` is moved to the double buffer, and upon return `*receiving` will contain an empty buffer to which the caller
332 * should append new data.
333 */
334 static h2o_iovec_t h2o_doublebuffer_prepare(h2o_doublebuffer_t *db, h2o_buffer_t **receiving, size_t max_bytes);
335 /**
336 * Marks that empty data is inflight. This function can be called when making preparations to call `h2o_send` but when only the HTTP
337 * response header fields are available.
338 */
339 static void h2o_doublebuffer_prepare_empty(h2o_doublebuffer_t *db);
340 /**
341 * Consumes bytes being marked as inflight (by previous call to `h2o_doublebuffer_prepare`). The intended design pattern is to call
342 * this function and then the generator's `do_send` function in the `do_proceed` callback. See lib/handler/fastcgi.c.
343 */
344 static void h2o_doublebuffer_consume(h2o_doublebuffer_t *db);
345 /**
346 * grows the vector so that it could store at least new_capacity elements of given size (or dies if impossible).
347 * @param pool memory pool that the vector is using
348 * @param vector the vector
349 * @param element_size size of the elements stored in the vector
350 * @param new_capacity the capacity of the buffer after the function returns
351 */
352 #define h2o_vector_reserve(pool, vector, new_capacity) \
353 h2o_vector__reserve((pool), (h2o_vector_t *)(void *)(vector), H2O_ALIGNOF((vector)->entries[0]), sizeof((vector)->entries[0]), \
354 (new_capacity))
355 static void h2o_vector__reserve(h2o_mem_pool_t *pool, h2o_vector_t *vector, size_t alignment, size_t element_size,
356 size_t new_capacity);
357 void h2o_vector__expand(h2o_mem_pool_t *pool, h2o_vector_t *vector, size_t alignment, size_t element_size, size_t new_capacity);
358 /**
359 * erase the entry at given index from the vector
360 */
361 #define h2o_vector_erase(vector, index) h2o_vector__erase((h2o_vector_t *)(void *)(vector), sizeof((vector)->entries[0]), (index))
362 static void h2o_vector__erase(h2o_vector_t *vector, size_t element_size, size_t index);
363
364 /**
365 * tests if target chunk (target_len bytes long) is equal to test chunk (test_len bytes long)
366 */
367 static int h2o_memis(const void *target, size_t target_len, const void *test, size_t test_len);
368
369 /**
370 * variant of memchr that searches the string from tail
371 */
372 static void *h2o_memrchr(const void *s, int c, size_t n);
373
374 /**
375 * secure memset
376 */
377 static void *h2o_mem_set_secure(void *b, int c, size_t len);
378
379 /**
380 * swaps contents of memory
381 */
382 void h2o_mem_swap(void *x, void *y, size_t len);
383
384 /**
385 * emits hexdump of given buffer to fp
386 */
387 void h2o_dump_memory(FILE *fp, const char *buf, size_t len);
388
389 /**
390 * appends an element to a NULL-terminated list allocated using malloc
391 */
392 void h2o_append_to_null_terminated_list(void ***list, void *element);
393
394 extern __thread h2o_mem_recycle_t h2o_mem_pool_allocator;
395 extern size_t h2o_mmap_errors;
396
397 /* inline defs */
398
h2o_memcpy(void * dst,const void * src,size_t n)399 inline void *h2o_memcpy(void *dst, const void *src, size_t n)
400 {
401 if (src != NULL)
402 return memcpy(dst, src, n);
403 else if (n != 0)
404 h2o_fatal("null pointer passed to memcpy");
405 return dst;
406 }
407
h2o_iovec_init(const void * base,size_t len)408 inline h2o_iovec_t h2o_iovec_init(const void *base, size_t len)
409 {
410 /* intentionally declared to take a "const void*" since it may contain any type of data and since _some_ buffers are constant */
411 h2o_iovec_t buf;
412 buf.base = (char *)base;
413 buf.len = len;
414 return buf;
415 }
416
h2o_mem_alloc(size_t sz)417 inline void *h2o_mem_alloc(size_t sz)
418 {
419 void *p = malloc(sz);
420 if (p == NULL)
421 h2o_fatal("no memory");
422 return p;
423 }
424
h2o_mem_realloc(void * oldp,size_t sz)425 inline void *h2o_mem_realloc(void *oldp, size_t sz)
426 {
427 void *newp = realloc(oldp, sz);
428 if (newp == NULL) {
429 h2o_fatal("no memory");
430 return oldp;
431 }
432 return newp;
433 }
434
h2o_mem_alloc_pool_aligned(h2o_mem_pool_t * pool,size_t alignment,size_t size)435 inline void *h2o_mem_alloc_pool_aligned(h2o_mem_pool_t *pool, size_t alignment, size_t size)
436 {
437 /* C11 6.2.8: "Every valid alignment value shall be a nonnegative integral power of two"; assert will be resolved at compile-
438 * time for performance-sensitive cases */
439 assert(alignment != 0 && (alignment & (alignment - 1)) == 0);
440 return h2o_mem__do_alloc_pool_aligned(pool, alignment, size);
441 }
442
h2o_mem_addref_shared(void * p)443 inline void h2o_mem_addref_shared(void *p)
444 {
445 struct st_h2o_mem_pool_shared_entry_t *entry = H2O_STRUCT_FROM_MEMBER(struct st_h2o_mem_pool_shared_entry_t, bytes, p);
446 assert(entry->refcnt != 0);
447 ++entry->refcnt;
448 }
449
h2o_mem_release_shared(void * p)450 inline int h2o_mem_release_shared(void *p)
451 {
452 struct st_h2o_mem_pool_shared_entry_t *entry = H2O_STRUCT_FROM_MEMBER(struct st_h2o_mem_pool_shared_entry_t, bytes, p);
453 assert(entry->refcnt != 0);
454 if (--entry->refcnt == 0) {
455 if (entry->dispose != NULL)
456 entry->dispose(entry->bytes);
457 free(entry);
458 return 1;
459 }
460 return 0;
461 }
462
h2o_buffer_init(h2o_buffer_t ** buffer,h2o_buffer_prototype_t * prototype)463 inline void h2o_buffer_init(h2o_buffer_t **buffer, h2o_buffer_prototype_t *prototype)
464 {
465 *buffer = &prototype->_initial_buf;
466 }
467
h2o_buffer_dispose(h2o_buffer_t ** _buffer)468 inline void h2o_buffer_dispose(h2o_buffer_t **_buffer)
469 {
470 h2o_buffer_t *buffer = *_buffer;
471 *_buffer = NULL;
472 if (buffer->_prototype != NULL)
473 h2o_buffer__do_free(buffer);
474 }
475
h2o_buffer_set_prototype(h2o_buffer_t ** buffer,h2o_buffer_prototype_t * prototype)476 inline void h2o_buffer_set_prototype(h2o_buffer_t **buffer, h2o_buffer_prototype_t *prototype)
477 {
478 if ((*buffer)->_prototype != NULL)
479 (*buffer)->_prototype = prototype;
480 else
481 *buffer = &prototype->_initial_buf;
482 }
483
h2o_buffer_link_to_pool(h2o_buffer_t * buffer,h2o_mem_pool_t * pool)484 inline void h2o_buffer_link_to_pool(h2o_buffer_t *buffer, h2o_mem_pool_t *pool)
485 {
486 h2o_buffer_t **slot = (h2o_buffer_t **)h2o_mem_alloc_shared(pool, sizeof(*slot), h2o_buffer__dispose_linked);
487 *slot = buffer;
488 }
489
h2o_buffer_append(h2o_buffer_t ** dst,const void * src,size_t len)490 inline void h2o_buffer_append(h2o_buffer_t **dst, const void *src, size_t len)
491 {
492 h2o_iovec_t buf = h2o_buffer_reserve(dst, len);
493 h2o_memcpy(buf.base, src, len);
494 (*dst)->size += len;
495 }
496
h2o_buffer_try_append(h2o_buffer_t ** dst,const void * src,size_t len)497 inline int h2o_buffer_try_append(h2o_buffer_t **dst, const void *src, size_t len)
498 {
499 h2o_iovec_t buf = h2o_buffer_try_reserve(dst, len);
500 if (buf.base == NULL)
501 return 0;
502 h2o_memcpy(buf.base, src, len);
503 (*dst)->size += len;
504 return 1;
505 }
506
h2o_doublebuffer_init(h2o_doublebuffer_t * db,h2o_buffer_prototype_t * prototype)507 inline void h2o_doublebuffer_init(h2o_doublebuffer_t *db, h2o_buffer_prototype_t *prototype)
508 {
509 h2o_buffer_init(&db->buf, prototype);
510 db->inflight = 0;
511 db->_bytes_inflight = 0;
512 }
513
h2o_doublebuffer_dispose(h2o_doublebuffer_t * db)514 inline void h2o_doublebuffer_dispose(h2o_doublebuffer_t *db)
515 {
516 h2o_buffer_dispose(&db->buf);
517 }
518
h2o_doublebuffer_prepare(h2o_doublebuffer_t * db,h2o_buffer_t ** receiving,size_t max_bytes)519 inline h2o_iovec_t h2o_doublebuffer_prepare(h2o_doublebuffer_t *db, h2o_buffer_t **receiving, size_t max_bytes)
520 {
521 assert(!db->inflight);
522 assert(max_bytes != 0);
523
524 if (db->buf->size == 0) {
525 if ((*receiving)->size == 0)
526 return h2o_iovec_init(NULL, 0);
527 /* swap buffers */
528 h2o_buffer_t *t = db->buf;
529 db->buf = *receiving;
530 *receiving = t;
531 }
532 if ((db->_bytes_inflight = db->buf->size) > max_bytes)
533 db->_bytes_inflight = max_bytes;
534 db->inflight = 1;
535 return h2o_iovec_init(db->buf->bytes, db->_bytes_inflight);
536 }
537
h2o_doublebuffer_prepare_empty(h2o_doublebuffer_t * db)538 inline void h2o_doublebuffer_prepare_empty(h2o_doublebuffer_t *db)
539 {
540 assert(!db->inflight);
541 db->inflight = 1;
542 }
543
h2o_doublebuffer_consume(h2o_doublebuffer_t * db)544 inline void h2o_doublebuffer_consume(h2o_doublebuffer_t *db)
545 {
546 assert(db->inflight);
547 db->inflight = 0;
548
549 if (db->buf->size == db->_bytes_inflight) {
550 h2o_buffer_consume_all(&db->buf, 1);
551 } else {
552 h2o_buffer_consume(&db->buf, db->_bytes_inflight);
553 }
554 db->_bytes_inflight = 0;
555 }
556
h2o_vector__reserve(h2o_mem_pool_t * pool,h2o_vector_t * vector,size_t alignment,size_t element_size,size_t new_capacity)557 inline void h2o_vector__reserve(h2o_mem_pool_t *pool, h2o_vector_t *vector, size_t alignment, size_t element_size,
558 size_t new_capacity)
559 {
560 if (vector->capacity < new_capacity) {
561 h2o_vector__expand(pool, vector, alignment, element_size, new_capacity);
562 }
563 }
564
h2o_vector__erase(h2o_vector_t * vector,size_t element_size,size_t index)565 inline void h2o_vector__erase(h2o_vector_t *vector, size_t element_size, size_t index)
566 {
567 char *entries = (char *)vector->entries;
568 memmove(entries + element_size * index, entries + element_size * (index + 1), element_size * (vector->size - index - 1));
569 --vector->size;
570 }
571
h2o_memis(const void * _target,size_t target_len,const void * _test,size_t test_len)572 inline int h2o_memis(const void *_target, size_t target_len, const void *_test, size_t test_len)
573 {
574 const char *target = (const char *)_target, *test = (const char *)_test;
575 if (target_len != test_len)
576 return 0;
577 if (target_len == 0)
578 return 1;
579 if (target[0] != test[0])
580 return 0;
581 return memcmp(target + 1, test + 1, test_len - 1) == 0;
582 }
583
h2o_memrchr(const void * s,int c,size_t n)584 inline void *h2o_memrchr(const void *s, int c, size_t n)
585 {
586 if (n != 0) {
587 const char *p = (const char *)s + n;
588 do {
589 if (*--p == c)
590 return (void *)p;
591 } while (p != s);
592 }
593 return NULL;
594 }
595
h2o_mem_set_secure(void * b,int c,size_t len)596 inline void *h2o_mem_set_secure(void *b, int c, size_t len)
597 {
598 return h2o_mem__set_secure(b, c, len);
599 }
600
601 #ifdef __cplusplus
602 }
603 #endif
604
605 #endif
606