Line data Source code
1 : /*
2 : * lwan - web server
3 : * Copyright (c) 2017 L. A. F. Pereira <l@tia.mat.br>
4 : *
5 : * This program is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU General Public License
7 : * as published by the Free Software Foundation; either version 2
8 : * of the License, or any later version.
9 : *
10 : * This program is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : * GNU General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU General Public License
16 : * along with this program; if not, write to the Free Software
17 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18 : * USA.
19 : */
20 :
21 : #define _DEFAULT_SOURCE
22 : #define _GNU_SOURCE
23 : #include <errno.h>
24 : #include <stdint.h>
25 : #include <stdlib.h>
26 :
27 : #include "lwan.h"
28 : #include "lwan-array.h"
29 :
30 992 : int lwan_array_reset(struct lwan_array *a, void *inline_storage)
31 : {
32 992 : if (UNLIKELY(!a))
33 0 : return -EINVAL;
34 :
35 992 : if (a->base != inline_storage)
36 753 : free(a->base);
37 :
38 992 : a->base = NULL;
39 992 : a->elements = 0;
40 :
41 992 : return 0;
42 : }
43 :
44 : #if !defined(LWAN_HAVE_BUILTIN_ADD_OVERFLOW)
45 : static inline bool add_overflow(size_t a, size_t b, size_t *out)
46 : {
47 : if (UNLIKELY(a > 0 && b > SIZE_MAX - a))
48 : return true;
49 :
50 : *out = a + b;
51 : return false;
52 : }
53 : #else
54 : #define add_overflow __builtin_add_overflow
55 : #endif
56 :
57 8380 : void *lwan_array_append_heap(struct lwan_array *a, size_t element_size)
58 : {
59 8380 : if (!(a->elements % LWAN_ARRAY_INCREMENT)) {
60 : void *new_base;
61 : size_t new_cap;
62 :
63 1302 : if (UNLIKELY(
64 : add_overflow(a->elements, LWAN_ARRAY_INCREMENT, &new_cap))) {
65 0 : errno = EOVERFLOW;
66 0 : return NULL;
67 : }
68 :
69 1302 : new_base = reallocarray(a->base, new_cap, element_size);
70 1302 : if (UNLIKELY(!new_base))
71 0 : return NULL;
72 :
73 1302 : a->base = new_base;
74 : }
75 :
76 8380 : return ((char *)a->base) + a->elements++ * element_size;
77 : }
78 :
79 854 : void *lwan_array_append_inline(struct lwan_array *a,
80 : size_t element_size,
81 : void *inline_storage)
82 : {
83 854 : if (!a->base)
84 334 : a->base = inline_storage;
85 520 : else if (UNLIKELY(a->base != inline_storage))
86 0 : return lwan_array_append_heap(a, element_size);
87 :
88 854 : assert(a->elements <= LWAN_ARRAY_INCREMENT);
89 :
90 854 : if (a->elements == LWAN_ARRAY_INCREMENT) {
91 : void *new_base =
92 0 : reallocarray(NULL, 2 * LWAN_ARRAY_INCREMENT, element_size);
93 :
94 0 : if (UNLIKELY(!new_base))
95 0 : return NULL;
96 :
97 0 : a->base = memcpy(new_base, inline_storage,
98 : LWAN_ARRAY_INCREMENT * element_size);
99 : }
100 :
101 854 : return ((char *)a->base) + a->elements++ * element_size;
102 : }
103 :
104 324 : void lwan_array_sort(struct lwan_array *a,
105 : size_t element_size,
106 : int (*cmp)(const void *a, const void *b))
107 : {
108 324 : if (LIKELY(a->elements))
109 324 : qsort(a->base, a->elements, element_size, cmp);
110 324 : }
111 :
112 2 : static void coro_lwan_array_free_heap(void *data)
113 : {
114 2 : struct lwan_array *array = data;
115 :
116 2 : lwan_array_reset(array, NULL);
117 2 : free(array);
118 2 : }
119 :
120 0 : static void coro_lwan_array_free_inline(void *data)
121 : {
122 0 : struct lwan_array *array = data;
123 :
124 0 : lwan_array_reset(array, array + 1);
125 0 : free(array);
126 0 : }
127 :
128 2 : struct lwan_array *coro_lwan_array_new(struct coro *coro,
129 : size_t struct_size,
130 : bool inline_first)
131 : {
132 : struct lwan_array *array;
133 :
134 2 : assert(struct_size >= sizeof(struct lwan_array));
135 :
136 2 : array = coro_malloc_full(coro, struct_size,
137 : inline_first ? coro_lwan_array_free_inline
138 : : coro_lwan_array_free_heap);
139 2 : if (LIKELY(array))
140 2 : *array = (struct lwan_array){.base = NULL, .elements = 0};
141 :
142 2 : return array;
143 : }
|