Skip to content

Commit

Permalink
Create and use lsbit_pos()
Browse files Browse the repository at this point in the history
This is a function to return the position of the least significant 1 bit
in a word.  In this commit it just isolates that bit and uses the
function single_1bit_pos() created 2 commits ago.
  • Loading branch information
khwilliamson committed Jul 17, 2021
1 parent 289f396 commit 928c5f6
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 27 deletions.
1 change: 1 addition & 0 deletions embed.fnc
Expand Up @@ -1141,6 +1141,7 @@ ATdmoR |bool |is_utf8_invariant_string|NN const U8* const s \
ATidRp |bool |is_utf8_invariant_string_loc|NN const U8* const s \
|STRLEN len \
|NULLOK const U8 ** ep
CTiRp |unsigned|lsbit_pos|PERL_UINTMAX_T word
CTiRp |unsigned|single_1bit_pos|PERL_UINTMAX_T word
#ifndef EBCDIC
CTiRp |unsigned int|variant_byte_number|PERL_UINTMAX_T word
Expand Down
1 change: 1 addition & 0 deletions embed.h
Expand Up @@ -302,6 +302,7 @@
#define load_module Perl_load_module
#endif
#define looks_like_number(a) Perl_looks_like_number(aTHX_ a)
#define lsbit_pos Perl_lsbit_pos
#define magic_dump(a) Perl_magic_dump(aTHX_ a)
#define markstack_grow() Perl_markstack_grow(aTHX)
#ifndef MULTIPLICITY
Expand Down
68 changes: 41 additions & 27 deletions inline.h
Expand Up @@ -664,6 +664,32 @@ Perl_is_utf8_invariant_string_loc(const U8* const s, STRLEN len, const U8 ** ep)
return TRUE;
}

PERL_STATIC_INLINE unsigned
Perl_lsbit_pos(PERL_UINTMAX_T word)
{
/* Find the position (0..63) of the least significant set bit in the input
* word */

ASSUME(word != 0);

/* Isolate the lsb;
* 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, and 'y's are their complements)
* s
* x..x100..00
* y..y011..11 Complement
* y..y100..00 Add 1
* 0..0100..00 And with the original
*
* (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.)
*/
return single_1bit_pos(word & (~word + 1));
}

PERL_STATIC_INLINE unsigned
Perl_single_1bit_pos(PERL_UINTMAX_T word)
{
Expand Down Expand Up @@ -702,23 +728,13 @@ Perl_variant_byte_number(PERL_UINTMAX_T word)
/* Bytes are stored like
* Byte8 ... Byte2 Byte1
* 63..56...15...8 7...0
*
* Isolate the lsb;
* 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, and 'y's are their complements)
* s
* x..x100..00
* y..y011..11 Complement
* y..y100..00 Add 1
* 0..0100..00 AND with the original
*
* (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);
* so getting the lsb of the whole modified word is getting the msb of the
* first byte that has its msb set */
word = lsbit_pos(word);

/* Here, word contains the position 7,15,23,...55,63 of that bit. Convert
* to 0..7 */
return (unsigned int) ((word + 1) >> 3) - 1;

# elif BYTEORDER == 0x4321 || BYTEORDER == 0x87654321

Expand All @@ -743,10 +759,6 @@ Perl_variant_byte_number(PERL_UINTMAX_T word)
* the 1 bits, which is our desired result */
word -= (word >> 1);

# else
# error Unexpected byte order
# endif

/* Here 'word' has a single bit set: the msb of the first byte in which it
* is set. Calculate that position in the word. We can use this
* specialized solution: https://stackoverflow.com/a/32339674/1626653,
Expand All @@ -758,18 +770,20 @@ Perl_variant_byte_number(PERL_UINTMAX_T word)
| (55 << 8) | (63 << 0));
word >>= PERL_WORDSIZE * 7; /* >> by either 56 or 24 */

/* Here, word contains the position 7,15,23,...,63 of that bit. Convert to
* 0..7 */
/* Here, word contains the position 63,55,...,23,15,7 of that bit. Convert
* to 0..7 */
word = ((word + 1) >> 3) - 1;

# if BYTEORDER == 0x4321 || BYTEORDER == 0x87654321

/* And invert the result */
/* And invert the result because of the reversed byte order on this
* platform */
word = CHARBITS - word - 1;

return (unsigned int) word;

# else
# error Unexpected byte order
# endif

return (unsigned int) word;
}

#endif
Expand Down
6 changes: 6 additions & 0 deletions proto.h
Expand Up @@ -1861,6 +1861,12 @@ PERL_CALLCONV I32 Perl_looks_like_number(pTHX_ SV *const sv)
#define PERL_ARGS_ASSERT_LOOKS_LIKE_NUMBER \
assert(sv)

#ifndef PERL_NO_INLINE_FUNCTIONS
PERL_STATIC_INLINE unsigned Perl_lsbit_pos(PERL_UINTMAX_T word)
__attribute__warn_unused_result__;
#define PERL_ARGS_ASSERT_LSBIT_POS
#endif

PERL_CALLCONV int Perl_magic_clear_all_env(pTHX_ SV* sv, MAGIC* mg);
#define PERL_ARGS_ASSERT_MAGIC_CLEAR_ALL_ENV \
assert(sv); assert(mg)
Expand Down

0 comments on commit 928c5f6

Please sign in to comment.