summaryrefslogtreecommitdiff
path: root/inline.h
diff options
context:
space:
mode:
authorKarl Williamson <khw@cpan.org>2021-06-05 01:15:37 -0600
committerKarl Williamson <khw@cpan.org>2021-07-30 05:41:27 -0600
commit8a6ab0a2b6184deb2f9a99f0a9622e8f836de4bd (patch)
tree280de16102aa7509f90b7cba01c2cdabea4ed550 /inline.h
parent995a49544ee5d0b46679907f5ba9fe50be890438 (diff)
downloadperl-8a6ab0a2b6184deb2f9a99f0a9622e8f836de4bd.tar.gz
Perl_variant_byte_number: Generalize
The current mechanism doesn't work if the lowest bit is the one set. At the moment that doesn't matter as we aren't looking at that bit anyway. But a future commit will refactor things so that bit will be looked at. So prepare for that. The new expression is simpler, besides.
Diffstat (limited to 'inline.h')
-rw-r--r--inline.h24
1 files changed, 10 insertions, 14 deletions
diff --git a/inline.h b/inline.h
index bde3c4c48c..42e1ae7bf4 100644
--- a/inline.h
+++ b/inline.h
@@ -727,22 +727,18 @@ Perl_variant_byte_number(PERL_UINTMAX_T word)
* https://stackoverflow.com/questions/757059/position-of-least-significant-bit-that-is-set
*
* The word will look like this, with a rightmost set bit in position 's':
- * ('x's are don't cares)
+ * ('x's are don't cares, and 'y's are their complements)
* s
- * x..x100..0
- * x..xx10..0 Right shift (rightmost 0 is shifted off)
- * x..xx01..1 Subtract 1, turns all the trailing zeros into 1's and
- * the 1 just to their left into a 0; the remainder is
- * untouched
- * 0..0011..1 The xor with the original, x..xx10..0, clears that
- * remainder, sets the bottom to all 1
- * 0..0100..0 Add 1 to clear the word except for the bit in 's'
+ * x..x100..00
+ * y..y011..11 Complement
+ * y..y100..00 Add 1
+ * 0..0100..00 AND with the original
*
- * Another method is to do 'word &= -word'; but it generates a compiler
- * message on some platforms about taking the negative of an unsigned */
-
- word >>= 1;
- word = 1 + (word ^ (word - 1));
+ * (Yes, complementing and adding 1 is just taking the negative on 2's
+ * complement machines, but not on 1's complement ones, and some compilers
+ * complain about negating an unsigned.)
+ */
+ word &= (~word + 1);
# elif BYTEORDER == 0x4321 || BYTEORDER == 0x87654321