Generalize macro and move to handy.h
authorKarl Williamson <khw@cpan.org>
Wed, 20 Mar 2019 21:31:03 +0000 (15:31 -0600)
committerKarl Williamson <khw@cpan.org>
Thu, 21 Mar 2019 17:17:45 +0000 (11:17 -0600)
The macro verified that its input was in the range '1' to '9' by using a
subtraction and a single conditional.  This commit generalizes this
non-obvious method of avoiding a conditional, and moves it to handy.h so
it can be used in other places.

handy.h
sv.c

diff --git a/handy.h b/handy.h
index 57ad62d..150fb08 100644 (file)
--- a/handy.h
+++ b/handy.h
@@ -1094,6 +1094,12 @@ patched there.  The file as of this writing is cpan/Devel-PPPort/parts/inc/misc
 #define FITS_IN_8_BITS(c) (1)
 #endif
 
+/* Returns true if c is in the range l..u
+ * Written with the cast so it only needs one conditional test
+ */
+#define inRANGE(c, l, u) (__ASSERT_((u) >= (l))                          \
+    ((WIDEST_UTYPE) (((c) - (l)) | 0) <= ((WIDEST_UTYPE) ((u) - (l)))))
+
 #ifdef EBCDIC
 #   ifndef _ALL_SOURCE
         /* The native libc isascii() et.al. functions return the wrong results
diff --git a/sv.c b/sv.c
index e9a4682..b6d9123 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -11071,12 +11071,6 @@ S_sprintf_arg_num_val(pTHX_ va_list *const args, int i, SV *sv, bool *neg)
     return (STRLEN)iv;
 }
 
-
-/* Returns true if c is in the range '1'..'9'
- * Written with the cast so it only needs one conditional test
- */
-#define IS_1_TO_9(c) ((U8)(c - '1') <= 8)
-
 /* Read in and return a number. Updates *pattern to point to the char
  * following the number. Expects the first char to 1..9.
  * Croaks if the number exceeds 1/4 of the maximum value of STRLEN.
@@ -11093,7 +11087,7 @@ S_expect_number(pTHX_ const char **const pattern)
 
     PERL_ARGS_ASSERT_EXPECT_NUMBER;
 
-    assert(IS_1_TO_9(**pattern));
+    assert(inRANGE(**pattern, '1', '9'));
 
     var = *(*pattern)++ - '0';
     while (isDIGIT(**pattern)) {
@@ -12042,7 +12036,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
     [%bcdefginopsuxDFOUX] format (mandatory)
 */
 
-       if (IS_1_TO_9(*q)) {
+       if (inRANGE(*q, '1', '9')) {
             width = expect_number(&q);
            if (*q == '$') {
                 if (args)
@@ -12110,7 +12104,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
        if (*q == '*') {
             STRLEN ix; /* explicit width/vector separator index */
            q++;
-           if (IS_1_TO_9(*q)) {
+            if (inRANGE(*q, '1', '9')) {
                 ix = expect_number(&q);
                if (*q++ == '$') {
                     if (args)
@@ -12182,7 +12176,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                fill = TRUE;
                 q++;
             }
-            if (IS_1_TO_9(*q))
+            if (inRANGE(*q, '1', '9'))
                 width = expect_number(&q);
        }
 
@@ -12195,7 +12189,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
            if (*q == '*') {
                 STRLEN ix; /* explicit precision index */
                q++;
-                if (IS_1_TO_9(*q)) {
+                if (inRANGE(*q, '1', '9')) {
                     ix = expect_number(&q);
                     if (*q++ == '$') {
                         if (args)
@@ -12234,7 +12228,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                  */
                 while (*q == '0')
                     q++;
-                precis = IS_1_TO_9(*q) ? expect_number(&q) : 0;
+                precis = inRANGE(*q, '1', '9') ? expect_number(&q) : 0;
                has_precis = TRUE;
            }
        }