SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
array.c
Go to the documentation of this file.
1/**
2 * @file array.c
3 * @brief Implementation of dynamic 2D arrays and memory management functions.
4 *
5 * This file contains functions for allocating, resizing, and freeing 2D arrays,
6 * as well as custom memory allocation functions with tracking capabilities.
7 *
8 * @copyright
9 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
10 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
11 *
12 * @license
13 * This file is distributed under the terms of the Software License Agreement
14 * found in the file LICENSE included with this distribution.
15 *
16 * @author M. Borland, C. Saunders, R. Soliday, H. Shang
17 */
18
19#include "mdb.h"
20#include "mdb_thread.h"
21
22static FILE *fp_tmalloc = NULL;
23static FILE *fp_trealloc = NULL;
24static FILE *fp_tfree = NULL;
25static uint64_t tmalloc_total_bytes = 0;
26static uint64_t trealloc_total_bytes = 0;
27static MDB_THREAD_LOCK alloc_record_lock = MDB_THREAD_LOCK_INITIALIZER;
28
29/**
30 * @brief Keeps a record of memory allocations by opening tracking files.
31 *
32 * Opens tracking files for memory allocation, reallocation, and freeing based on the provided filename.
33 * If tracking files are already open, they are closed before reopening.
34 *
35 * @param filename The base name for the tracking files.
36 */
37void keep_alloc_record(char *filename) {
38 char s[100];
39
40 mdb_thread_lock(&alloc_record_lock);
41 if (fp_tmalloc)
42 fclose(fp_tmalloc);
43 if (fp_trealloc)
44 fclose(fp_trealloc);
45 if (fp_tfree)
46 fclose(fp_tfree);
47 sprintf(s, "%s.tmalloc", filename);
48 fp_tmalloc = fopen_e(s, "w", 0);
49 sprintf(s, "%s.trealloc", filename);
50 fp_trealloc = fopen_e(s, "w", 0);
51 sprintf(s, "%s.tfree", filename);
52 fp_tfree = fopen_e(s, "w", 0);
53 mdb_thread_unlock(&alloc_record_lock);
54}
55
56/**
57 * @brief Allocates a memory block of the specified size with zero initialization.
58 *
59 * Uses `calloc` to allocate memory and initializes it to zero. Tracks the allocation if tracking is enabled.
60 * If the allocation fails, the function prints an error message and aborts the program.
61 *
62 * @param size_of_block The size of the memory block to allocate in bytes.
63 * @return Pointer to the allocated memory block.
64 */
65void *tmalloc(uint64_t size_of_block) {
66 void *ptr;
67
68 if (size_of_block <= 0)
69 size_of_block = 4;
70
71 /* even though the function is tMalloc, I use calloc to get memory filled
72 * with zeros
73 */
74 if (!(ptr = calloc(size_of_block, 1))) {
75 printf("error: memory allocation failure--%"PRIu64" Bytes requested.\n",
76 size_of_block);
77 mdb_thread_lock(&alloc_record_lock);
78 printf("tmalloc() has allocated %"PRIu64" bytes previously\n", tmalloc_total_bytes);
79 mdb_thread_unlock(&alloc_record_lock);
80 abort();
81 }
82 mdb_thread_lock(&alloc_record_lock);
83 if (fp_tmalloc) {
84 fprintf(fp_tmalloc, "%"PRIx64" %"PRIu64"\n", (uint64_t)ptr, size_of_block);
85 fflush(fp_tmalloc);
86 }
87 tmalloc_total_bytes += size_of_block;
88 mdb_thread_unlock(&alloc_record_lock);
89 return (ptr);
90}
91
92/**
93 * @brief Allocates a 2D array with specified dimensions.
94 *
95 * Allocates memory for a 2D array where each row is a contiguous block of memory. Initializes each row to zero.
96 *
97 * @param size The size of each element in the array.
98 * @param n1 The number of rows.
99 * @param n2 The number of columns.
100 * @return Pointer to the allocated 2D array.
101 */
102void **zarray_2d(uint64_t size, uint64_t n1, uint64_t n2) {
103 void **ptr1, **ptr0;
104
105 ptr0 = ptr1 = (void **)tmalloc((uint64_t)(sizeof(*ptr0) * n1));
106 while (n1--)
107 *ptr1++ = (void *)tmalloc((uint64_t)(size * n2));
108 return (ptr0);
109}
110
111/**
112 * @brief Resizes an existing 2D array to new dimensions.
113 *
114 * Resizes the array of pointers if the number of rows (`n1`) increases.
115 * Additionally, resizes each row to accommodate more columns (`n2`) if needed.
116 * If resizing fails, the function aborts the program.
117 *
118 * @param size The size of each element in the array.
119 * @param old_n1 The original number of rows.
120 * @param old_n2 The original number of columns.
121 * @param array Pointer to the original 2D array.
122 * @param n1 The new number of rows.
123 * @param n2 The new number of columns.
124 * @return Pointer to the resized 2D array.
125 */
126void **resize_zarray_2d(uint64_t size, uint64_t old_n1, uint64_t old_n2,
127 void **array, uint64_t n1, uint64_t n2) {
128 void **ptr;
129
130 if (n1 > old_n1) {
131 /* increase length of array of pointers */
132 if (!(array = (void **)trealloc((void *)array,
133 (uint64_t)(sizeof(*array) * n1))))
134 bomb("memory allocation failuire in resize_zarray_2d()", NULL);
135 /* allocate memory for new pointed-to objects */
136 ptr = array + n1;
137 while (n1-- != old_n1)
138 *--ptr = (void *)tmalloc(size * n2);
139 }
140
141 if (n2 > old_n2) {
142 /* increase size of old pointed-to objects */
143 ptr = array;
144 while (old_n1--) {
145 if (!(*ptr = (void *)trealloc((void *)*ptr, (uint64_t)(size * n2))))
146 bomb("memory allocation failure in resize_zarray_2d()", NULL);
147 ptr++;
148 }
149 }
150
151 return (array);
152}
153
154/**
155 * @brief Frees a 2D array and its associated memory.
156 *
157 * Frees each row of the 2D array and then frees the array of pointers itself.
158 *
159 * @param array Pointer to the 2D array to free.
160 * @param n1 The number of rows in the array.
161 * @param n2 The number of columns in the array.
162 * @return Status of the free operation (1 if successful, 0 otherwise).
163 */
164int free_zarray_2d(void **array, uint64_t n1, uint64_t n2) {
165 void *ptr0;
166
167 if (!(ptr0 = array))
168 return (0);
169 while (n1--) {
170 if (*array) {
171 tfree(*array);
172 *array = NULL;
173 } else
174 return (0);
175 array++;
176 }
177 return (tfree(ptr0));
178}
179
180/**
181 * @brief Reallocates a memory block to a new size.
182 *
183 * Uses `realloc` to resize the memory block. Tracks the reallocation if tracking is enabled.
184 * If the reallocation fails, the function prints an error message and aborts the program.
185 *
186 * @param old_ptr Pointer to the original memory block.
187 * @param size_of_block The new size for the memory block in bytes.
188 * @return Pointer to the reallocated memory block.
189 */
190void *trealloc(void *old_ptr, uint64_t size_of_block) {
191 void *ptr;
192
193 if (size_of_block <= 0)
194 size_of_block = 4;
195
196 if (!old_ptr)
197 return (tmalloc(size_of_block));
198 uint64_t oldaddr = (uint64_t)old_ptr;
199 if (!(ptr = realloc(old_ptr, (uint64_t)(size_of_block)))) {
200 printf("error: memory reallocation failure--%"PRIu64" bytes requested.\n",
201 size_of_block);
202 mdb_thread_lock(&alloc_record_lock);
203 printf("trealloc() has reallocated %"PRIu64" bytes previously\n", trealloc_total_bytes);
204 mdb_thread_unlock(&alloc_record_lock);
205 abort();
206 }
207 mdb_thread_lock(&alloc_record_lock);
208 if (fp_trealloc) {
209 fprintf(fp_trealloc, "d:%"PRIx64"\na:%"PRIx64" %"PRIu64"\n", oldaddr,
210 (uint64_t)ptr, size_of_block);
211 fflush(fp_trealloc);
212 }
213 trealloc_total_bytes += size_of_block;
214 mdb_thread_unlock(&alloc_record_lock);
215 return (ptr);
216}
217
218/**
219 * @brief Sets a block of memory to zero.
220 *
221 * Iterates through the specified memory block and sets each byte to zero.
222 *
223 * @param mem Pointer to the memory block.
224 * @param n_bytes The number of bytes to set to zero.
225 */
226void zero_memory(void *mem, uint64_t n_bytes) {
227 char *cmem;
228
229 if (!(cmem = mem))
230 return;
231 while (n_bytes--)
232 *cmem++ = 0;
233}
234
235/**
236 * @brief Frees a memory block and records the deallocation if tracking is enabled.
237 *
238 * Frees the specified memory block and logs the deallocation if tracking is active.
239 *
240 * @param ptr Pointer to the memory block to free.
241 * @return Status of the free operation (1 if successful, 0 otherwise).
242 */
243int tfree(void *ptr) {
244 mdb_thread_lock(&alloc_record_lock);
245 if (fp_tfree) {
246 fprintf(fp_tfree, "%"PRIx64"\n", (uint64_t)ptr);
247 fflush(fp_tfree);
248 }
249 mdb_thread_unlock(&alloc_record_lock);
250 if (ptr) {
251 free(ptr);
252 return (1);
253 }
254 return (0);
255}
256
257/**
258 * @brief Allocates a 1D array with specified lower and upper indices.
259 *
260 * Allocates memory for a 1D array and adjusts the pointer based on the lower index to allow
261 * negative indexing if necessary.
262 *
263 * @param size The size of each element in the array.
264 * @param lower_index The lower index of the array.
265 * @param upper_index The upper index of the array.
266 * @return Pointer to the allocated 1D array.
267 */
268void *array_1d(uint64_t size, uint64_t lower_index, uint64_t upper_index) {
269 char *ptr;
270
271 if (!(ptr = tmalloc((uint64_t)size * (upper_index - lower_index + 1))))
272 bomb("unable to allocate array (array_1d)", NULL);
273 ptr -= lower_index * size;
274 return ((void *)ptr);
275}
276
277/**
278 * @brief Allocates a 2D array with specified lower and upper indices for both dimensions.
279 *
280 * Allocates memory for a 2D array of pointers, where each row is a 1D array.
281 * Adjusts pointers based on lower indices to allow for flexible indexing ranges.
282 *
283 * @param size The size of each element in the array.
284 * @param lower1 The lower index for the first dimension (rows).
285 * @param upper1 The upper index for the first dimension (rows).
286 * @param lower2 The lower index for the second dimension (columns).
287 * @param upper2 The upper index for the second dimension (columns).
288 * @return Pointer to the allocated 2D array.
289 */
290void **array_2d(uint64_t size, uint64_t lower1, uint64_t upper1,
291 uint64_t lower2, uint64_t upper2)
292 /* array is [upper1-lower1+1]x[upper2-lower2+1] */
293{
294 register uint64_t i, n1, n2;
295 char **ptr;
296
297 if (!(ptr = tmalloc((uint64_t)sizeof(*ptr) *(n1 = upper1 - lower1 + 1))))
298 bomb("unable to allocate array (array_2d)", NULL);
299
300 n2 = upper2 - lower2 + 1;
301 for (i = 0; i < n1; i++) {
302 if (!(ptr[i] = tmalloc((uint64_t)size * n2)))
303 bomb("unable to allocate array (array_2d)", NULL);
304 ptr[i] -= lower2 * size;
305 }
306
307 return ((void **)(ptr - lower1));
308}
309
310/**
311 * @brief Frees a 1D array that was previously allocated.
312 *
313 * Adjusts the pointer based on the lower index and frees the allocated memory.
314 *
315 * @param array Pointer to the 1D array to free.
316 * @param size The size of each element in the array.
317 * @param lower_index The lower index of the array.
318 * @param upper_index The upper index of the array.
319 * @return Status of the free operation (1 if successful, 0 otherwise).
320 */
321int free_array_1d(void *array, uint64_t size, uint64_t lower_index,
322 uint64_t upper_index) {
323 if (!array)
324 return (0);
325 free((char *)array + size * lower_index);
326 return (1);
327}
328
329/**
330 * @brief Frees a 2D array and its associated memory.
331 *
332 * Adjusts the pointer based on the lower indices and frees each row followed by the array of pointers.
333 *
334 * @param array Pointer to the 2D array to free.
335 * @param size The size of each element in the array.
336 * @param lower1 The lower index for the first dimension (rows).
337 * @param upper1 The upper index for the first dimension (rows).
338 * @param lower2 The lower index for the second dimension (columns).
339 * @param upper2 The upper index for the second dimension (columns).
340 * @return Status of the free operation (1 if successful, 0 otherwise).
341 */
342int free_array_2d(void **array, uint64_t size, uint64_t lower1, uint64_t upper1,
343 uint64_t lower2, uint64_t upper2)
344 /* array is [upper1-lower1]x[upper2-lower2] */
345{
346 uint64_t i, n1;
347 char *ptr;
348
349 if (!array)
350 return (0);
351
352 n1 = upper1 - lower1 + 1;
353 array += lower1;
354 for (i = 0; i < n1; i++) {
355 if ((ptr = (char *)array[i] + size * lower2))
356 free(ptr);
357 }
358
359 free(array);
360 return (1);
361}
362
363/**
364 * @brief Allocates a contiguous 2D array with zero-based indexing.
365 *
366 * Allocates a single contiguous block of memory for a 2D array and sets up row pointers accordingly.
367 *
368 * @param size The size of each element in the array.
369 * @param n1 The number of rows.
370 * @param n2 The number of columns.
371 * @return Pointer to the allocated contiguous 2D array.
372 */
373void **czarray_2d(const uint64_t size, const uint64_t n1, const uint64_t n2) {
374 char **ptr0;
375 char *buffer;
376 uint64_t i;
377
378 ptr0 = (char **)tmalloc((uint64_t)(sizeof(*ptr0) * n1));
379 buffer = (char *)tmalloc((uint64_t)(sizeof(*buffer) * size * n1 * n2));
380 for (i = 0; i < n1; i++)
381 ptr0[i] = buffer + i * size * n2;
382 return ((void **)ptr0);
383}
384
385/**
386 * @brief Resizes a contiguous 2D array to new dimensions.
387 *
388 * Resizes both the array of row pointers and the contiguous memory block holding the array elements.
389 *
390 * @param data Pointer to the original contiguous 2D array.
391 * @param size The size of each element in the array.
392 * @param n1 The new number of rows.
393 * @param n2 The new number of columns.
394 * @return Pointer to the resized contiguous 2D array.
395 */
396void **resize_czarray_2d(void **data, uint64_t size, uint64_t n1, uint64_t n2) {
397 char **ptr0;
398 char *buffer;
399 uint64_t i;
400
401 if (!data)
402 return czarray_2d(size, n1, n2);
403 buffer = (char *)trealloc(*data, (uint64_t)(sizeof(char) * size * n1 * n2));
404 ptr0 = (char **)trealloc(data, (uint64_t)(sizeof(char *) * n1));
405 for (i = 0; i < n1; i++)
406 ptr0[i] = buffer + i * size * n2;
407 return ((void **)ptr0);
408}
409
410/**
411 * @brief Frees a contiguous 2D array and its associated memory.
412 *
413 * Frees the contiguous memory block holding the array elements and the array of row pointers.
414 *
415 * @param array Pointer to the contiguous 2D array to free.
416 * @param n1 The number of rows in the array.
417 * @param n2 The number of columns in the array.
418 * @return Status of the free operation (always returns 0).
419 */
420int free_czarray_2d(void **array, uint64_t n1, uint64_t n2) {
421 free(*array);
422 free(array);
423 return 0;
424}
void ** zarray_2d(uint64_t size, uint64_t n1, uint64_t n2)
Allocates a 2D array with specified dimensions.
Definition array.c:102
void ** resize_zarray_2d(uint64_t size, uint64_t old_n1, uint64_t old_n2, void **array, uint64_t n1, uint64_t n2)
Resizes an existing 2D array to new dimensions.
Definition array.c:126
void ** array_2d(uint64_t size, uint64_t lower1, uint64_t upper1, uint64_t lower2, uint64_t upper2)
Allocates a 2D array with specified lower and upper indices for both dimensions.
Definition array.c:290
void * array_1d(uint64_t size, uint64_t lower_index, uint64_t upper_index)
Allocates a 1D array with specified lower and upper indices.
Definition array.c:268
void * trealloc(void *old_ptr, uint64_t size_of_block)
Reallocates a memory block to a new size.
Definition array.c:190
int free_array_1d(void *array, uint64_t size, uint64_t lower_index, uint64_t upper_index)
Frees a 1D array that was previously allocated.
Definition array.c:321
void zero_memory(void *mem, uint64_t n_bytes)
Sets a block of memory to zero.
Definition array.c:226
int free_zarray_2d(void **array, uint64_t n1, uint64_t n2)
Frees a 2D array and its associated memory.
Definition array.c:164
void ** resize_czarray_2d(void **data, uint64_t size, uint64_t n1, uint64_t n2)
Resizes a contiguous 2D array to new dimensions.
Definition array.c:396
int tfree(void *ptr)
Frees a memory block and records the deallocation if tracking is enabled.
Definition array.c:243
int free_array_2d(void **array, uint64_t size, uint64_t lower1, uint64_t upper1, uint64_t lower2, uint64_t upper2)
Frees a 2D array and its associated memory.
Definition array.c:342
void ** czarray_2d(const uint64_t size, const uint64_t n1, const uint64_t n2)
Allocates a contiguous 2D array with zero-based indexing.
Definition array.c:373
void keep_alloc_record(char *filename)
Keeps a record of memory allocations by opening tracking files.
Definition array.c:37
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:65
int free_czarray_2d(void **array, uint64_t n1, uint64_t n2)
Frees a contiguous 2D array and its associated memory.
Definition array.c:420
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
Definition bomb.c:26
FILE * fopen_e(char *file, char *open_mode, long mode)
Opens a file with error checking, messages, and aborts.
Definition fopen_e.c:30