1 #ifndef JEMALLOC_INTERNAL_EMITTER_H
2 #define JEMALLOC_INTERNAL_EMITTER_H
4 #include "jemalloc/internal/ql.h"
6 typedef enum emitter_output_e emitter_output_t;
7 enum emitter_output_e {
12 typedef enum emitter_justify_e emitter_justify_t;
13 enum emitter_justify_e {
15 emitter_justify_right,
16 /* Not for users; just to pass to internal functions. */
20 typedef enum emitter_type_e emitter_type_t;
24 emitter_type_unsigned,
31 * A title is a column title in a table; it's just a string, but it's
37 typedef struct emitter_col_s emitter_col_t;
38 struct emitter_col_s {
39 /* Filled in by the user. */
40 emitter_justify_t justify;
46 unsigned unsigned_val;
48 uint32_t uint32_t_val;
50 uint64_t uint64_t_val;
56 /* Filled in by initialization. */
57 ql_elm(emitter_col_t) link;
60 typedef struct emitter_row_s emitter_row_t;
61 struct emitter_row_s {
62 ql_head(emitter_col_t) cols;
65 typedef struct emitter_s emitter_t;
67 emitter_output_t output;
68 /* The output information. */
69 void (*write_cb)(void *, const char *);
72 /* True if we've already emitted a value at the given depth. */
74 /* True if we emitted a key and will emit corresponding value next. */
78 /* Internal convenience function. Write to the emitter the given string. */
79 JEMALLOC_FORMAT_PRINTF(2, 3)
81 emitter_printf(emitter_t *emitter, const char *format, ...) {
85 malloc_vcprintf(emitter->write_cb, emitter->cbopaque, format, ap);
89 static inline const char * JEMALLOC_FORMAT_ARG(3)
90 emitter_gen_fmt(char *out_fmt, size_t out_size, const char *fmt_specifier,
91 emitter_justify_t justify, int width) {
94 if (justify == emitter_justify_none) {
95 written = malloc_snprintf(out_fmt, out_size,
96 "%%%s", fmt_specifier);
97 } else if (justify == emitter_justify_left) {
98 written = malloc_snprintf(out_fmt, out_size,
99 "%%-%d%s", width, fmt_specifier);
101 written = malloc_snprintf(out_fmt, out_size,
102 "%%%d%s", width, fmt_specifier);
104 /* Only happens in case of bad format string, which *we* choose. */
105 assert(written < out_size);
110 * Internal. Emit the given value type in the relevant encoding (so that the
111 * bool true gets mapped to json "true", but the string "true" gets mapped to
112 * json "\"true\"", for instance.
114 * Width is ignored if justify is emitter_justify_none.
117 emitter_print_value(emitter_t *emitter, emitter_justify_t justify, int width,
118 emitter_type_t value_type, const void *value) {
123 * We dynamically generate a format string to emit, to let us use the
124 * snprintf machinery. This is kinda hacky, but gets the job done
125 * quickly without having to think about the various snprintf edge
131 #define EMIT_SIMPLE(type, format) \
132 emitter_printf(emitter, \
133 emitter_gen_fmt(fmt, FMT_SIZE, format, justify, width), \
134 *(const type *)value);
136 switch (value_type) {
137 case emitter_type_bool:
138 emitter_printf(emitter,
139 emitter_gen_fmt(fmt, FMT_SIZE, "%s", justify, width),
140 *(const bool *)value ? "true" : "false");
142 case emitter_type_int:
143 EMIT_SIMPLE(int, "%d")
145 case emitter_type_unsigned:
146 EMIT_SIMPLE(unsigned, "%u")
148 case emitter_type_ssize:
149 EMIT_SIMPLE(ssize_t, "%zd")
151 case emitter_type_size:
152 EMIT_SIMPLE(size_t, "%zu")
154 case emitter_type_string:
155 str_written = malloc_snprintf(buf, BUF_SIZE, "\"%s\"",
156 *(const char *const *)value);
158 * We control the strings we output; we shouldn't get anything
159 * anywhere near the fmt size.
161 assert(str_written < BUF_SIZE);
162 emitter_printf(emitter,
163 emitter_gen_fmt(fmt, FMT_SIZE, "%s", justify, width), buf);
165 case emitter_type_uint32:
166 EMIT_SIMPLE(uint32_t, "%" FMTu32)
168 case emitter_type_uint64:
169 EMIT_SIMPLE(uint64_t, "%" FMTu64)
171 case emitter_type_title:
172 EMIT_SIMPLE(char *const, "%s");
182 /* Internal functions. In json mode, tracks nesting state. */
184 emitter_nest_inc(emitter_t *emitter) {
185 emitter->nesting_depth++;
186 emitter->item_at_depth = false;
190 emitter_nest_dec(emitter_t *emitter) {
191 emitter->nesting_depth--;
192 emitter->item_at_depth = true;
196 emitter_indent(emitter_t *emitter) {
197 int amount = emitter->nesting_depth;
198 const char *indent_str;
199 if (emitter->output == emitter_output_json) {
205 for (int i = 0; i < amount; i++) {
206 emitter_printf(emitter, "%s", indent_str);
211 emitter_json_key_prefix(emitter_t *emitter) {
212 if (emitter->emitted_key) {
213 emitter->emitted_key = false;
216 emitter_printf(emitter, "%s\n", emitter->item_at_depth ? "," : "");
217 emitter_indent(emitter);
220 /******************************************************************************/
221 /* Public functions for emitter_t. */
224 emitter_init(emitter_t *emitter, emitter_output_t emitter_output,
225 void (*write_cb)(void *, const char *), void *cbopaque) {
226 emitter->output = emitter_output;
227 emitter->write_cb = write_cb;
228 emitter->cbopaque = cbopaque;
229 emitter->item_at_depth = false;
230 emitter->emitted_key = false;
231 emitter->nesting_depth = 0;
234 /******************************************************************************/
235 /* JSON public API. */
238 * Emits a key (e.g. as appears in an object). The next json entity emitted will
239 * be the corresponding value.
242 emitter_json_key(emitter_t *emitter, const char *json_key) {
243 if (emitter->output == emitter_output_json) {
244 emitter_json_key_prefix(emitter);
245 emitter_printf(emitter, "\"%s\": ", json_key);
246 emitter->emitted_key = true;
251 emitter_json_value(emitter_t *emitter, emitter_type_t value_type,
253 if (emitter->output == emitter_output_json) {
254 emitter_json_key_prefix(emitter);
255 emitter_print_value(emitter, emitter_justify_none, -1,
257 emitter->item_at_depth = true;
261 /* Shorthand for calling emitter_json_key and then emitter_json_value. */
263 emitter_json_kv(emitter_t *emitter, const char *json_key,
264 emitter_type_t value_type, const void *value) {
265 emitter_json_key(emitter, json_key);
266 emitter_json_value(emitter, value_type, value);
270 emitter_json_array_begin(emitter_t *emitter) {
271 if (emitter->output == emitter_output_json) {
272 emitter_json_key_prefix(emitter);
273 emitter_printf(emitter, "[");
274 emitter_nest_inc(emitter);
278 /* Shorthand for calling emitter_json_key and then emitter_json_array_begin. */
280 emitter_json_array_kv_begin(emitter_t *emitter, const char *json_key) {
281 emitter_json_key(emitter, json_key);
282 emitter_json_array_begin(emitter);
286 emitter_json_array_end(emitter_t *emitter) {
287 if (emitter->output == emitter_output_json) {
288 assert(emitter->nesting_depth > 0);
289 emitter_nest_dec(emitter);
290 emitter_printf(emitter, "\n");
291 emitter_indent(emitter);
292 emitter_printf(emitter, "]");
297 emitter_json_object_begin(emitter_t *emitter) {
298 if (emitter->output == emitter_output_json) {
299 emitter_json_key_prefix(emitter);
300 emitter_printf(emitter, "{");
301 emitter_nest_inc(emitter);
305 /* Shorthand for calling emitter_json_key and then emitter_json_object_begin. */
307 emitter_json_object_kv_begin(emitter_t *emitter, const char *json_key) {
308 emitter_json_key(emitter, json_key);
309 emitter_json_object_begin(emitter);
313 emitter_json_object_end(emitter_t *emitter) {
314 if (emitter->output == emitter_output_json) {
315 assert(emitter->nesting_depth > 0);
316 emitter_nest_dec(emitter);
317 emitter_printf(emitter, "\n");
318 emitter_indent(emitter);
319 emitter_printf(emitter, "}");
324 /******************************************************************************/
325 /* Table public API. */
328 emitter_table_dict_begin(emitter_t *emitter, const char *table_key) {
329 if (emitter->output == emitter_output_table) {
330 emitter_indent(emitter);
331 emitter_printf(emitter, "%s\n", table_key);
332 emitter_nest_inc(emitter);
337 emitter_table_dict_end(emitter_t *emitter) {
338 if (emitter->output == emitter_output_table) {
339 emitter_nest_dec(emitter);
344 emitter_table_kv_note(emitter_t *emitter, const char *table_key,
345 emitter_type_t value_type, const void *value,
346 const char *table_note_key, emitter_type_t table_note_value_type,
347 const void *table_note_value) {
348 if (emitter->output == emitter_output_table) {
349 emitter_indent(emitter);
350 emitter_printf(emitter, "%s: ", table_key);
351 emitter_print_value(emitter, emitter_justify_none, -1,
353 if (table_note_key != NULL) {
354 emitter_printf(emitter, " (%s: ", table_note_key);
355 emitter_print_value(emitter, emitter_justify_none, -1,
356 table_note_value_type, table_note_value);
357 emitter_printf(emitter, ")");
359 emitter_printf(emitter, "\n");
361 emitter->item_at_depth = true;
365 emitter_table_kv(emitter_t *emitter, const char *table_key,
366 emitter_type_t value_type, const void *value) {
367 emitter_table_kv_note(emitter, table_key, value_type, value, NULL,
368 emitter_type_bool, NULL);
372 /* Write to the emitter the given string, but only in table mode. */
373 JEMALLOC_FORMAT_PRINTF(2, 3)
375 emitter_table_printf(emitter_t *emitter, const char *format, ...) {
376 if (emitter->output == emitter_output_table) {
378 va_start(ap, format);
379 malloc_vcprintf(emitter->write_cb, emitter->cbopaque, format, ap);
385 emitter_table_row(emitter_t *emitter, emitter_row_t *row) {
386 if (emitter->output != emitter_output_table) {
390 ql_foreach(col, &row->cols, link) {
391 emitter_print_value(emitter, col->justify, col->width,
392 col->type, (const void *)&col->bool_val);
394 emitter_table_printf(emitter, "\n");
398 emitter_row_init(emitter_row_t *row) {
403 emitter_col_init(emitter_col_t *col, emitter_row_t *row) {
404 ql_elm_new(col, link);
405 ql_tail_insert(&row->cols, col, link);
409 /******************************************************************************/
411 * Generalized public API. Emits using either JSON or table, according to
412 * settings in the emitter_t. */
415 * Note emits a different kv pair as well, but only in table mode. Omits the
416 * note if table_note_key is NULL.
419 emitter_kv_note(emitter_t *emitter, const char *json_key, const char *table_key,
420 emitter_type_t value_type, const void *value,
421 const char *table_note_key, emitter_type_t table_note_value_type,
422 const void *table_note_value) {
423 if (emitter->output == emitter_output_json) {
424 emitter_json_key(emitter, json_key);
425 emitter_json_value(emitter, value_type, value);
427 emitter_table_kv_note(emitter, table_key, value_type, value,
428 table_note_key, table_note_value_type, table_note_value);
430 emitter->item_at_depth = true;
434 emitter_kv(emitter_t *emitter, const char *json_key, const char *table_key,
435 emitter_type_t value_type, const void *value) {
436 emitter_kv_note(emitter, json_key, table_key, value_type, value, NULL,
437 emitter_type_bool, NULL);
441 emitter_dict_begin(emitter_t *emitter, const char *json_key,
442 const char *table_header) {
443 if (emitter->output == emitter_output_json) {
444 emitter_json_key(emitter, json_key);
445 emitter_json_object_begin(emitter);
447 emitter_table_dict_begin(emitter, table_header);
452 emitter_dict_end(emitter_t *emitter) {
453 if (emitter->output == emitter_output_json) {
454 emitter_json_object_end(emitter);
456 emitter_table_dict_end(emitter);
461 emitter_begin(emitter_t *emitter) {
462 if (emitter->output == emitter_output_json) {
463 assert(emitter->nesting_depth == 0);
464 emitter_printf(emitter, "{");
465 emitter_nest_inc(emitter);
468 * This guarantees that we always call write_cb at least once.
469 * This is useful if some invariant is established by each call
470 * to write_cb, but doesn't hold initially: e.g., some buffer
471 * holds a null-terminated string.
473 emitter_printf(emitter, "%s", "");
478 emitter_end(emitter_t *emitter) {
479 if (emitter->output == emitter_output_json) {
480 assert(emitter->nesting_depth == 1);
481 emitter_nest_dec(emitter);
482 emitter_printf(emitter, "\n}\n");
486 #endif /* JEMALLOC_INTERNAL_EMITTER_H */