[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