This module is obsolete. Please use growing arrays instead.

It is quite usual situation when you need an array of items and you don not know how large it will be in the time you allocate it. Then you need some kind of dynamically growing buffer.

Generic growing buffers

The generic buffers are in ucw/gbuf.h. They are generics generated by preprocessor. To use them, you need to define:

  • GBUF_PREFIX(name) — the identifier generating macro.

  • GBUF_TYPE — the data type they operate with.

You may define GBUF_TRACE(\...) macro. If you do, it will be used to log the growing of the buffer. The macro should act like printf() — the first parameter will be format, the rest variables for it.

#define BUF_T   GBUF_PREFIX(t)

Type identifier of the buffer. The macro is not available outside the header file, but it is used in the definitions of functions.

typedef struct BUF_T {
  size_t len;
  GBUF_TYPE *ptr;
} BUF_T;

The growing buffer. ptr holds the memory and len is the current length of available memory.

static inline void GBUF_PREFIX(init)(BUF_T *b);

Initializes an empty growing buffer in b.

static void UNUSED GBUF_PREFIX(done)(BUF_T *b);

Frees all memory in the buffer and returns it to an empty state.

static void UNUSED GBUF_PREFIX(set_size)(BUF_T *b, size_t len);

Sets the length of the buffer b to exactly len. Do not use for the growing (you can use this at the end, when you know the exact size), it would be slow.

Use GBUF_PREFIX(grow)() for growing.

static inline GBUF_TYPE *GBUF_PREFIX(grow)(BUF_T *b, size_t len);

Sets the size of the buffer b to at last len. It grows in exponential manner, to ensure the total cost of reallocs is linear with the final size.

You can tweak the final size (when you do not need to grow any more) by GBUF_PREFIX(set_size)().

Growing buffers for byte-sized items

It is often needed to allocate the buffer by bytes (if you handle some anonymous data) or characters (strings of unknown length).

With the ucw/bbuf.h header, you get an instance of growing buffers with type byte and prefix bb_. Aside from that, you get few functions to manipulate strings in the buffers.

char *bb_vprintf(bb_t *bb, const char *fmt, va_list args);

printf() into a growing buffer with va_list arguments. Generates a '\0'-terminated string at the beginning of the buffer and returns pointer to it.

char *bb_printf(bb_t *bb, const char *fmt, ...);

printf() into a growing buffer. Generates a '\0'-terminated string at the beginning of the buffer and returns pointer to it.

char *bb_vprintf_at(bb_t *bb, size_t ofs, const char *fmt, va_list args);

Like bb_vprintf(), but it does not start at the beginning of the buffer, but ofs bytes further.

Returns pointer to the new string (eg. ofs bytes after the beginning of buffer).

char *bb_printf_at(bb_t *bb, size_t ofs, const char *fmt, ...);

Like bb_vprintf_at(), but it takes individual arguments.