xref: /netbsd-src/external/bsd/jemalloc.old/include/jemalloc/internal/emitter.h (revision 8e33eff89e26cf71871ead62f0d5063e1313c33a)
1*8e33eff8Schristos #ifndef JEMALLOC_INTERNAL_EMITTER_H
2*8e33eff8Schristos #define JEMALLOC_INTERNAL_EMITTER_H
3*8e33eff8Schristos 
4*8e33eff8Schristos #include "jemalloc/internal/ql.h"
5*8e33eff8Schristos 
6*8e33eff8Schristos typedef enum emitter_output_e emitter_output_t;
7*8e33eff8Schristos enum emitter_output_e {
8*8e33eff8Schristos 	emitter_output_json,
9*8e33eff8Schristos 	emitter_output_table
10*8e33eff8Schristos };
11*8e33eff8Schristos 
12*8e33eff8Schristos typedef enum emitter_justify_e emitter_justify_t;
13*8e33eff8Schristos enum emitter_justify_e {
14*8e33eff8Schristos 	emitter_justify_left,
15*8e33eff8Schristos 	emitter_justify_right,
16*8e33eff8Schristos 	/* Not for users; just to pass to internal functions. */
17*8e33eff8Schristos 	emitter_justify_none
18*8e33eff8Schristos };
19*8e33eff8Schristos 
20*8e33eff8Schristos typedef enum emitter_type_e emitter_type_t;
21*8e33eff8Schristos enum emitter_type_e {
22*8e33eff8Schristos 	emitter_type_bool,
23*8e33eff8Schristos 	emitter_type_int,
24*8e33eff8Schristos 	emitter_type_unsigned,
25*8e33eff8Schristos 	emitter_type_uint32,
26*8e33eff8Schristos 	emitter_type_uint64,
27*8e33eff8Schristos 	emitter_type_size,
28*8e33eff8Schristos 	emitter_type_ssize,
29*8e33eff8Schristos 	emitter_type_string,
30*8e33eff8Schristos 	/*
31*8e33eff8Schristos 	 * A title is a column title in a table; it's just a string, but it's
32*8e33eff8Schristos 	 * not quoted.
33*8e33eff8Schristos 	 */
34*8e33eff8Schristos 	emitter_type_title,
35*8e33eff8Schristos };
36*8e33eff8Schristos 
37*8e33eff8Schristos typedef struct emitter_col_s emitter_col_t;
38*8e33eff8Schristos struct emitter_col_s {
39*8e33eff8Schristos 	/* Filled in by the user. */
40*8e33eff8Schristos 	emitter_justify_t justify;
41*8e33eff8Schristos 	int width;
42*8e33eff8Schristos 	emitter_type_t type;
43*8e33eff8Schristos 	union {
44*8e33eff8Schristos 		bool bool_val;
45*8e33eff8Schristos 		int int_val;
46*8e33eff8Schristos 		unsigned unsigned_val;
47*8e33eff8Schristos 		uint32_t uint32_val;
48*8e33eff8Schristos 		uint64_t uint64_val;
49*8e33eff8Schristos 		size_t size_val;
50*8e33eff8Schristos 		ssize_t ssize_val;
51*8e33eff8Schristos 		const char *str_val;
52*8e33eff8Schristos 	};
53*8e33eff8Schristos 
54*8e33eff8Schristos 	/* Filled in by initialization. */
55*8e33eff8Schristos 	ql_elm(emitter_col_t) link;
56*8e33eff8Schristos };
57*8e33eff8Schristos 
58*8e33eff8Schristos typedef struct emitter_row_s emitter_row_t;
59*8e33eff8Schristos struct emitter_row_s {
60*8e33eff8Schristos 	ql_head(emitter_col_t) cols;
61*8e33eff8Schristos };
62*8e33eff8Schristos 
63*8e33eff8Schristos static inline void
64*8e33eff8Schristos emitter_row_init(emitter_row_t *row) {
65*8e33eff8Schristos 	ql_new(&row->cols);
66*8e33eff8Schristos }
67*8e33eff8Schristos 
68*8e33eff8Schristos static inline void
69*8e33eff8Schristos emitter_col_init(emitter_col_t *col, emitter_row_t *row) {
70*8e33eff8Schristos 	ql_elm_new(col, link);
71*8e33eff8Schristos 	ql_tail_insert(&row->cols, col, link);
72*8e33eff8Schristos }
73*8e33eff8Schristos 
74*8e33eff8Schristos typedef struct emitter_s emitter_t;
75*8e33eff8Schristos struct emitter_s {
76*8e33eff8Schristos 	emitter_output_t output;
77*8e33eff8Schristos 	/* The output information. */
78*8e33eff8Schristos 	void (*write_cb)(void *, const char *);
79*8e33eff8Schristos 	void *cbopaque;
80*8e33eff8Schristos 	int nesting_depth;
81*8e33eff8Schristos 	/* True if we've already emitted a value at the given depth. */
82*8e33eff8Schristos 	bool item_at_depth;
83*8e33eff8Schristos };
84*8e33eff8Schristos 
85*8e33eff8Schristos static inline void
86*8e33eff8Schristos emitter_init(emitter_t *emitter, emitter_output_t emitter_output,
87*8e33eff8Schristos     void (*write_cb)(void *, const char *), void *cbopaque) {
88*8e33eff8Schristos 	emitter->output = emitter_output;
89*8e33eff8Schristos 	emitter->write_cb = write_cb;
90*8e33eff8Schristos 	emitter->cbopaque = cbopaque;
91*8e33eff8Schristos 	emitter->item_at_depth = false;
92*8e33eff8Schristos 	emitter->nesting_depth = 0;
93*8e33eff8Schristos }
94*8e33eff8Schristos 
95*8e33eff8Schristos /* Internal convenience function.  Write to the emitter the given string. */
96*8e33eff8Schristos JEMALLOC_FORMAT_PRINTF(2, 3)
97*8e33eff8Schristos static inline void
98*8e33eff8Schristos emitter_printf(emitter_t *emitter, const char *format, ...) {
99*8e33eff8Schristos 	va_list ap;
100*8e33eff8Schristos 
101*8e33eff8Schristos 	va_start(ap, format);
102*8e33eff8Schristos 	malloc_vcprintf(emitter->write_cb, emitter->cbopaque, format, ap);
103*8e33eff8Schristos 	va_end(ap);
104*8e33eff8Schristos }
105*8e33eff8Schristos 
106*8e33eff8Schristos /* Write to the emitter the given string, but only in table mode. */
107*8e33eff8Schristos JEMALLOC_FORMAT_PRINTF(2, 3)
108*8e33eff8Schristos static inline void
109*8e33eff8Schristos emitter_table_printf(emitter_t *emitter, const char *format, ...) {
110*8e33eff8Schristos 	if (emitter->output == emitter_output_table) {
111*8e33eff8Schristos 		va_list ap;
112*8e33eff8Schristos 		va_start(ap, format);
113*8e33eff8Schristos 		malloc_vcprintf(emitter->write_cb, emitter->cbopaque, format, ap);
114*8e33eff8Schristos 		va_end(ap);
115*8e33eff8Schristos 	}
116*8e33eff8Schristos }
117*8e33eff8Schristos 
118*8e33eff8Schristos static inline const char * __attribute__((__format_arg__(3)))
119*8e33eff8Schristos emitter_gen_fmt(char *out_fmt, size_t out_size, const char *fmt_specifier,
120*8e33eff8Schristos     emitter_justify_t justify, int width) {
121*8e33eff8Schristos 	size_t written;
122*8e33eff8Schristos 	fmt_specifier++;
123*8e33eff8Schristos 	if (justify == emitter_justify_none) {
124*8e33eff8Schristos 		written = malloc_snprintf(out_fmt, out_size,
125*8e33eff8Schristos 		    "%%%s", fmt_specifier);
126*8e33eff8Schristos 	} else if (justify == emitter_justify_left) {
127*8e33eff8Schristos 		written = malloc_snprintf(out_fmt, out_size,
128*8e33eff8Schristos 		    "%%-%d%s", width, fmt_specifier);
129*8e33eff8Schristos 	} else {
130*8e33eff8Schristos 		written = malloc_snprintf(out_fmt, out_size,
131*8e33eff8Schristos 		    "%%%d%s", width, fmt_specifier);
132*8e33eff8Schristos 	}
133*8e33eff8Schristos 	/* Only happens in case of bad format string, which *we* choose. */
134*8e33eff8Schristos 	assert(written <  out_size);
135*8e33eff8Schristos 	return out_fmt;
136*8e33eff8Schristos }
137*8e33eff8Schristos 
138*8e33eff8Schristos /*
139*8e33eff8Schristos  * Internal.  Emit the given value type in the relevant encoding (so that the
140*8e33eff8Schristos  * bool true gets mapped to json "true", but the string "true" gets mapped to
141*8e33eff8Schristos  * json "\"true\"", for instance.
142*8e33eff8Schristos  *
143*8e33eff8Schristos  * Width is ignored if justify is emitter_justify_none.
144*8e33eff8Schristos  */
145*8e33eff8Schristos static inline void
146*8e33eff8Schristos emitter_print_value(emitter_t *emitter, emitter_justify_t justify, int width,
147*8e33eff8Schristos     emitter_type_t value_type, const void *value) {
148*8e33eff8Schristos 	size_t str_written;
149*8e33eff8Schristos #define BUF_SIZE 256
150*8e33eff8Schristos #define FMT_SIZE 10
151*8e33eff8Schristos 	/*
152*8e33eff8Schristos 	 * We dynamically generate a format string to emit, to let us use the
153*8e33eff8Schristos 	 * snprintf machinery.  This is kinda hacky, but gets the job done
154*8e33eff8Schristos 	 * quickly without having to think about the various snprintf edge
155*8e33eff8Schristos 	 * cases.
156*8e33eff8Schristos 	 */
157*8e33eff8Schristos 	char fmt[FMT_SIZE];
158*8e33eff8Schristos 	char buf[BUF_SIZE];
159*8e33eff8Schristos 
160*8e33eff8Schristos #define EMIT_SIMPLE(type, format)					\
161*8e33eff8Schristos 	emitter_printf(emitter,						\
162*8e33eff8Schristos 	    emitter_gen_fmt(fmt, FMT_SIZE, format, justify, width),	\
163*8e33eff8Schristos 	    *(const type *)value);
164*8e33eff8Schristos 
165*8e33eff8Schristos 	switch (value_type) {
166*8e33eff8Schristos 	case emitter_type_bool:
167*8e33eff8Schristos 		emitter_printf(emitter,
168*8e33eff8Schristos 		    emitter_gen_fmt(fmt, FMT_SIZE, "%s", justify, width),
169*8e33eff8Schristos 		    *(const bool *)value ?  "true" : "false");
170*8e33eff8Schristos 		break;
171*8e33eff8Schristos 	case emitter_type_int:
172*8e33eff8Schristos 		EMIT_SIMPLE(int, "%d")
173*8e33eff8Schristos 		break;
174*8e33eff8Schristos 	case emitter_type_unsigned:
175*8e33eff8Schristos 		EMIT_SIMPLE(unsigned, "%u")
176*8e33eff8Schristos 		break;
177*8e33eff8Schristos 	case emitter_type_ssize:
178*8e33eff8Schristos 		EMIT_SIMPLE(ssize_t, "%zd")
179*8e33eff8Schristos 		break;
180*8e33eff8Schristos 	case emitter_type_size:
181*8e33eff8Schristos 		EMIT_SIMPLE(size_t, "%zu")
182*8e33eff8Schristos 		break;
183*8e33eff8Schristos 	case emitter_type_string:
184*8e33eff8Schristos 		str_written = malloc_snprintf(buf, BUF_SIZE, "\"%s\"",
185*8e33eff8Schristos 		    *(const char *const *)value);
186*8e33eff8Schristos 		/*
187*8e33eff8Schristos 		 * We control the strings we output; we shouldn't get anything
188*8e33eff8Schristos 		 * anywhere near the fmt size.
189*8e33eff8Schristos 		 */
190*8e33eff8Schristos 		assert(str_written < BUF_SIZE);
191*8e33eff8Schristos 		emitter_printf(emitter,
192*8e33eff8Schristos 		    emitter_gen_fmt(fmt, FMT_SIZE, "%s", justify, width), buf);
193*8e33eff8Schristos 		break;
194*8e33eff8Schristos 	case emitter_type_uint32:
195*8e33eff8Schristos 		EMIT_SIMPLE(uint32_t, "%" FMTu32)
196*8e33eff8Schristos 		break;
197*8e33eff8Schristos 	case emitter_type_uint64:
198*8e33eff8Schristos 		EMIT_SIMPLE(uint64_t, "%" FMTu64)
199*8e33eff8Schristos 		break;
200*8e33eff8Schristos 	case emitter_type_title:
201*8e33eff8Schristos 		EMIT_SIMPLE(char *const, "%s");
202*8e33eff8Schristos 		break;
203*8e33eff8Schristos 	default:
204*8e33eff8Schristos 		unreachable();
205*8e33eff8Schristos 	}
206*8e33eff8Schristos #undef BUF_SIZE
207*8e33eff8Schristos #undef FMT_SIZE
208*8e33eff8Schristos }
209*8e33eff8Schristos 
210*8e33eff8Schristos 
211*8e33eff8Schristos /* Internal functions.  In json mode, tracks nesting state. */
212*8e33eff8Schristos static inline void
213*8e33eff8Schristos emitter_nest_inc(emitter_t *emitter) {
214*8e33eff8Schristos 	emitter->nesting_depth++;
215*8e33eff8Schristos 	emitter->item_at_depth = false;
216*8e33eff8Schristos }
217*8e33eff8Schristos 
218*8e33eff8Schristos static inline void
219*8e33eff8Schristos emitter_nest_dec(emitter_t *emitter) {
220*8e33eff8Schristos 	emitter->nesting_depth--;
221*8e33eff8Schristos 	emitter->item_at_depth = true;
222*8e33eff8Schristos }
223*8e33eff8Schristos 
224*8e33eff8Schristos static inline void
225*8e33eff8Schristos emitter_indent(emitter_t *emitter) {
226*8e33eff8Schristos 	int amount = emitter->nesting_depth;
227*8e33eff8Schristos 	const char *indent_str;
228*8e33eff8Schristos 	if (emitter->output == emitter_output_json) {
229*8e33eff8Schristos 		indent_str = "\t";
230*8e33eff8Schristos 	} else {
231*8e33eff8Schristos 		amount *= 2;
232*8e33eff8Schristos 		indent_str = " ";
233*8e33eff8Schristos 	}
234*8e33eff8Schristos 	for (int i = 0; i < amount; i++) {
235*8e33eff8Schristos 		emitter_printf(emitter, "%s", indent_str);
236*8e33eff8Schristos 	}
237*8e33eff8Schristos }
238*8e33eff8Schristos 
239*8e33eff8Schristos static inline void
240*8e33eff8Schristos emitter_json_key_prefix(emitter_t *emitter) {
241*8e33eff8Schristos 	emitter_printf(emitter, "%s\n", emitter->item_at_depth ? "," : "");
242*8e33eff8Schristos 	emitter_indent(emitter);
243*8e33eff8Schristos }
244*8e33eff8Schristos 
245*8e33eff8Schristos static inline void
246*8e33eff8Schristos emitter_begin(emitter_t *emitter) {
247*8e33eff8Schristos 	if (emitter->output == emitter_output_json) {
248*8e33eff8Schristos 		assert(emitter->nesting_depth == 0);
249*8e33eff8Schristos 		emitter_printf(emitter, "{");
250*8e33eff8Schristos 		emitter_nest_inc(emitter);
251*8e33eff8Schristos 	} else {
252*8e33eff8Schristos 		// tabular init
253*8e33eff8Schristos 		emitter_printf(emitter, "%s", "");
254*8e33eff8Schristos 	}
255*8e33eff8Schristos }
256*8e33eff8Schristos 
257*8e33eff8Schristos static inline void
258*8e33eff8Schristos emitter_end(emitter_t *emitter) {
259*8e33eff8Schristos 	if (emitter->output == emitter_output_json) {
260*8e33eff8Schristos 		assert(emitter->nesting_depth == 1);
261*8e33eff8Schristos 		emitter_nest_dec(emitter);
262*8e33eff8Schristos 		emitter_printf(emitter, "\n}\n");
263*8e33eff8Schristos 	}
264*8e33eff8Schristos }
265*8e33eff8Schristos 
266*8e33eff8Schristos /*
267*8e33eff8Schristos  * Note emits a different kv pair as well, but only in table mode.  Omits the
268*8e33eff8Schristos  * note if table_note_key is NULL.
269*8e33eff8Schristos  */
270*8e33eff8Schristos static inline void
271*8e33eff8Schristos emitter_kv_note(emitter_t *emitter, const char *json_key, const char *table_key,
272*8e33eff8Schristos     emitter_type_t value_type, const void *value,
273*8e33eff8Schristos     const char *table_note_key, emitter_type_t table_note_value_type,
274*8e33eff8Schristos     const void *table_note_value) {
275*8e33eff8Schristos 	if (emitter->output == emitter_output_json) {
276*8e33eff8Schristos 		assert(emitter->nesting_depth > 0);
277*8e33eff8Schristos 		emitter_json_key_prefix(emitter);
278*8e33eff8Schristos 		emitter_printf(emitter, "\"%s\": ", json_key);
279*8e33eff8Schristos 		emitter_print_value(emitter, emitter_justify_none, -1,
280*8e33eff8Schristos 		    value_type, value);
281*8e33eff8Schristos 	} else {
282*8e33eff8Schristos 		emitter_indent(emitter);
283*8e33eff8Schristos 		emitter_printf(emitter, "%s: ", table_key);
284*8e33eff8Schristos 		emitter_print_value(emitter, emitter_justify_none, -1,
285*8e33eff8Schristos 		    value_type, value);
286*8e33eff8Schristos 		if (table_note_key != NULL) {
287*8e33eff8Schristos 			emitter_printf(emitter, " (%s: ", table_note_key);
288*8e33eff8Schristos 			emitter_print_value(emitter, emitter_justify_none, -1,
289*8e33eff8Schristos 			    table_note_value_type, table_note_value);
290*8e33eff8Schristos 			emitter_printf(emitter, ")");
291*8e33eff8Schristos 		}
292*8e33eff8Schristos 		emitter_printf(emitter, "\n");
293*8e33eff8Schristos 	}
294*8e33eff8Schristos 	emitter->item_at_depth = true;
295*8e33eff8Schristos }
296*8e33eff8Schristos 
297*8e33eff8Schristos static inline void
298*8e33eff8Schristos emitter_kv(emitter_t *emitter, const char *json_key, const char *table_key,
299*8e33eff8Schristos     emitter_type_t value_type, const void *value) {
300*8e33eff8Schristos 	emitter_kv_note(emitter, json_key, table_key, value_type, value, NULL,
301*8e33eff8Schristos 	    emitter_type_bool, NULL);
302*8e33eff8Schristos }
303*8e33eff8Schristos 
304*8e33eff8Schristos static inline void
305*8e33eff8Schristos emitter_json_kv(emitter_t *emitter, const char *json_key,
306*8e33eff8Schristos     emitter_type_t value_type, const void *value) {
307*8e33eff8Schristos 	if (emitter->output == emitter_output_json) {
308*8e33eff8Schristos 		emitter_kv(emitter, json_key, NULL, value_type, value);
309*8e33eff8Schristos 	}
310*8e33eff8Schristos }
311*8e33eff8Schristos 
312*8e33eff8Schristos static inline void
313*8e33eff8Schristos emitter_table_kv(emitter_t *emitter, const char *table_key,
314*8e33eff8Schristos     emitter_type_t value_type, const void *value) {
315*8e33eff8Schristos 	if (emitter->output == emitter_output_table) {
316*8e33eff8Schristos 		emitter_kv(emitter, NULL, table_key, value_type, value);
317*8e33eff8Schristos 	}
318*8e33eff8Schristos }
319*8e33eff8Schristos 
320*8e33eff8Schristos static inline void
321*8e33eff8Schristos emitter_dict_begin(emitter_t *emitter, const char *json_key,
322*8e33eff8Schristos     const char *table_header) {
323*8e33eff8Schristos 	if (emitter->output == emitter_output_json) {
324*8e33eff8Schristos 		emitter_json_key_prefix(emitter);
325*8e33eff8Schristos 		emitter_printf(emitter, "\"%s\": {", json_key);
326*8e33eff8Schristos 		emitter_nest_inc(emitter);
327*8e33eff8Schristos 	} else {
328*8e33eff8Schristos 		emitter_indent(emitter);
329*8e33eff8Schristos 		emitter_printf(emitter, "%s\n", table_header);
330*8e33eff8Schristos 		emitter_nest_inc(emitter);
331*8e33eff8Schristos 	}
332*8e33eff8Schristos }
333*8e33eff8Schristos 
334*8e33eff8Schristos static inline void
335*8e33eff8Schristos emitter_dict_end(emitter_t *emitter) {
336*8e33eff8Schristos 	if (emitter->output == emitter_output_json) {
337*8e33eff8Schristos 		assert(emitter->nesting_depth > 0);
338*8e33eff8Schristos 		emitter_nest_dec(emitter);
339*8e33eff8Schristos 		emitter_printf(emitter, "\n");
340*8e33eff8Schristos 		emitter_indent(emitter);
341*8e33eff8Schristos 		emitter_printf(emitter, "}");
342*8e33eff8Schristos 	} else {
343*8e33eff8Schristos 		emitter_nest_dec(emitter);
344*8e33eff8Schristos 	}
345*8e33eff8Schristos }
346*8e33eff8Schristos 
347*8e33eff8Schristos static inline void
348*8e33eff8Schristos emitter_json_dict_begin(emitter_t *emitter, const char *json_key) {
349*8e33eff8Schristos 	if (emitter->output == emitter_output_json) {
350*8e33eff8Schristos 		emitter_dict_begin(emitter, json_key, NULL);
351*8e33eff8Schristos 	}
352*8e33eff8Schristos }
353*8e33eff8Schristos 
354*8e33eff8Schristos static inline void
355*8e33eff8Schristos emitter_json_dict_end(emitter_t *emitter) {
356*8e33eff8Schristos 	if (emitter->output == emitter_output_json) {
357*8e33eff8Schristos 		emitter_dict_end(emitter);
358*8e33eff8Schristos 	}
359*8e33eff8Schristos }
360*8e33eff8Schristos 
361*8e33eff8Schristos static inline void
362*8e33eff8Schristos emitter_table_dict_begin(emitter_t *emitter, const char *table_key) {
363*8e33eff8Schristos 	if (emitter->output == emitter_output_table) {
364*8e33eff8Schristos 		emitter_dict_begin(emitter, NULL, table_key);
365*8e33eff8Schristos 	}
366*8e33eff8Schristos }
367*8e33eff8Schristos 
368*8e33eff8Schristos static inline void
369*8e33eff8Schristos emitter_table_dict_end(emitter_t *emitter) {
370*8e33eff8Schristos 	if (emitter->output == emitter_output_table) {
371*8e33eff8Schristos 		emitter_dict_end(emitter);
372*8e33eff8Schristos 	}
373*8e33eff8Schristos }
374*8e33eff8Schristos 
375*8e33eff8Schristos static inline void
376*8e33eff8Schristos emitter_json_arr_begin(emitter_t *emitter, const char *json_key) {
377*8e33eff8Schristos 	if (emitter->output == emitter_output_json) {
378*8e33eff8Schristos 		emitter_json_key_prefix(emitter);
379*8e33eff8Schristos 		emitter_printf(emitter, "\"%s\": [", json_key);
380*8e33eff8Schristos 		emitter_nest_inc(emitter);
381*8e33eff8Schristos 	}
382*8e33eff8Schristos }
383*8e33eff8Schristos 
384*8e33eff8Schristos static inline void
385*8e33eff8Schristos emitter_json_arr_end(emitter_t *emitter) {
386*8e33eff8Schristos 	if (emitter->output == emitter_output_json) {
387*8e33eff8Schristos 		assert(emitter->nesting_depth > 0);
388*8e33eff8Schristos 		emitter_nest_dec(emitter);
389*8e33eff8Schristos 		emitter_printf(emitter, "\n");
390*8e33eff8Schristos 		emitter_indent(emitter);
391*8e33eff8Schristos 		emitter_printf(emitter, "]");
392*8e33eff8Schristos 	}
393*8e33eff8Schristos }
394*8e33eff8Schristos 
395*8e33eff8Schristos static inline void
396*8e33eff8Schristos emitter_json_arr_obj_begin(emitter_t *emitter) {
397*8e33eff8Schristos 	if (emitter->output == emitter_output_json) {
398*8e33eff8Schristos 		emitter_json_key_prefix(emitter);
399*8e33eff8Schristos 		emitter_printf(emitter, "{");
400*8e33eff8Schristos 		emitter_nest_inc(emitter);
401*8e33eff8Schristos 	}
402*8e33eff8Schristos }
403*8e33eff8Schristos 
404*8e33eff8Schristos static inline void
405*8e33eff8Schristos emitter_json_arr_obj_end(emitter_t *emitter) {
406*8e33eff8Schristos 	if (emitter->output == emitter_output_json) {
407*8e33eff8Schristos 		assert(emitter->nesting_depth > 0);
408*8e33eff8Schristos 		emitter_nest_dec(emitter);
409*8e33eff8Schristos 		emitter_printf(emitter, "\n");
410*8e33eff8Schristos 		emitter_indent(emitter);
411*8e33eff8Schristos 		emitter_printf(emitter, "}");
412*8e33eff8Schristos 	}
413*8e33eff8Schristos }
414*8e33eff8Schristos 
415*8e33eff8Schristos static inline void
416*8e33eff8Schristos emitter_json_arr_value(emitter_t *emitter, emitter_type_t value_type,
417*8e33eff8Schristos     const void *value) {
418*8e33eff8Schristos 	if (emitter->output == emitter_output_json) {
419*8e33eff8Schristos 		emitter_json_key_prefix(emitter);
420*8e33eff8Schristos 		emitter_print_value(emitter, emitter_justify_none, -1,
421*8e33eff8Schristos 		    value_type, value);
422*8e33eff8Schristos 	}
423*8e33eff8Schristos }
424*8e33eff8Schristos 
425*8e33eff8Schristos static inline void
426*8e33eff8Schristos emitter_table_row(emitter_t *emitter, emitter_row_t *row) {
427*8e33eff8Schristos 	if (emitter->output != emitter_output_table) {
428*8e33eff8Schristos 		return;
429*8e33eff8Schristos 	}
430*8e33eff8Schristos 	emitter_col_t *col;
431*8e33eff8Schristos 	ql_foreach(col, &row->cols, link) {
432*8e33eff8Schristos 		emitter_print_value(emitter, col->justify, col->width,
433*8e33eff8Schristos 		    col->type, (const void *)&col->bool_val);
434*8e33eff8Schristos 	}
435*8e33eff8Schristos 	emitter_table_printf(emitter, "\n");
436*8e33eff8Schristos }
437*8e33eff8Schristos 
438*8e33eff8Schristos #endif /* JEMALLOC_INTERNAL_EMITTER_H */
439