[m-rev.] for review: speed up string to int and string to uint conversion

Julien Fischer jfischer at opturion.com
Sun Aug 9 23:46:23 AEST 2026


On Sun, 9 Aug 2026 at 20:08, Zoltan Somogyi <zoltan.somogyi at runbox.com> wrote:
>
> On Sun, 9 Aug 2026 13:58:31 +1000, Julien Fischer <jfischer at opturion.com> wrote:
>
>
> > +do_base_string_to_int(Base, String, Int) :-
> > +    string.index(String, 0, Char),
> > +    End = string.count_code_units(String),
> > +    ( if
> > +        ( Char = ('-'), Sign0 = negative
> > +        ; Char = ('+'), Sign0 = positive
> > +        )
> > +    then
> > +        Sign = Sign0,
> > +        % Start at the first digit, which *should* be just after the sign.
> > +        End > 1,
> > +        Start = 1
> > +    else
> > +        Sign = positive,
> > +        Start = 0
> > +    ),
> > +    % The divisions below are all safe since our callers set Base
> > +    % to be in 2..36.
> > +    (
> > +        Sign = positive,
> > +        CutOff = max_int `unchecked_quotient` Base,
> > +        CutLimit = max_int `unchecked_rem` Base,
>
> If you are looking for further speedups, this could be done here.
> Realistically, there are two possible values of max_int, and therefore
> we could do a lookup in one of two 36-element precomputed arrays,
> at least when targeting C. (Arranging access to such an array may be
> slower than two divisions in Java/C#.)

I'll try that at some point. The other thing we can try is to use the
initial length of the input string as a bound on the number of digits
it could possibly contain. For sufficiently small strings we could
have a version that omits the overflow check entirely.

...

> > +    % We must detect the overflow *before* it happens. Computing
> > +    % (Base * !.Int) + M and then testing the result does not work,
>
> ... or !.Int.

I'm not sure what you mean by that.

...

> I don't think CutOff and CutLimit are good names for these roles,
> because in a sense they are BOTH limits.
>
> A good name for CutOff would tell readers that this is the maximum
> that !.Int can be before the addition of a digit, and the CutLimit
> is the max value of that digit *if* !.Int = CutOff. However, right now
> I also cannot think of any *short* names that do that. Maybe
> something like MaxSoFar/MaxBeforeNextDigit and MaxNextDigit?

MaxIntSoFar and MaxIntLastDigit?  (suitably adjusted for the negative case)

...

> > +    % The overflow check here is the one described in the comment on
> > +    % do_base_string_to_positive_int_loop above.
> > +    %
> > +:- pred do_base_string_to_uint_loop(uint::in, int::in, uint::in, uint::in,
> > +    string::in, int::in, int::in, uint::in, uint::out) is semidet.
> > +
> > +do_base_string_to_uint_loop(UBase, Base, CutOff, CutLimit, String,
> > +        I, End, !UInt) :-
> > +    ( if I < End then
> > +        unsafe_index_next(String, I, J, Char),
> > +        char.unsafe_base_digit_to_int(Base, Char, M),
> > +        MU = uint.cast_from_int(M),
>
> I don't think this cast is a builtin. You can eliminate its runtime cost
> by adding a uint version of unsafe_base_digit_to_int. Since bases are
> inherently positive, arguably *that* should be the main version anyway.

I will look into that in a separate change.

I have followed your other review comments.

Julien.


More information about the reviews mailing list