File: string_builder.h

package info (click to toggle)
drgn 0.0.33-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,892 kB
  • sloc: python: 59,081; ansic: 51,400; awk: 423; makefile: 339; sh: 113
file content (239 lines) | stat: -rw-r--r-- 6,683 bytes parent folder | download | duplicates (2)
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 */