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;
54 /* Filled in by initialization. */
55 ql_elm(emitter_col_t) link;
58 typedef struct emitter_row_s emitter_row_t;
59 struct emitter_row_s {
60 ql_head(emitter_col_t) cols;
64 emitter_row_init(emitter_row_t *row) {
69 emitter_col_init(emitter_col_t *col, emitter_row_t *row) {
70 ql_elm_new(col, link);
71 ql_tail_insert(&row->cols, col, link);
74 typedef struct emitter_s emitter_t;
76 emitter_output_t output;
77 /* The output information. */
78 void (*write_cb)(void *, const char *);
81 /* True if we've already emitted a value at the given depth. */
86 emitter_init(emitter_t *emitter, emitter_output_t emitter_output,
87 void (*write_cb)(void *, const char *), void *cbopaque) {
88 emitter->output = emitter_output;
89 emitter->write_cb = write_cb;
90 emitter->cbopaque = cbopaque;
91 emitter->item_at_depth = false;
92 emitter->nesting_depth = 0;
95 /* Internal convenience function. Write to the emitter the given string. */
96 JEMALLOC_FORMAT_PRINTF(2, 3)
98 emitter_printf(emitter_t *emitter, const char *format, ...) {
101 va_start(ap, format);
102 malloc_vcprintf(emitter->write_cb, emitter->cbopaque, format, ap);
106 /* Write to the emitter the given string, but only in table mode. */
107 JEMALLOC_FORMAT_PRINTF(2, 3)
109 emitter_table_printf(emitter_t *emitter, const char *format, ...) {
110 if (emitter->output == emitter_output_table) {
112 va_start(ap, format);
113 malloc_vcprintf(emitter->write_cb, emitter->cbopaque, format, ap);
119 emitter_gen_fmt(char *out_fmt, size_t out_size, const char *fmt_specifier,
120 emitter_justify_t justify, int width) {
122 if (justify == emitter_justify_none) {
123 written = malloc_snprintf(out_fmt, out_size,
124 "%%%s", fmt_specifier);
125 } else if (justify == emitter_justify_left) {
126 written = malloc_snprintf(out_fmt, out_size,
127 "%%-%d%s", width, fmt_specifier);
129 written = malloc_snprintf(out_fmt, out_size,
130 "%%%d%s", width, fmt_specifier);
132 /* Only happens in case of bad format string, which *we* choose. */
133 assert(written < out_size);
137 * Internal. Emit the given value type in the relevant encoding (so that the
138 * bool true gets mapped to json "true", but the string "true" gets mapped to
139 * json "\"true\"", for instance.
141 * Width is ignored if justify is emitter_justify_none.
144 emitter_print_value(emitter_t *emitter, emitter_justify_t justify, int width,
145 emitter_type_t value_type, const void *value) {
150 * We dynamically generate a format string to emit, to let us use the
151 * snprintf machinery. This is kinda hacky, but gets the job done
152 * quickly without having to think about the various snprintf edge
158 #define EMIT_SIMPLE(type, format) \
159 emitter_gen_fmt(fmt, FMT_SIZE, format, justify, width); \
160 emitter_printf(emitter, fmt, *(const type *)value); \
162 switch (value_type) {
163 case emitter_type_bool:
164 emitter_gen_fmt(fmt, FMT_SIZE, "s", justify, width);
165 emitter_printf(emitter, fmt, *(const bool *)value ?
168 case emitter_type_int:
169 EMIT_SIMPLE(int, "d")
171 case emitter_type_unsigned:
172 EMIT_SIMPLE(unsigned, "u")
174 case emitter_type_ssize:
175 EMIT_SIMPLE(ssize_t, "zd")
177 case emitter_type_size:
178 EMIT_SIMPLE(size_t, "zu")
180 case emitter_type_string:
181 str_written = malloc_snprintf(buf, BUF_SIZE, "\"%s\"",
182 *(const char *const *)value);
184 * We control the strings we output; we shouldn't get anything
185 * anywhere near the fmt size.
187 assert(str_written < BUF_SIZE);
188 emitter_gen_fmt(fmt, FMT_SIZE, "s", justify, width);
189 emitter_printf(emitter, fmt, buf);
191 case emitter_type_uint32:
192 EMIT_SIMPLE(uint32_t, FMTu32)
194 case emitter_type_uint64:
195 EMIT_SIMPLE(uint64_t, FMTu64)
197 case emitter_type_title:
198 EMIT_SIMPLE(char *const, "s");
208 /* Internal functions. In json mode, tracks nesting state. */
210 emitter_nest_inc(emitter_t *emitter) {
211 emitter->nesting_depth++;
212 emitter->item_at_depth = false;
216 emitter_nest_dec(emitter_t *emitter) {
217 emitter->nesting_depth--;
218 emitter->item_at_depth = true;
222 emitter_indent(emitter_t *emitter) {
223 int amount = emitter->nesting_depth;
224 const char *indent_str;
225 if (emitter->output == emitter_output_json) {
231 for (int i = 0; i < amount; i++) {
232 emitter_printf(emitter, "%s", indent_str);
237 emitter_json_key_prefix(emitter_t *emitter) {
238 emitter_printf(emitter, "%s\n", emitter->item_at_depth ? "," : "");
239 emitter_indent(emitter);
243 emitter_begin(emitter_t *emitter) {
244 if (emitter->output == emitter_output_json) {
245 assert(emitter->nesting_depth == 0);
246 emitter_printf(emitter, "{");
247 emitter_nest_inc(emitter);
250 emitter_printf(emitter, "%s", "");
255 emitter_end(emitter_t *emitter) {
256 if (emitter->output == emitter_output_json) {
257 assert(emitter->nesting_depth == 1);
258 emitter_nest_dec(emitter);
259 emitter_printf(emitter, "\n}\n");
264 * Note emits a different kv pair as well, but only in table mode. Omits the
265 * note if table_note_key is NULL.
268 emitter_kv_note(emitter_t *emitter, const char *json_key, const char *table_key,
269 emitter_type_t value_type, const void *value,
270 const char *table_note_key, emitter_type_t table_note_value_type,
271 const void *table_note_value) {
272 if (emitter->output == emitter_output_json) {
273 assert(emitter->nesting_depth > 0);
274 emitter_json_key_prefix(emitter);
275 emitter_printf(emitter, "\"%s\": ", json_key);
276 emitter_print_value(emitter, emitter_justify_none, -1,
279 emitter_indent(emitter);
280 emitter_printf(emitter, "%s: ", table_key);
281 emitter_print_value(emitter, emitter_justify_none, -1,
283 if (table_note_key != NULL) {
284 emitter_printf(emitter, " (%s: ", table_note_key);
285 emitter_print_value(emitter, emitter_justify_none, -1,
286 table_note_value_type, table_note_value);
287 emitter_printf(emitter, ")");
289 emitter_printf(emitter, "\n");
291 emitter->item_at_depth = true;
295 emitter_kv(emitter_t *emitter, const char *json_key, const char *table_key,
296 emitter_type_t value_type, const void *value) {
297 emitter_kv_note(emitter, json_key, table_key, value_type, value, NULL,
298 emitter_type_bool, NULL);
302 emitter_json_kv(emitter_t *emitter, const char *json_key,
303 emitter_type_t value_type, const void *value) {
304 if (emitter->output == emitter_output_json) {
305 emitter_kv(emitter, json_key, NULL, value_type, value);
310 emitter_table_kv(emitter_t *emitter, const char *table_key,
311 emitter_type_t value_type, const void *value) {
312 if (emitter->output == emitter_output_table) {
313 emitter_kv(emitter, NULL, table_key, value_type, value);
318 emitter_dict_begin(emitter_t *emitter, const char *json_key,
319 const char *table_header) {
320 if (emitter->output == emitter_output_json) {
321 emitter_json_key_prefix(emitter);
322 emitter_printf(emitter, "\"%s\": {", json_key);
323 emitter_nest_inc(emitter);
325 emitter_indent(emitter);
326 emitter_printf(emitter, "%s\n", table_header);
327 emitter_nest_inc(emitter);
332 emitter_dict_end(emitter_t *emitter) {
333 if (emitter->output == emitter_output_json) {
334 assert(emitter->nesting_depth > 0);
335 emitter_nest_dec(emitter);
336 emitter_printf(emitter, "\n");
337 emitter_indent(emitter);
338 emitter_printf(emitter, "}");
340 emitter_nest_dec(emitter);
345 emitter_json_dict_begin(emitter_t *emitter, const char *json_key) {
346 if (emitter->output == emitter_output_json) {
347 emitter_dict_begin(emitter, json_key, NULL);
352 emitter_json_dict_end(emitter_t *emitter) {
353 if (emitter->output == emitter_output_json) {
354 emitter_dict_end(emitter);
359 emitter_table_dict_begin(emitter_t *emitter, const char *table_key) {
360 if (emitter->output == emitter_output_table) {
361 emitter_dict_begin(emitter, NULL, table_key);
366 emitter_table_dict_end(emitter_t *emitter) {
367 if (emitter->output == emitter_output_table) {
368 emitter_dict_end(emitter);
373 emitter_json_arr_begin(emitter_t *emitter, const char *json_key) {
374 if (emitter->output == emitter_output_json) {
375 emitter_json_key_prefix(emitter);
376 emitter_printf(emitter, "\"%s\": [", json_key);
377 emitter_nest_inc(emitter);
382 emitter_json_arr_end(emitter_t *emitter) {
383 if (emitter->output == emitter_output_json) {
384 assert(emitter->nesting_depth > 0);
385 emitter_nest_dec(emitter);
386 emitter_printf(emitter, "\n");
387 emitter_indent(emitter);
388 emitter_printf(emitter, "]");
393 emitter_json_arr_obj_begin(emitter_t *emitter) {
394 if (emitter->output == emitter_output_json) {
395 emitter_json_key_prefix(emitter);
396 emitter_printf(emitter, "{");
397 emitter_nest_inc(emitter);
402 emitter_json_arr_obj_end(emitter_t *emitter) {
403 if (emitter->output == emitter_output_json) {
404 assert(emitter->nesting_depth > 0);
405 emitter_nest_dec(emitter);
406 emitter_printf(emitter, "\n");
407 emitter_indent(emitter);
408 emitter_printf(emitter, "}");
413 emitter_json_arr_value(emitter_t *emitter, emitter_type_t value_type,
415 if (emitter->output == emitter_output_json) {
416 emitter_json_key_prefix(emitter);
417 emitter_print_value(emitter, emitter_justify_none, -1,
423 emitter_table_row(emitter_t *emitter, emitter_row_t *row) {
424 if (emitter->output != emitter_output_table) {
428 ql_foreach(col, &row->cols, link) {
429 emitter_print_value(emitter, col->justify, col->width,
430 col->type, (const void *)&col->bool_val);
432 emitter_table_printf(emitter, "\n");
435 #endif /* JEMALLOC_INTERNAL_EMITTER_H */