data-stack.h revision 33b0119d4effb14cd0f1bdd3ad5f2954e3b1e63e
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen/* Data stack makes it very easy to implement functions returning dynamic data
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen without having to worry much about memory management like freeing the
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen result or having large enough buffers for the result.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_ prefix was chosen to describe functions allocating memory from data
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen stack. "t" meaning temporary.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen Advantages over control stack and alloca():
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen - Functions can return a value allocated from data stack
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen - We can portably specify how much data we want to allocate at runtime
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen Advantages over malloc():
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen - FAST, most of the time allocating memory means only updating a couple of
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen pointers and integers. Freeing the memory all at once also is a fast
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen - No need to free() each allocation resulting in prettier code
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen - No memory leaks
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen - No memory fragmentation
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen Disadvantages:
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen - Allocating memory inside loops can accidentally allocate a lot of memory
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if the loops are long and you forgot to place t_push() and t_pop() there.
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen - t_malloc()ed data could be accidentally stored into permanent location
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen and accessed after it's already been freed. const'ing the return values
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen helps for most uses though (see the t_malloc() description).
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen - Debugging invalid memory usage may be difficult using existing tools,
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen although compiling with DEBUG enabled helps finding simple buffer
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenextern unsigned int data_stack_frame;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen/* All t_..() allocations between t_push*() and t_pop() are freed after t_pop()
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen is called. Returns the current stack frame number, which can be used
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen to detect missing t_pop() calls:
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen x = t_push(__func__); .. if (t_pop() != x) abort();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen In DEBUG mode, t_push_named() makes a temporary allocation for the name,
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen but is safe to call in a loop as it performs the allocation within its own
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen frame. However, you should always prefer to use T_BEGIN { ... } T_END below.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenunsigned int t_push(const char *marker) ATTR_HOT;
03739a8eaad2d8b34b9d87dbbe5b13c5d5dfa11aTimo Sirainenunsigned int t_push_named(const char *format, ...) ATTR_HOT ATTR_FORMAT(1, 2);
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen/* Simplifies the if (t_pop() != x) check by comparing it internally and
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen panicking if it doesn't match. */
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen/* Usage: T_BEGIN { code } T_END */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen STMT_START { unsigned int _data_stack_cur_id = t_push(NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#elif defined (__GNUC__) && !defined (__STRICT_ANSI__)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen STMT_START { unsigned int _data_stack_cur_id = t_push(__FUNCTION__);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen STMT_START { unsigned int _data_stack_cur_id = t_push(T_CAT2(__FILE__,__LINE__));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* WARNING: Be careful when using these functions, it's too easy to
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen accidentally save the returned value somewhere permanently.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen You probably should never use these functions directly, rather
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen create functions that return 'const xxx*' types and use t_malloc()
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen internally in them. This is a lot safer, since usually compiler
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen warns if you try to place them in xxx*. See strfuncs.c for examples.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_malloc() calls never fail. If there's not enough memory left,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_panic() will be called. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid *t_malloc(size_t size) ATTR_MALLOC ATTR_RETURNS_NONNULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid *t_malloc0(size_t size) ATTR_MALLOC ATTR_RETURNS_NONNULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Try growing allocated memory. Returns TRUE if successful. Works only
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for last allocated memory in current stack frame. */
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen/* Returns the number of bytes available in data stack without allocating
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen more memory. */
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen/* Returns pointer to a temporary buffer you can use. The buffer will be
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen invalid as soon as next t_malloc() is called!
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen If you wish to grow the buffer, you must give the full wanted size
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen in the size parameter. If return value doesn't point to the same value
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen as last time, you need to memcpy() data from the old buffer to the
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen new one (or do some other trickery). See t_buffer_reget(). */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainenvoid *t_buffer_get(size_t size) ATTR_RETURNS_NONNULL;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen/* Grow the buffer, memcpy()ing the memory to new location if needed. */
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen#define t_buffer_reget_type(buffer, type, size) \
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainenvoid *t_buffer_reget(void *buffer, size_t size) ATTR_RETURNS_NONNULL;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen/* Make the last t_buffer_get()ed buffer permanent. Note that size MUST be
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen less or equal than the size you gave with last t_buffer_get() or the
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen result will be undefined. */
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen/* Allocate the last t_buffer_get()ed data entirely. */
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen/* If enabled, all the used memory is cleared after t_pop(). */