% mmc --loop-invariants str_loopinv.m
%
% Uncaught Mercury exception:
% Software Error: map.lookup: key not found
%         Key Type: term.var(parse_tree.prog_data.prog_var_type)
%         Key Value: var(27)
%         Value Type: ll_backend.var_locn.var_state

%-----------------------------------------------------------------------------%

:- module str_loopinv.
:- interface.
:- import_module io.

:- pred float_to_string(float::in, string::uo) is det.

:- pred main(io::di, io::uo) is det.


%-----------------------------------------------------------------------------%

:- implementation.

:- import_module int.
:- import_module list.
:- use_module string.

%-----------------------------------------------------------------------------%

main(!IO).

float_to_string(Float, unsafe_promise_unique(String)) :-
    % XXX The unsafe_promise_unique is needed because in
    % string.float_to_string_2 the call to string.to_float doesn't
    % have a (ui, out) mode hence the output string cannot be unique.
    String = float_to_string_2(min_precision, Float).

:- func float_to_string_2(int, float) = (string) is det.

float_to_string_2(Prec, Float) = String :-
    string.format("%#." ++ string.int_to_string(Prec) ++ "g",
        [string.f(Float)], Tmp),
    ( Prec = max_precision ->
        String = Tmp
    ;
        ( string.to_float(Tmp, Float) ->
            String = Tmp
        ;
            String = float_to_string_2(Prec + 1, Float)
        )
    ).

:- func string ++ string = string.

A ++ B = C :-
    append(A, B, C).

:- pred append(string, string, string).
:- mode append(in, in, in) is semidet.  % implied
:- mode append(in, in, uo) is det.

:- pragma promise_equivalent_clauses(append/3).

append(S1::in, S2::in, S3::in) :-
    append_iii(S1, S2, S3).
append(S1::in, S2::in, S3::uo) :-
    append_iio(S1, S2, S3).

:- pred append_iii(string::in, string::in, string::in) is semidet.

:- pragma foreign_proc("C",
    append_iii(S1::in, S2::in, S3::in),
    [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
        does_not_affect_liveness],
"{
    size_t len_1 = strlen(S1);
    SUCCESS_INDICATOR = (
        strncmp(S1, S3, len_1) == 0 &&
        strcmp(S2, S3 + len_1) == 0
    );
}").

:- pred append_iio(string::in, string::in, string::uo) is det.

:- pragma foreign_proc("C",
    append_iio(S1::in, S2::in, S3::uo),
    [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
        does_not_affect_liveness],
"{
    size_t len_1, len_2;
    len_1 = strlen(S1);
    len_2 = strlen(S2);
    MR_allocate_aligned_string_msg(S3, len_1 + len_2, MR_PROC_LABEL);
    strcpy(S3, S1);
    strcpy(S3 + len_1, S2);
}").

:- func min_precision = int.

min_precision = 15.

:- func max_precision = int.

max_precision = min_precision + 2.

%-----------------------------------------------------------------------------%
% vi:ft=mercury:ts=8:sts=4:sw=4:et
