Skip to content

Commit 3724dea

Browse files
committed
use a hash table in the expression formatter
This replaces the linear-time if-then-else construct by a logarithmic hash table. The hash table could be extended at runtime.
1 parent 46de6f6 commit 3724dea

File tree

1 file changed

+142
-54
lines changed

1 file changed

+142
-54
lines changed

src/util/format_expr.cpp

Lines changed: 142 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -217,81 +217,145 @@ std::ostream &fallback_format_rec(std::ostream &os, const exprt &expr)
217217
return os;
218218
}
219219

220-
// The below generates a string in a generic syntax
220+
class format_expr_configt
221+
{
222+
public:
223+
format_expr_configt()
224+
{
225+
setup();
226+
}
227+
228+
using formattert =
229+
std::function<std::ostream &(std::ostream &, const exprt &)>;
230+
using expr_mapt = std::unordered_map<irep_idt, formattert>;
231+
232+
expr_mapt expr_map;
233+
234+
/// find the formatter for a given expression
235+
const formattert &find_formatter(const exprt &);
236+
237+
private:
238+
/// setup the expressions we can format
239+
void setup();
240+
241+
formattert fallback;
242+
};
243+
244+
// The below generates textual output in a generic syntax
221245
// that is inspired by C/C++/Java, and is meant for debugging
222246
// purposes.
223-
std::ostream &format_rec(std::ostream &os, const exprt &expr)
247+
void format_expr_configt::setup()
224248
{
225-
const auto &id = expr.id();
226-
227-
if(
228-
id == ID_plus || id == ID_mult || id == ID_and || id == ID_or ||
229-
id == ID_xor)
230-
{
249+
auto multi_ary_expr =
250+
[](std::ostream &os, const exprt &expr) -> std::ostream & {
231251
return format_rec(os, to_multi_ary_expr(expr));
232-
}
233-
else if(
234-
id == ID_lt || id == ID_gt || id == ID_ge || id == ID_le || id == ID_div ||
235-
id == ID_minus || id == ID_implies || id == ID_equal || id == ID_notequal)
236-
{
252+
};
253+
254+
expr_map[ID_plus] = multi_ary_expr;
255+
expr_map[ID_mult] = multi_ary_expr;
256+
expr_map[ID_and] = multi_ary_expr;
257+
expr_map[ID_or] = multi_ary_expr;
258+
expr_map[ID_xor] = multi_ary_expr;
259+
260+
auto binary_expr = [](std::ostream &os, const exprt &expr) -> std::ostream & {
237261
return format_rec(os, to_binary_expr(expr));
238-
}
239-
else if(id == ID_not || id == ID_unary_minus)
262+
};
263+
264+
expr_map[ID_lt] = binary_expr;
265+
expr_map[ID_gt] = binary_expr;
266+
expr_map[ID_ge] = binary_expr;
267+
expr_map[ID_le] = binary_expr;
268+
expr_map[ID_div] = binary_expr;
269+
expr_map[ID_minus] = binary_expr;
270+
expr_map[ID_implies] = binary_expr;
271+
expr_map[ID_equal] = binary_expr;
272+
expr_map[ID_notequal] = binary_expr;
273+
274+
auto unary_expr = [](std::ostream &os, const exprt &expr) -> std::ostream & {
240275
return format_rec(os, to_unary_expr(expr));
241-
else if(id == ID_constant)
276+
};
277+
278+
expr_map[ID_not] = unary_expr;
279+
expr_map[ID_unary_minus] = unary_expr;
280+
281+
expr_map[ID_constant] =
282+
[](std::ostream &os, const exprt &expr) -> std::ostream & {
242283
return format_rec(os, to_constant_expr(expr));
243-
else if(id == ID_typecast)
284+
};
285+
286+
expr_map[ID_typecast] =
287+
[](std::ostream &os, const exprt &expr) -> std::ostream & {
244288
return os << "cast(" << format(to_typecast_expr(expr).op()) << ", "
245289
<< format(expr.type()) << ')';
246-
else if(
247-
id == ID_byte_extract_little_endian || id == ID_byte_extract_big_endian)
248-
{
290+
};
291+
292+
auto byte_extract =
293+
[](std::ostream &os, const exprt &expr) -> std::ostream & {
249294
const auto &byte_extract_expr = to_byte_extract_expr(expr);
250-
return os << id << '(' << format(byte_extract_expr.op()) << ", "
295+
return os << expr.id() << '(' << format(byte_extract_expr.op()) << ", "
251296
<< format(byte_extract_expr.offset()) << ", "
252297
<< format(byte_extract_expr.type()) << ')';
253-
}
254-
else if(id == ID_byte_update_little_endian || id == ID_byte_update_big_endian)
255-
{
298+
};
299+
300+
expr_map[ID_byte_extract_little_endian] = byte_extract;
301+
expr_map[ID_byte_extract_big_endian] = byte_extract;
302+
303+
auto byte_update = [](std::ostream &os, const exprt &expr) -> std::ostream & {
256304
const auto &byte_update_expr = to_byte_update_expr(expr);
257-
return os << id << '(' << format(byte_update_expr.op()) << ", "
305+
return os << expr.id() << '(' << format(byte_update_expr.op()) << ", "
258306
<< format(byte_update_expr.offset()) << ", "
259307
<< format(byte_update_expr.value()) << ", "
260308
<< format(byte_update_expr.type()) << ')';
261-
}
262-
else if(id == ID_member)
309+
};
310+
311+
expr_map[ID_byte_update_little_endian] = byte_update;
312+
expr_map[ID_byte_update_big_endian] = byte_update;
313+
314+
expr_map[ID_member] =
315+
[](std::ostream &os, const exprt &expr) -> std::ostream & {
263316
return os << format(to_member_expr(expr).op()) << '.'
264317
<< to_member_expr(expr).get_component_name();
265-
else if(id == ID_symbol)
318+
};
319+
320+
expr_map[ID_symbol] =
321+
[](std::ostream &os, const exprt &expr) -> std::ostream & {
266322
return os << to_symbol_expr(expr).get_identifier();
267-
else if(id == ID_index)
268-
{
323+
};
324+
325+
expr_map[ID_index] =
326+
[](std::ostream &os, const exprt &expr) -> std::ostream & {
269327
const auto &index_expr = to_index_expr(expr);
270328
return os << format(index_expr.array()) << '[' << format(index_expr.index())
271329
<< ']';
272-
}
273-
else if(id == ID_type)
330+
};
331+
332+
expr_map[ID_type] =
333+
[](std::ostream &os, const exprt &expr) -> std::ostream & {
274334
return format_rec(os, expr.type());
275-
else if(id == ID_forall)
276-
{
335+
};
336+
337+
expr_map[ID_forall] =
338+
[](std::ostream &os, const exprt &expr) -> std::ostream & {
277339
return os << u8"\u2200 " << format(to_quantifier_expr(expr).symbol())
278340
<< " : " << format(to_quantifier_expr(expr).symbol().type())
279341
<< " . " << format(to_quantifier_expr(expr).where());
280-
}
281-
else if(id == ID_exists)
282-
{
342+
};
343+
344+
expr_map[ID_exists] =
345+
[](std::ostream &os, const exprt &expr) -> std::ostream & {
283346
return os << u8"\u2203 " << format(to_quantifier_expr(expr).symbol())
284347
<< " : " << format(to_quantifier_expr(expr).symbol().type())
285348
<< " . " << format(to_quantifier_expr(expr).where());
286-
}
287-
else if(id == ID_let)
288-
{
349+
};
350+
351+
expr_map[ID_let] = [](std::ostream &os, const exprt &expr) -> std::ostream & {
289352
return os << "LET " << format(to_let_expr(expr).symbol()) << " = "
290353
<< format(to_let_expr(expr).value()) << " IN "
291354
<< format(to_let_expr(expr).where());
292-
}
293-
else if(id == ID_lambda)
294-
{
355+
};
356+
357+
expr_map[ID_lambda] =
358+
[](std::ostream &os, const exprt &expr) -> std::ostream & {
295359
const auto &lambda_expr = to_lambda_expr(expr);
296360

297361
os << u8"\u03bb ";
@@ -309,9 +373,9 @@ std::ostream &format_rec(std::ostream &os, const exprt &expr)
309373
}
310374

311375
return os << " . " << format(lambda_expr.where());
312-
}
313-
else if(id == ID_array || id == ID_struct)
314-
{
376+
};
377+
378+
auto compound = [](std::ostream &os, const exprt &expr) -> std::ostream & {
315379
os << "{ ";
316380

317381
bool first = true;
@@ -327,16 +391,20 @@ std::ostream &format_rec(std::ostream &os, const exprt &expr)
327391
}
328392

329393
return os << " }";
330-
}
331-
else if(id == ID_if)
332-
{
394+
};
395+
396+
expr_map[ID_array] = compound;
397+
expr_map[ID_struct] = compound;
398+
399+
expr_map[ID_if] = [](std::ostream &os, const exprt &expr) -> std::ostream & {
333400
const auto &if_expr = to_if_expr(expr);
334401
return os << '(' << format(if_expr.cond()) << " ? "
335402
<< format(if_expr.true_case()) << " : "
336403
<< format(if_expr.false_case()) << ')';
337-
}
338-
else if(id == ID_code)
339-
{
404+
};
405+
406+
expr_map[ID_code] =
407+
[](std::ostream &os, const exprt &expr) -> std::ostream & {
340408
const auto &code = to_code(expr);
341409
const irep_idt &statement = code.get_statement();
342410

@@ -377,7 +445,27 @@ std::ostream &format_rec(std::ostream &os, const exprt &expr)
377445
}
378446
else
379447
return fallback_format_rec(os, expr);
380-
}
381-
else
448+
};
449+
450+
fallback = [](std::ostream &os, const exprt &expr) -> std::ostream & {
382451
return fallback_format_rec(os, expr);
452+
};
453+
}
454+
455+
const format_expr_configt::formattert &
456+
format_expr_configt::find_formatter(const exprt &expr)
457+
{
458+
auto m_it = expr_map.find(expr.id());
459+
if(m_it == expr_map.end())
460+
return fallback;
461+
else
462+
return m_it->second;
463+
}
464+
465+
format_expr_configt format_expr_config;
466+
467+
std::ostream &format_rec(std::ostream &os, const exprt &expr)
468+
{
469+
auto &formatter = format_expr_config.find_formatter(expr);
470+
return formatter(os, expr);
383471
}

0 commit comments

Comments
 (0)