Skip to content

Commit 7414d76

Browse files
Add builtin support for string_of_int
1 parent 0b44c89 commit 7414d76

File tree

3 files changed

+125
-2
lines changed

3 files changed

+125
-2
lines changed

src/solvers/refinement/string_builtin_function.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,84 @@ optionalt<exprt> string_insertion_builtin_functiont::eval(
222222
return make_string(result_value, type);
223223
}
224224

225+
/// Constructor from arguments of a function application.
226+
/// The arguments in `fun_args` should be in order:
227+
/// an integer `result.length`, a character pointer `&result[0]`,
228+
/// an expression `arg` which is to be converted to a string.
229+
/// Other arguments are ignored by this constructor.
230+
string_creation_builtin_functiont::string_creation_builtin_functiont(
231+
const exprt &return_code,
232+
const std::vector<exprt> &fun_args,
233+
array_poolt &array_pool)
234+
: string_builtin_functiont(return_code)
235+
{
236+
PRECONDITION(fun_args.size() >= 3);
237+
result = array_pool.find(fun_args[1], fun_args[0]);
238+
arg = fun_args[2];
239+
}
240+
241+
optionalt<exprt> string_of_int_builtin_functiont::eval(
242+
const std::function<exprt(const exprt &)> &get_value) const
243+
{
244+
const auto arg_value = numeric_cast<mp_integer>(get_value(arg));
245+
if(!arg_value)
246+
return {};
247+
static std::string digits = "0123456789abcdefghijklmnopqrstuvwxyz";
248+
const auto radix_value = numeric_cast<mp_integer>(get_value(radix));
249+
if(!radix_value || *radix_value > digits.length())
250+
return {};
251+
252+
mp_integer current_value = *arg_value;
253+
std::vector<mp_integer> right_to_left_characters;
254+
if(current_value < 0)
255+
current_value = -current_value;
256+
if(current_value == 0)
257+
right_to_left_characters.emplace_back('0');
258+
while(current_value > 0)
259+
{
260+
const auto digit_value = (current_value % *radix_value).to_ulong();
261+
right_to_left_characters.emplace_back(digits.at(digit_value));
262+
current_value /= *radix_value;
263+
}
264+
if(*arg_value < 0)
265+
right_to_left_characters.emplace_back('-');
266+
267+
const auto length = right_to_left_characters.size();
268+
const auto length_expr = from_integer(length, result.length().type());
269+
const array_typet type(result.type().subtype(), length_expr);
270+
return make_string(
271+
right_to_left_characters.rbegin(), right_to_left_characters.rend(), type);
272+
}
273+
274+
exprt string_of_int_builtin_functiont::length_constraint() const
275+
{
276+
const typet &type = result.length().type();
277+
const auto radix_opt = numeric_cast<std::size_t>(radix);
278+
const auto radix_value = radix_opt.has_value() ? radix_opt.value() : 2;
279+
const std::size_t upper_bound =
280+
max_printed_string_length(arg.type(), radix_value);
281+
const exprt negative_arg =
282+
binary_relation_exprt(arg, ID_le, from_integer(0, type));
283+
const exprt absolute_arg =
284+
if_exprt(negative_arg, unary_minus_exprt(arg), arg);
285+
286+
exprt size_expr = from_integer(1, type);
287+
exprt min_int_with_current_size = from_integer(1, radix.type());
288+
for(std::size_t current_size = 2; current_size <= upper_bound + 1;
289+
++current_size)
290+
{
291+
min_int_with_current_size = mult_exprt(radix, min_int_with_current_size);
292+
const exprt at_least_current_size =
293+
binary_relation_exprt(absolute_arg, ID_ge, min_int_with_current_size);
294+
size_expr = if_exprt(
295+
at_least_current_size, from_integer(current_size, type), size_expr);
296+
}
297+
298+
const exprt size_expr_with_sign = if_exprt(
299+
negative_arg, plus_exprt(size_expr, from_integer(1, type)), size_expr);
300+
return equal_exprt(result.length(), size_expr_with_sign);
301+
}
302+
225303
string_builtin_function_with_no_evalt::string_builtin_function_with_no_evalt(
226304
const exprt &return_code,
227305
const function_application_exprt &f,

src/solvers/refinement/string_builtin_function.h

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,12 @@ class string_creation_builtin_functiont : public string_builtin_functiont
264264
{
265265
public:
266266
array_string_exprt result;
267-
std::vector<exprt> args;
268-
exprt return_code;
267+
exprt arg;
268+
269+
string_creation_builtin_functiont(
270+
const exprt &return_code,
271+
const std::vector<exprt> &fun_args,
272+
array_poolt &array_pool);
269273

270274
optionalt<array_string_exprt> string_result() const override
271275
{
@@ -278,6 +282,43 @@ class string_creation_builtin_functiont : public string_builtin_functiont
278282
}
279283
};
280284

285+
/// String creation from integer types
286+
class string_of_int_builtin_functiont : public string_creation_builtin_functiont
287+
{
288+
public:
289+
string_of_int_builtin_functiont(
290+
const exprt &return_code,
291+
const std::vector<exprt> &fun_args,
292+
array_poolt &array_pool)
293+
: string_creation_builtin_functiont(return_code, fun_args, array_pool)
294+
{
295+
PRECONDITION(fun_args.size() <= 4);
296+
if(fun_args.size() == 4)
297+
radix = fun_args[3];
298+
else
299+
radix = from_integer(10, arg.type());
300+
};
301+
302+
optionalt<exprt>
303+
eval(const std::function<exprt(const exprt &)> &get_value) const override;
304+
305+
std::string name() const override
306+
{
307+
return "string_of_int";
308+
}
309+
310+
exprt add_constraints(string_constraint_generatort &generator) const override
311+
{
312+
return generator.add_axioms_for_string_of_int_with_radix(
313+
result, arg, radix);
314+
}
315+
316+
exprt length_constraint() const override;
317+
318+
private:
319+
exprt radix;
320+
};
321+
281322
/// String test
282323
class string_test_builtin_functiont : public string_builtin_functiont
283324
{

src/solvers/refinement/string_refinement_util.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,10 @@ static std::unique_ptr<string_builtin_functiont> to_string_builtin_function(
224224
return util_make_unique<string_concat_char_builtin_functiont>(
225225
return_code, fun_app.arguments(), array_pool);
226226

227+
if(id == ID_cprover_string_of_int_func)
228+
return util_make_unique<string_of_int_builtin_functiont>(
229+
return_code, fun_app.arguments(), array_pool);
230+
227231
return util_make_unique<string_builtin_function_with_no_evalt>(
228232
return_code, fun_app, array_pool);
229233
}

0 commit comments

Comments
 (0)