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
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
// SPDX-License-Identifier: LGPL-2.1-or-later
/**
* @file
*
* String builder interface.
*
* See @ref StringBuilding.
*/
#ifndef DRGN_STRING_BUILDER_H
#define DRGN_STRING_BUILDER_H
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
/**
* @ingroup Internals
*
* @defgroup StringBuilding String building
*
* String builder interface.
*
* @ref string_builder provides an append-only way to build a string piece by
* piece. @ref string_callback provides an alternative to prepending pieces.
*
* @{
*/
/**
* String builder.
*
* A string builder consists of a buffer and a length. The buffer is resized as
* needed. The buffer can only be appended to; see @ref string_callback for an
* alternative to insertion.
*/
struct string_builder {
/**
* Current string buffer.
*
* This may be reallocated when appending.
*/
char *str;
/** Length of @c str. */
size_t len;
/** Allocated size of @c str. */
size_t capacity;
};
/** String builder initializer. */
#define STRING_BUILDER_INIT { 0 }
/** Free memory allocated by a @ref string_builder. */
static inline void string_builder_deinit(struct string_builder *sb)
{
free(sb->str);
}
/**
* Define and initialize a @ref string_builder named @p sb that is automatically
* deinitialized when it goes out of scope.
*/
#define STRING_BUILDER(sb) \
__attribute__((__cleanup__(string_builder_deinit))) \
struct string_builder sb = STRING_BUILDER_INIT
/**
* Steal the string buffer from a @ref string_builder.
*
* The string builder can no longer be used except to be passed to @ref
* string_builder_deinit(), which will do nothing.
*
* @return String buffer. This must be freed with @c free().
*/
static inline char *string_builder_steal(struct string_builder *sb)
{
char *str = sb->str;
sb->str = NULL;
return str;
}
/**
* Null-terminate a @ref string_builder.
*
* This appends a null character without incrementing @ref string_builder::len.
*
* @return @c true on success, @c false on error (if we couldn't allocate
* memory).
*/
bool string_builder_null_terminate(struct string_builder *sb);
/**
* Resize the buffer of a @ref string_builder to a given capacity.
*
* On success, the allocated size of the string buffer is at least @p capacity.
*
* @param[in] sb String builder.
* @param[in] capacity New minimum allocated size of the string buffer.
* @return @c true on success, @c false on error (if we couldn't allocate
* memory).
*/
bool string_builder_reserve(struct string_builder *sb, size_t capacity);
/**
* Resize the buffer of a @ref string_builder to accomodate appending
* characters.
*
* On success, the allocated size of the string buffer is at least
* `sb->len + n`. This will also allocate extra space so that appends have
* amortized constant time complexity.
*
* @param[in] sb String builder.
* @param[in] n Minimum number of additional characters to reserve.
* @return @c true on success, @c false on error (if we couldn't allocate
* memory).
*/
bool string_builder_reserve_for_append(struct string_builder *sb, size_t n);
/**
* Append a character to a @ref string_builder.
*
* @param[in] sb String builder.
* @param[in] c Character to append.
* @return @c true on success, @c false on error (if we couldn't allocate
* memory).
*/
bool string_builder_appendc(struct string_builder *sb, char c);
/**
* Append a number of characters from a string to a @ref string_builder.
*
* @param[in] sb String builder.
* @param[in] str String to append.
* @param[in] len Number of characters from @c str to append.
* @return @c true on success, @c false on error (if we couldn't allocate
* memory).
*/
bool string_builder_appendn(struct string_builder *sb, const char *str,
size_t len);
/**
* Append a null-terminated string to a @ref string_builder.
*
* @param[in] sb String builder.
* @param[in] str String to append.
* @return @c true on success, @c false on error (if we couldn't allocate
* memory).
*/
static inline bool string_builder_append(struct string_builder *sb,
const char *str)
{
return string_builder_appendn(sb, str, strlen(str));
}
/**
* Append a string to a @ref string_builder from a printf-style format.
*
* @param[in] sb String builder.
* @param[in] format printf-style format string.
* @param[in] ... Arguments for the format string.
* @return @c true on success, @c false on error (if we couldn't allocate
* memory).
*/
bool string_builder_appendf(struct string_builder *sb, const char *format, ...)
__attribute__((__format__(__printf__, 2, 3)));
/**
* Append a string to a @ref string_builder from vprintf-style arguments.
*
* @sa string_builder_appendf()
*
* @param[in] sb String builder.
* @param[in] format printf-style format string.
* @param[in] ap Arguments for the format string.
* @return @c true on success, @c false on error (if we couldn't allocate
* memory).
*/
bool string_builder_vappendf(struct string_builder *sb, const char *format,
va_list ap);
/**
* Append a newline character to a @ref string_builder if the string isn't empty
* and doesn't already end in a newline.
*
* @param[in] sb String builder.
* @return @c true on success, @c false on error (if we couldn't allocate
* memory).
*/
bool string_builder_line_break(struct string_builder *sb);
/**
* Callback to append to a string later.
*
* Instead of providing functionality to prepend to a @ref string_builder, we
* achieve the same thing by passing around a callback until all prefixes have
* been appended, then calling the callback to append the "infix". This avoids
* the O(n) array shift required for prepend.
*/
struct string_callback {
/** Callback function. */
struct drgn_error *(*fn)(struct string_callback *str, void *arg,
struct string_builder *sb);
/**
* Another string callback to be passed to the callback.
*
* This is useful for strings that need to be built recursively.
*/
struct string_callback *str;
/** Callback argument. */
void *arg;
};
/**
* Call a string callback.
*
* The callback function will be passed @ref string_callback::str and @ref
* string_callback::arg.
*
* @param[in] str String callback. If @c NULL, this is a no-op.
* @param[in] sb String builder to append to.
* @return @c true on success, @c false on error (if we couldn't allocate
* memory).
*/
static inline struct drgn_error *string_callback_call(struct string_callback *str,
struct string_builder *sb)
{
if (str)
return str->fn(str->str, str->arg, sb);
else
return NULL;
}
/** @} */
#endif /* DRGN_STRING_BUILDER_H */
|