summaryrefslogtreecommitdiff
path: root/handy.h
diff options
context:
space:
mode:
authorKarl Williamson <khw@cpan.org>2020-12-05 16:21:52 -0700
committerKarl Williamson <khw@cpan.org>2020-12-06 13:04:46 -0700
commit92a0bb2462f53210b5f8af1332fc91806d507595 (patch)
treee6f0a11eb3e5110f1efab3da86628b8de0eb1c48 /handy.h
parent803e49356bee5584477e9411bafc8d8253ce5a47 (diff)
downloadperl-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.h30
1 files changed, 22 insertions, 8 deletions
diff --git a/handy.h b/handy.h
index 6e752b5610..05dbec300e 100644
--- a/handy.h
+++ b/handy.h
@@ -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