o3tl::make_unsigned
Luboš Luňák
l.lunak at collabora.com
Thu Jan 30 14:13:25 UTC 2020
On Thursday 30 of January 2020, Stephan Bergmann wrote:
> On 30/01/2020 12:56, Luboš Luňák wrote:
> > This contradicts your original mail, where you stated that what is used
> > is "if (sal_uInt32(e1) < e2) ... // (B)" (i.e. without the <0 check).
> > And
>
> Maybe it is unclear, but my original mail was talking about a "correct"
> comparison
>
> e1 < e2
>
> (i.e., where it is known that e1 >= 0, but where compilers might
> nevertheless emit a signed-vs.-unsigned warning).
Then make_unsigned() covers a smaller problem area than make_signed(), which
covers all cases except for the exceptional totally huge value cases. I.e.
with make_signed() you practically do not need to care what the values in "e1
< e2" are. Why make API that requires caring about the value when there can
be API that makes it practically irrelevant?
> > It doesn't pretend any more than make_unsigned() does. It's just that
> > it's harder to accidentally break its requirements in practice.
>
> ...while it's probably easier to write code that is guaranteed to comply
> with the make_unsigned preconditions.
No? I'd have to try really hard to write realistic code that uses highest bit
set in a large unsigned non-bitfield variable.
> (Also, I have no idea what the usage patterns for actual types S1 and U2
> are. For usages with small U2,
Small unsigned types are promoted at least to int. If needed, make_signed()
can promote them to long long if needed (probably not). And if they are to be
compared using <, then their usage pattern will be that U2 is a count of
something.
> or e2 obtained from tainted sources,
> casting to S2 may well be an issue wrt preconditions.)
Such as?
> > But people will not consistently use (*), because it's more
> > error-prone, longer to type and harder to read (yeah, we're all lazy).
> > Using just "e1 < S1
>
> I'm not sure about that. As I wrote, I saw lots of occurrences of (*)
> across the LO code base.
And how many occurences that do not do (*) have you seen? (I have no idea how
to reasonably search for those).
> (And, again, people writing broken code is
> something that o3tl::make_unsigned cannot and will not address.)
And, yet, o3tl::make_signed would address that, for all cases that matter.
> > (e2)" can assert in S1 and then the only disadvantage there I can see is
> > if somebody actually somehow manages to trigger the assert =>
> > make_signed() is the better API.
>
> I don't understand the above sentence; what do you mean with "can assert
> in S1"?
e2 > std::numeric_limits<S1>::max() || e1 < S1(e2)
can be rewritten as
S1 make_signed(U2 v) { assert( v <= std::numeric_limits<S1>::max()); return
v; }
and then
e1 < make_signed(e2)
pretty much always does the job. And we'll probably hit the 25th LO
anniversary sooner than this assert.
--
Luboš Luňák
l.lunak at collabora.com
More information about the LibreOffice
mailing list