summaryrefslogtreecommitdiffstats
path: root/src/util/ralloc.h
blob: f088a36274da3468e754f06c4d90c8ad40bfac50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
/*
 * Copyright © 2010 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * \file ralloc.h
 *
 * ralloc: a recursive memory allocator
 *
 * The ralloc memory allocator creates a hierarchy of allocated
 * objects. Every allocation is in reference to some parent, and
 * every allocated object can in turn be used as the parent of a
 * subsequent allocation. This allows for extremely convenient
 * discarding of an entire tree/sub-tree of allocations by calling
 * ralloc_free on any particular object to free it and all of its
 * children.
 *
 * The conceptual working of ralloc was directly inspired by Andrew
 * Tridgell's talloc, but ralloc is an independent implementation
 * released under the MIT license and tuned for Mesa.
 *
 * talloc is more sophisticated than ralloc in that it includes reference
 * counting and useful debugging features.  However, it is released under
 * a non-permissive open source license.
 */

#ifndef RALLOC_H
#define RALLOC_H

#ifdef __cplusplus
extern "C" {
#endif

#include <stddef.h>
#include <stdarg.h>
#include <stdbool.h>

#include "macros.h"

/**
 * \def ralloc(ctx, type)
 * Allocate a new object chained off of the given context.
 *
 * This is equivalent to:
 * \code
 * ((type *) ralloc_size(ctx, sizeof(type))
 * \endcode
 */
#define ralloc(ctx, type)  ((type *) ralloc_size(ctx, sizeof(type)))

/**
 * \def rzalloc(ctx, type)
 * Allocate a new object out of the given context and initialize it to zero.
 *
 * This is equivalent to:
 * \code
 * ((type *) rzalloc_size(ctx, sizeof(type))
 * \endcode
 */
#define rzalloc(ctx, type) ((type *) rzalloc_size(ctx, sizeof(type)))

/**
 * Allocate a new ralloc context.
 *
 * While any ralloc'd pointer can be used as a context, sometimes it is useful
 * to simply allocate a context with no associated memory.
 *
 * It is equivalent to:
 * \code
 * ((type *) ralloc_size(ctx, 0)
 * \endcode
 */
void *ralloc_context(const void *ctx);

/**
 * Allocate memory chained off of the given context.
 *
 * This is the core allocation routine which is used by all others.  It
 * simply allocates storage for \p size bytes and returns the pointer,
 * similar to \c malloc.
 */
void *ralloc_size(const void *ctx, size_t size) MALLOCLIKE;

/**
 * Allocate zero-initialized memory chained off of the given context.
 *
 * This is similar to \c calloc with a size of 1.
 */
void *rzalloc_size(const void *ctx, size_t size) MALLOCLIKE;

/**
 * Resize a piece of ralloc-managed memory, preserving data.
 *
 * Similar to \c realloc.  Unlike C89, passing 0 for \p size does not free the
 * memory.  Instead, it resizes it to a 0-byte ralloc context, just like
 * calling ralloc_size(ctx, 0).  This is different from talloc.
 *
 * \param ctx  The context to use for new allocation.  If \p ptr != NULL,
 *             it must be the same as ralloc_parent(\p ptr).
 * \param ptr  Pointer to the memory to be resized.  May be NULL.
 * \param size The amount of memory to allocate, in bytes.
 */
void *reralloc_size(const void *ctx, void *ptr, size_t size);

/// \defgroup array Array Allocators @{

/**
 * \def ralloc_array(ctx, type, count)
 * Allocate an array of objects chained off the given context.
 *
 * Similar to \c calloc, but does not initialize the memory to zero.
 *
 * More than a convenience function, this also checks for integer overflow when
 * multiplying \c sizeof(type) and \p count.  This is necessary for security.
 *
 * This is equivalent to:
 * \code
 * ((type *) ralloc_array_size(ctx, sizeof(type), count)
 * \endcode
 */
#define ralloc_array(ctx, type, count) \
   ((type *) ralloc_array_size(ctx, sizeof(type), count))

/**
 * \def rzalloc_array(ctx, type, count)
 * Allocate a zero-initialized array chained off the given context.
 *
 * Similar to \c calloc.
 *
 * More than a convenience function, this also checks for integer overflow when
 * multiplying \c sizeof(type) and \p count.  This is necessary for security.
 *
 * This is equivalent to:
 * \code
 * ((type *) rzalloc_array_size(ctx, sizeof(type), count)
 * \endcode
 */
#define rzalloc_array(ctx, type, count) \
   ((type *) rzalloc_array_size(ctx, sizeof(type), count))

/**
 * \def reralloc(ctx, ptr, type, count)
 * Resize a ralloc-managed array, preserving data.
 *
 * Similar to \c realloc.  Unlike C89, passing 0 for \p size does not free the
 * memory.  Instead, it resizes it to a 0-byte ralloc context, just like
 * calling ralloc_size(ctx, 0).  This is different from talloc.
 *
 * More than a convenience function, this also checks for integer overflow when
 * multiplying \c sizeof(type) and \p count.  This is necessary for security.
 *
 * \param ctx   The context to use for new allocation.  If \p ptr != NULL,
 *              it must be the same as ralloc_parent(\p ptr).
 * \param ptr   Pointer to the array to be resized.  May be NULL.
 * \param type  The element type.
 * \param count The number of elements to allocate.
 */
#define reralloc(ctx, ptr, type, count) \
   ((type *) reralloc_array_size(ctx, ptr, sizeof(type), count))

/**
 * Allocate memory for an array chained off the given context.
 *
 * Similar to \c calloc, but does not initialize the memory to zero.
 *
 * More than a convenience function, this also checks for integer overflow when
 * multiplying \p size and \p count.  This is necessary for security.
 */
void *ralloc_array_size(const void *ctx, size_t size, unsigned count) MALLOCLIKE;

/**
 * Allocate a zero-initialized array chained off the given context.
 *
 * Similar to \c calloc.
 *
 * More than a convenience function, this also checks for integer overflow when
 * multiplying \p size and \p count.  This is necessary for security.
 */
void *rzalloc_array_size(const void *ctx, size_t size, unsigned count) MALLOCLIKE;

/**
 * Resize a ralloc-managed array, preserving data.
 *
 * Similar to \c realloc.  Unlike C89, passing 0 for \p size does not free the
 * memory.  Instead, it resizes it to a 0-byte ralloc context, just like
 * calling ralloc_size(ctx, 0).  This is different from talloc.
 *
 * More than a convenience function, this also checks for integer overflow when
 * multiplying \c sizeof(type) and \p count.  This is necessary for security.
 *
 * \param ctx   The context to use for new allocation.  If \p ptr != NULL,
 *              it must be the same as ralloc_parent(\p ptr).
 * \param ptr   Pointer to the array to be resized.  May be NULL.
 * \param size  The size of an individual element.
 * \param count The number of elements to allocate.
 *
 * \return True unless allocation failed.
 */
void *reralloc_array_size(const void *ctx, void *ptr, size_t size,
			  unsigned count);
/// @}

/**
 * Free a piece of ralloc-managed memory.
 *
 * This will also free the memory of any children allocated this context.
 */
void ralloc_free(void *ptr);

/**
 * "Steal" memory from one context, changing it to another.
 *
 * This changes \p ptr's context to \p new_ctx.  This is quite useful if
 * memory is allocated out of a temporary context.
 */
void ralloc_steal(const void *new_ctx, void *ptr);

/**
 * Return the given pointer's ralloc context.
 */
void *ralloc_parent(const void *ptr);

/**
 * Return a context whose memory will be automatically freed at program exit.
 *
 * The first call to this function creates a context and registers a handler
 * to free it using \c atexit.  This may cause trouble if used in a library
 * loaded with \c dlopen.
 */
void *ralloc_autofree_context(void);

/**
 * Set a callback to occur just before an object is freed.
 */
void ralloc_set_destructor(const void *ptr, void(*destructor)(void *));

/// \defgroup array String Functions @{
/**
 * Duplicate a string, allocating the memory from the given context.
 */
char *ralloc_strdup(const void *ctx, const char *str) MALLOCLIKE;

/**
 * Duplicate a string, allocating the memory from the given context.
 *
 * Like \c strndup, at most \p n characters are copied.  If \p str is longer
 * than \p n characters, \p n are copied, and a termining \c '\0' byte is added.
 */
char *ralloc_strndup(const void *ctx, const char *str, size_t n) MALLOCLIKE;

/**
 * Concatenate two strings, allocating the necessary space.
 *
 * This appends \p str to \p *dest, similar to \c strcat, using ralloc_resize
 * to expand \p *dest to the appropriate size.  \p dest will be updated to the
 * new pointer unless allocation fails.
 *
 * The result will always be null-terminated.
 *
 * \return True unless allocation failed.
 */
bool ralloc_strcat(char **dest, const char *str);

/**
 * Concatenate two strings, allocating the necessary space.
 *
 * This appends at most \p n bytes of \p str to \p *dest, using ralloc_resize
 * to expand \p *dest to the appropriate size.  \p dest will be updated to the
 * new pointer unless allocation fails.
 *
 * The result will always be null-terminated; \p str does not need to be null
 * terminated if it is longer than \p n.
 *
 * \return True unless allocation failed.
 */
bool ralloc_strncat(char **dest, const char *str, size_t n);

/**
 * Print to a string.
 *
 * This is analogous to \c sprintf, but allocates enough space (using \p ctx
 * as the context) for the resulting string.
 *
 * \return The newly allocated string.
 */
char *ralloc_asprintf (const void *ctx, const char *fmt, ...) PRINTFLIKE(2, 3) MALLOCLIKE;

/**
 * Print to a string, given a va_list.
 *
 * This is analogous to \c vsprintf, but allocates enough space (using \p ctx
 * as the context) for the resulting string.
 *
 * \return The newly allocated string.
 */
char *ralloc_vasprintf(const void *ctx, const char *fmt, va_list args) MALLOCLIKE;

/**
 * Rewrite the tail of an existing string, starting at a given index.
 *
 * Overwrites the contents of *str starting at \p start with newly formatted
 * text, including a new null-terminator.  Allocates more memory as necessary.
 *
 * This can be used to append formatted text when the length of the existing
 * string is already known, saving a strlen() call.
 *
 * \sa ralloc_asprintf_append
 *
 * \param str   The string to be updated.
 * \param start The index to start appending new data at.
 * \param fmt   A printf-style formatting string
 *
 * \p str will be updated to the new pointer unless allocation fails.
 * \p start will be increased by the length of the newly formatted text.
 *
 * \return True unless allocation failed.
 */
bool ralloc_asprintf_rewrite_tail(char **str, size_t *start,
				  const char *fmt, ...)
				  PRINTFLIKE(3, 4);

/**
 * Rewrite the tail of an existing string, starting at a given index.
 *
 * Overwrites the contents of *str starting at \p start with newly formatted
 * text, including a new null-terminator.  Allocates more memory as necessary.
 *
 * This can be used to append formatted text when the length of the existing
 * string is already known, saving a strlen() call.
 *
 * \sa ralloc_vasprintf_append
 *
 * \param str   The string to be updated.
 * \param start The index to start appending new data at.
 * \param fmt   A printf-style formatting string
 * \param args  A va_list containing the data to be formatted
 *
 * \p str will be updated to the new pointer unless allocation fails.
 * \p start will be increased by the length of the newly formatted text.
 *
 * \return True unless allocation failed.
 */
bool ralloc_vasprintf_rewrite_tail(char **str, size_t *start, const char *fmt,
				   va_list args);

/**
 * Append formatted text to the supplied string.
 *
 * This is equivalent to
 * \code
 * ralloc_asprintf_rewrite_tail(str, strlen(*str), fmt, ...)
 * \endcode
 *
 * \sa ralloc_asprintf
 * \sa ralloc_asprintf_rewrite_tail
 * \sa ralloc_strcat
 *
 * \p str will be updated to the new pointer unless allocation fails.
 *
 * \return True unless allocation failed.
 */
bool ralloc_asprintf_append (char **str, const char *fmt, ...)
			     PRINTFLIKE(2, 3);

/**
 * Append formatted text to the supplied string, given a va_list.
 *
 * This is equivalent to
 * \code
 * ralloc_vasprintf_rewrite_tail(str, strlen(*str), fmt, args)
 * \endcode
 *
 * \sa ralloc_vasprintf
 * \sa ralloc_vasprintf_rewrite_tail
 * \sa ralloc_strcat
 *
 * \p str will be updated to the new pointer unless allocation fails.
 *
 * \return True unless allocation failed.
 */
bool ralloc_vasprintf_append(char **str, const char *fmt, va_list args);
/// @}

#ifdef __cplusplus
} /* end of extern "C" */
#endif

/**
 * Declare C++ new and delete operators which use ralloc.
 *
 * Placing this macro in the body of a class makes it possible to do:
 *
 * TYPE *var = new(mem_ctx) TYPE(...);
 * delete var;
 *
 * which is more idiomatic in C++ than calling ralloc.
 */
#define DECLARE_RALLOC_CXX_OPERATORS(TYPE)                               \
private:                                                                 \
   static void _ralloc_destructor(void *p)                               \
   {                                                                     \
      reinterpret_cast<TYPE *>(p)->~TYPE();                              \
   }                                                                     \
public:                                                                  \
   static void* operator new(size_t size, void *mem_ctx)                 \
   {                                                                     \
      void *p = ralloc_size(mem_ctx, size);                              \
      assert(p != NULL);                                                 \
      if (!HAS_TRIVIAL_DESTRUCTOR(TYPE))                                 \
         ralloc_set_destructor(p, _ralloc_destructor);                   \
      return p;                                                          \
   }                                                                     \
                                                                         \
   static void operator delete(void *p)                                  \
   {                                                                     \
      /* The object's destructor is guaranteed to have already been      \
       * called by the delete operator at this point -- Make sure it's   \
       * not called again.                                               \
       */                                                                \
      if (!HAS_TRIVIAL_DESTRUCTOR(TYPE))                                 \
         ralloc_set_destructor(p, NULL);                                 \
      ralloc_free(p);                                                    \
   }


#endif