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