1 /*------------------------------------------------------------------------- 2 * 3 * pg_bitutils.h 4 * Miscellaneous functions for bit-wise operations. 5 * 6 * 7 * Copyright (c) 2019, PostgreSQL Global Development Group 8 * 9 * src/include/port/pg_bitutils.h 10 * 11 *------------------------------------------------------------------------- 12 */ 13 #ifndef PG_BITUTILS_H 14 #define PG_BITUTILS_H 15 16 extern PGDLLIMPORT const uint8 pg_leftmost_one_pos[256]; 17 extern PGDLLIMPORT const uint8 pg_rightmost_one_pos[256]; 18 extern PGDLLIMPORT const uint8 pg_number_of_ones[256]; 19 20 /* 21 * pg_leftmost_one_pos32 22 * Returns the position of the most significant set bit in "word", 23 * measured from the least significant bit. word must not be 0. 24 */ 25 static inline int 26 pg_leftmost_one_pos32(uint32 word) 27 { 28 #ifdef HAVE__BUILTIN_CLZ 29 Assert(word != 0); 30 31 return 31 - __builtin_clz(word); 32 #else 33 int shift = 32 - 8; 34 35 Assert(word != 0); 36 37 while ((word >> shift) == 0) 38 shift -= 8; 39 40 return shift + pg_leftmost_one_pos[(word >> shift) & 255]; 41 #endif /* HAVE__BUILTIN_CLZ */ 42 } 43 44 /* 45 * pg_leftmost_one_pos64 46 * As above, but for a 64-bit word. 47 */ 48 static inline int 49 pg_leftmost_one_pos64(uint64 word) 50 { 51 #ifdef HAVE__BUILTIN_CLZ 52 Assert(word != 0); 53 54 #if defined(HAVE_LONG_INT_64) 55 return 63 - __builtin_clzl(word); 56 #elif defined(HAVE_LONG_LONG_INT_64) 57 return 63 - __builtin_clzll(word); 58 #else 59 #error must have a working 64-bit integer datatype 60 #endif 61 #else /* !HAVE__BUILTIN_CLZ */ 62 int shift = 64 - 8; 63 64 Assert(word != 0); 65 66 while ((word >> shift) == 0) 67 shift -= 8; 68 69 return shift + pg_leftmost_one_pos[(word >> shift) & 255]; 70 #endif /* HAVE__BUILTIN_CLZ */ 71 } 72 73 /* 74 * pg_rightmost_one_pos32 75 * Returns the position of the least significant set bit in "word", 76 * measured from the least significant bit. word must not be 0. 77 */ 78 static inline int 79 pg_rightmost_one_pos32(uint32 word) 80 { 81 #ifdef HAVE__BUILTIN_CTZ 82 Assert(word != 0); 83 84 return __builtin_ctz(word); 85 #else 86 int result = 0; 87 88 Assert(word != 0); 89 90 while ((word & 255) == 0) 91 { 92 word >>= 8; 93 result += 8; 94 } 95 result += pg_rightmost_one_pos[word & 255]; 96 return result; 97 #endif /* HAVE__BUILTIN_CTZ */ 98 } 99 100 /* 101 * pg_rightmost_one_pos64 102 * As above, but for a 64-bit word. 103 */ 104 static inline int 105 pg_rightmost_one_pos64(uint64 word) 106 { 107 #ifdef HAVE__BUILTIN_CTZ 108 Assert(word != 0); 109 110 #if defined(HAVE_LONG_INT_64) 111 return __builtin_ctzl(word); 112 #elif defined(HAVE_LONG_LONG_INT_64) 113 return __builtin_ctzll(word); 114 #else 115 #error must have a working 64-bit integer datatype 116 #endif 117 #else /* !HAVE__BUILTIN_CTZ */ 118 int result = 0; 119 120 Assert(word != 0); 121 122 while ((word & 255) == 0) 123 { 124 word >>= 8; 125 result += 8; 126 } 127 result += pg_rightmost_one_pos[word & 255]; 128 return result; 129 #endif /* HAVE__BUILTIN_CTZ */ 130 } 131 132 /* Count the number of one-bits in a uint32 or uint64 */ 133 extern int (*pg_popcount32) (uint32 word); 134 extern int (*pg_popcount64) (uint64 word); 135 136 /* Count the number of one-bits in a byte array */ 137 extern uint64 pg_popcount(const char *buf, int bytes); 138 139 /* 140 * Rotate the bits of "word" to the right by n bits. 141 */ 142 static inline uint32 143 pg_rotate_right32(uint32 word, int n) 144 { 145 return (word >> n) | (word << (sizeof(word) * BITS_PER_BYTE - n)); 146 } 147 148 #endif /* PG_BITUTILS_H */ 149