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