diff options
author | Karl Williamson <khw@cpan.org> | 2020-12-05 16:21:52 -0700 |
---|---|---|
committer | Karl Williamson <khw@cpan.org> | 2020-12-06 13:04:46 -0700 |
commit | 92a0bb2462f53210b5f8af1332fc91806d507595 (patch) | |
tree | e6f0a11eb3e5110f1efab3da86628b8de0eb1c48 /handy.h | |
parent | 803e49356bee5584477e9411bafc8d8253ce5a47 (diff) | |
download | perl-92a0bb2462f53210b5f8af1332fc91806d507595.tar.gz |
inRANGE, withinCOUNT: Split so can avoid asserts
This commit splits these macros up into components that are separately
callable. The components are considered internal core only, and the
purpose is to avoid duplicate assert() calls that were causing some
compilers to crash from not being able to handle the size.
In particular, this commit refactors inRANGE so that the asserts are
done only once, shortening what it expands to.
Diffstat (limited to 'handy.h')
-rw-r--r-- | handy.h | 30 |
1 files changed, 22 insertions, 8 deletions
@@ -1409,18 +1409,32 @@ or casts * needed. (The NV casts stop any warnings about comparison always being true * if called with an unsigned. The cast preserves the sign, which is all we * care about.) */ -#define withinCOUNT(c, l, n) (__ASSERT_((NV) (l) >= 0) \ - __ASSERT_((NV) (n) >= 0) \ - (((WIDEST_UTYPE) (((c)) - ((l) | 0))) <= (((WIDEST_UTYPE) ((n) | 0))))) +#define withinCOUNT(c, l, n) (__ASSERT_((NV) (l) >= 0) \ + __ASSERT_((NV) (n) >= 0) \ + withinCOUNT_KNOWN_VALID_((c), (l), (n))) + +/* For internal use only, this can be used in places where it is known that the + * parameters to withinCOUNT() are valid, to avoid the asserts. For example, + * inRANGE() below, calls this several times, but does all the necessary + * asserts itself, once. The reason that this is necessary is that the + * duplicate asserts were exceeding the internal limits of some compilers */ +#define withinCOUNT_KNOWN_VALID_(c, l, n) \ + (((WIDEST_UTYPE) (((c)) - ((l) | 0))) <= (((WIDEST_UTYPE) ((n) | 0)))) /* Returns true if c is in the range l..u, where 'l' is non-negative * Written this way so that after optimization, only one conditional test is * needed. */ -#define inRANGE(c, l, u) (__ASSERT_((u) >= (l)) \ - ( (sizeof(c) == sizeof(U8)) ? withinCOUNT(((U8) (c)), (l), ((u) - (l))) \ - : (sizeof(c) == sizeof(U32)) ? withinCOUNT(((U32) (c)), (l), ((u) - (l))) \ - : (__ASSERT_(sizeof(c) == sizeof(WIDEST_UTYPE)) \ - withinCOUNT(((WIDEST_UTYPE) (c)), (l), ((u) - (l)))))) +#define inRANGE(c, l, u) (__ASSERT_((NV) (l) >= 0) __ASSERT_((u) >= (l)) \ + ( (sizeof(c) == sizeof(U8)) ? inRANGE_helper_(U8, (c), (l), ((u))) \ + : (sizeof(c) == sizeof(U32)) ? inRANGE_helper_(U32,(c), (l), ((u))) \ + : (__ASSERT_(sizeof(c) == sizeof(WIDEST_UTYPE)) \ + inRANGE_helper_(WIDEST_UTYPE,(c), (l), ((u)))))) + +/* For internal use, this is used by machine-generated code which generates + * known valid calls, with a known sizeof(). This avoids the extra code and + * asserts that were exceeding internal limits of some compilers. */ +#define inRANGE_helper_(cast, c, l, u) \ + withinCOUNT_KNOWN_VALID_(((cast) (c)), (l), ((u) - (l))) #ifdef EBCDIC # ifndef _ALL_SOURCE |