1 /* wmem_array.c
2  * Wireshark Memory Manager Array
3  * Copyright 2013, Evan Huus <eapache@gmail.com>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11 
12 #include "config.h"
13 
14 #include <string.h>
15 #include <stdlib.h>
16 #include <glib.h>
17 
18 #include "wmem_core.h"
19 #include "wmem_array.h"
20 
21 /* Holds a wmem-allocated array.
22  *  elem_len is the size of each element
23  *  elem_count is the number of used elements
24  *  alloc_count is the length (in elems) of the raw buffer pointed to by buf,
25  *      regardless of how many elems are used (the contents)
26  */
27 struct _wmem_array_t {
28     wmem_allocator_t *allocator;
29 
30     guint8 *buf;
31 
32     gsize elem_size;
33 
34     guint elem_count;
35     guint alloc_count;
36 
37     gboolean null_terminated;
38 };
39 
40 wmem_array_t *
wmem_array_sized_new(wmem_allocator_t * allocator,gsize elem_size,guint alloc_count)41 wmem_array_sized_new(wmem_allocator_t *allocator, gsize elem_size,
42                      guint alloc_count)
43 {
44     wmem_array_t *array;
45 
46     array = wmem_new(allocator, wmem_array_t);
47 
48     array->allocator   = allocator;
49     array->elem_size   = elem_size;
50     array->elem_count  = 0;
51     array->alloc_count = alloc_count ? alloc_count : 1;
52     array->null_terminated = FALSE;
53 
54     array->buf = (guint8 *)wmem_alloc(array->allocator,
55             array->elem_size * array->alloc_count);
56 
57     return array;
58 }
59 
60 wmem_array_t *
wmem_array_new(wmem_allocator_t * allocator,const gsize elem_size)61 wmem_array_new(wmem_allocator_t *allocator, const gsize elem_size)
62 {
63     wmem_array_t *array;
64 
65     array = wmem_array_sized_new(allocator, elem_size, 1);
66 
67     return array;
68 }
69 
70 void
wmem_array_grow(wmem_array_t * array,const guint to_add)71 wmem_array_grow(wmem_array_t *array, const guint to_add)
72 {
73     guint new_alloc_count, new_count;
74 
75     new_alloc_count = array->alloc_count;
76     new_count = array->elem_count + to_add;
77 
78     while (new_alloc_count < new_count) {
79         new_alloc_count *= 2;
80     }
81 
82     if (new_alloc_count == array->alloc_count) {
83         return;
84     }
85 
86     array->buf = (guint8 *)wmem_realloc(array->allocator, array->buf,
87             new_alloc_count * array->elem_size);
88 
89     array->alloc_count = new_alloc_count;
90 }
91 
92 static void
wmem_array_write_null_terminator(wmem_array_t * array)93 wmem_array_write_null_terminator(wmem_array_t *array)
94 {
95     if (array->null_terminated) {
96         wmem_array_grow(array, 1);
97         memset(&array->buf[array->elem_count * array->elem_size], 0x0, array->elem_size);
98     }
99 }
100 
101 void
wmem_array_set_null_terminator(wmem_array_t * array)102 wmem_array_set_null_terminator(wmem_array_t *array)
103 {
104     array->null_terminated = TRUE;
105     wmem_array_write_null_terminator(array);
106 }
107 
108 void
wmem_array_bzero(wmem_array_t * array)109 wmem_array_bzero(wmem_array_t *array)
110 {
111     memset(array->buf, 0x0, array->elem_size * array->elem_count);
112 }
113 
114 void
wmem_array_append(wmem_array_t * array,const void * in,guint count)115 wmem_array_append(wmem_array_t *array, const void *in, guint count)
116 {
117     wmem_array_grow(array, count);
118 
119     memcpy(&array->buf[array->elem_count * array->elem_size], in,
120             count * array->elem_size);
121 
122     array->elem_count += count;
123 
124     wmem_array_write_null_terminator(array);
125 }
126 
127 void *
wmem_array_index(wmem_array_t * array,guint array_index)128 wmem_array_index(wmem_array_t *array, guint array_index)
129 {
130     g_assert(array_index < array->elem_count);
131     return &array->buf[array_index * array->elem_size];
132 }
133 
134 int
wmem_array_try_index(wmem_array_t * array,guint array_index,void * val)135 wmem_array_try_index(wmem_array_t *array, guint array_index, void *val)
136 {
137     if (array_index >= array->elem_count)
138         return -1;
139     memcpy(val, &array->buf[array_index * array->elem_size], array->elem_size);
140     return 0;
141 }
142 
143 void
wmem_array_sort(wmem_array_t * array,int (* compar)(const void *,const void *))144 wmem_array_sort(wmem_array_t *array, int (*compar)(const void*,const void*))
145 {
146     qsort(array->buf, array->elem_count, array->elem_size, compar);
147 }
148 
149 void *
wmem_array_get_raw(wmem_array_t * array)150 wmem_array_get_raw(wmem_array_t *array)
151 {
152     return array->buf;
153 }
154 
155 guint
wmem_array_get_count(wmem_array_t * array)156 wmem_array_get_count(wmem_array_t *array)
157 {
158     return array->elem_count;
159 }
160 
161 void
wmem_destroy_array(wmem_array_t * array)162 wmem_destroy_array(wmem_array_t *array)
163 {
164     wmem_free(array->allocator, array->buf);
165     wmem_free(array->allocator, array);
166 }
167 
168 /*
169  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
170  *
171  * Local variables:
172  * c-basic-offset: 4
173  * tab-width: 8
174  * indent-tabs-mode: nil
175  * End:
176  *
177  * vi: set shiftwidth=4 tabstop=8 expandtab:
178  * :indentSize=4:tabSize=8:noTabs=true:
179  */
180