Skip to content

Commit d237bbe

Browse files
Add builtin support for string_of_int
1 parent 49c753c commit d237bbe

File tree

3 files changed

+127
-2
lines changed

3 files changed

+127
-2
lines changed

src/solvers/refinement/string_builtin_function.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,87 @@ optionalt<exprt> string_insertion_builtin_functiont::eval(
225225
return make_string(result_value, type);
226226
}
227227

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

src/solvers/refinement/string_builtin_function.h

Lines changed: 42 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,42 @@ 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+
radix = from_integer(10, arg.type());
299+
};
300+
301+
optionalt<exprt>
302+
eval(const std::function<exprt(const exprt &)> &get_value) const override;
303+
304+
std::string name() const override
305+
{
306+
return "string_of_int";
307+
}
308+
309+
exprt add_constraints(string_constraint_generatort &generator) const override
310+
{
311+
return
312+
generator.add_axioms_for_string_of_int_with_radix(result, arg, radix);
313+
}
314+
315+
exprt length_constraint() const override;
316+
317+
private:
318+
exprt radix;
319+
};
320+
281321
/// String test
282322
class string_test_builtin_functiont : public string_builtin_functiont
283323
{

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)