diff options
author | David Rowley <drowley@postgresql.org> | 2020-04-08 16:22:52 +1200 |
---|---|---|
committer | David Rowley <drowley@postgresql.org> | 2020-04-08 16:22:52 +1200 |
commit | f0705bb6286d8a24e08ddd99641264ba947ebd03 (patch) | |
tree | 97518ecfc8e12e4ab5702bc6925d37d16c620443 /src | |
parent | 7a5d74b7dd4b1324e8a8fff4086d51d4f43b1721 (diff) | |
download | postgresql-f0705bb6286d8a24e08ddd99641264ba947ebd03.tar.gz postgresql-f0705bb6286d8a24e08ddd99641264ba947ebd03.zip |
Add functions to calculate the next power of 2
There are many areas in the code where we need to determine the next
highest power of 2 of a given number. We tend to always do that in an
ad-hoc way each time, generally with some tight for loop which performs a
bitshift left once per loop and goes until it finds a number above the
given number.
Here we add two generic functions which make use of the existing
pg_leftmost_one_pos* functions which, when available, will allow us to
calculate the next power of 2 without any looping.
Here we don't add any code which uses these new functions. That will be
done in follow-up commits.
Author: David Fetter, with some minor adjustments by me
Reviewed-by: John Naylor, Jesse Zhang
Discussion: https://postgr.es/m/20200114173553.GE32763%40fetter.org
Diffstat (limited to 'src')
-rw-r--r-- | src/include/port/pg_bitutils.h | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/src/include/port/pg_bitutils.h b/src/include/port/pg_bitutils.h index 498e5323081..4ca92f076dc 100644 --- a/src/include/port/pg_bitutils.h +++ b/src/include/port/pg_bitutils.h @@ -129,6 +129,78 @@ pg_rightmost_one_pos64(uint64 word) #endif /* HAVE__BUILTIN_CTZ */ } +/* + * pg_nextpower2_32 + * Returns the next highest power of 2 of 'num', or 'num', if it's + * already a power of 2. + * + * 'num' mustn't be 0 or be above PG_UINT32_MAX / 2 + 1. + */ +static inline uint32 +pg_nextpower2_32(uint32 num) +{ + Assert(num > 0 && num <= PG_UINT32_MAX / 2 + 1); + + /* + * A power 2 number has only 1 bit set. Subtracting 1 from such a number + * will turn on all previous bits resulting in no common bits being set + * between num and num-1. + */ + if ((num & (num - 1)) == 0) + return num; /* already power 2 */ + + return ((uint32) 1) << (pg_leftmost_one_pos32(num) + 1); +} + +/* + * pg_nextpower2_64 + * Returns the next highest power of 2 of 'num', or 'num', if it's + * already a power of 2. + * + * 'num' mustn't be 0 or be above PG_UINT64_MAX / 2 + 1. + */ +static inline uint64 +pg_nextpower2_64(uint64 num) +{ + Assert(num > 0 && num <= PG_UINT64_MAX / 2 + 1); + + /* + * A power 2 number has only 1 bit set. Subtracting 1 from such a number + * will turn on all previous bits resulting in no common bits being set + * between num and num-1. + */ + if ((num & (num - 1)) == 0) + return num; /* already power 2 */ + + return ((uint64) 1) << (pg_leftmost_one_pos64(num) + 1); +} + +/* + * pg_ceil_log2_32 + * Returns equivalent of ceil(log2(num)) + */ +static inline uint32 +pg_ceil_log2_32(uint32 num) +{ + if (num < 2) + return 0; + else + return pg_leftmost_one_pos32(num - 1) + 1; +} + +/* + * pg_ceil_log2_64 + * Returns equivalent of ceil(log2(num)) + */ +static inline uint64 +pg_ceil_log2_64(uint64 num) +{ + if (num < 2) + return 0; + else + return pg_leftmost_one_pos64(num - 1) + 1; +} + /* Count the number of one-bits in a uint32 or uint64 */ extern int (*pg_popcount32) (uint32 word); extern int (*pg_popcount64) (uint64 word); |