Browse Source

putil: define pbitops in terms of fundamental types

This ensures there's always an overload matching a particular definition of size_t / uint64_t, etc.
rdb 5 years ago
parent
commit
72b96f1afa
2 changed files with 156 additions and 56 deletions
  1. 129 35
      panda/src/putil/pbitops.I
  2. 27 21
      panda/src/putil/pbitops.h

+ 129 - 35
panda/src/putil/pbitops.I

@@ -15,7 +15,7 @@
  * Returns the number of 1 bits in the indicated word.
  */
 INLINE int
-count_bits_in_word(uint16_t x) {
+count_bits_in_word(unsigned short x) {
   return (int)num_bits_on[x];
 }
 
@@ -23,9 +23,9 @@ count_bits_in_word(uint16_t x) {
  * Returns the number of 1 bits in the indicated word.
  */
 INLINE int
-count_bits_in_word(uint32_t x) {
+count_bits_in_word(unsigned int x) {
 #if defined(__GNUC__) && defined(__POPCNT__)
-  return __builtin_popcount((unsigned int) x);
+  return __builtin_popcount(x);
 #else
   return (int)num_bits_on[x & 0xffff] + (int)num_bits_on[(x >> 16) & 0xffff];
 #endif
@@ -35,44 +35,74 @@ count_bits_in_word(uint32_t x) {
  * Returns the number of 1 bits in the indicated word.
  */
 INLINE int
-count_bits_in_word(uint64_t x) {
+count_bits_in_word(unsigned long x) {
 #if defined(__GNUC__) && defined(__POPCNT__)
-  return __builtin_popcountll((unsigned long long) x);
+  return __builtin_popcountl(x);
+#elif defined(_LP64)
+  return count_bits_in_word((unsigned int)x) + count_bits_in_word((unsigned int)(x >> 32));
 #else
-  return count_bits_in_word((uint32_t)x) + count_bits_in_word((uint32_t)(x >> 32));
+  return count_bits_in_word((unsigned int)x);
 #endif
 }
 
+/**
+ * Returns the number of 1 bits in the indicated word.
+ */
+INLINE int
+count_bits_in_word(unsigned long long x) {
+#if defined(__GNUC__) && defined(__POPCNT__)
+  return __builtin_popcountll(x);
+#else
+  return count_bits_in_word((unsigned int)x) + count_bits_in_word((unsigned int)(x >> 32));
+#endif
+}
+
+/**
+ * Returns a value such that every bit at or below the highest bit in x is 1.
+ */
+INLINE unsigned short
+flood_bits_down(unsigned short x) {
+  x |= (x >> 1);
+  x |= (x >> 2);
+  x |= (x >> 4);
+  x |= (x >> 8);
+  return x;
+}
+
 /**
  * Returns a value such that every bit at or below the highest bit in x is 1.
  */
-INLINE uint16_t
-flood_bits_down(uint16_t x) {
+INLINE unsigned int
+flood_bits_down(unsigned int x) {
   x |= (x >> 1);
   x |= (x >> 2);
   x |= (x >> 4);
   x |= (x >> 8);
+  x |= (x >> 16);
   return x;
 }
 
 /**
  * Returns a value such that every bit at or below the highest bit in x is 1.
  */
-INLINE uint32_t
-flood_bits_down(uint32_t x) {
+INLINE unsigned long
+flood_bits_down(unsigned long x) {
   x |= (x >> 1);
   x |= (x >> 2);
   x |= (x >> 4);
   x |= (x >> 8);
   x |= (x >> 16);
+#if defined(_LP64) || defined(__LP64__)
+  x |= (x >> 32);
+#endif
   return x;
 }
 
 /**
  * Returns a value such that every bit at or below the highest bit in x is 1.
  */
-INLINE uint64_t
-flood_bits_down(uint64_t x) {
+INLINE unsigned long long
+flood_bits_down(unsigned long long x) {
   x |= (x >> 1);
   x |= (x >> 2);
   x |= (x >> 4);
@@ -85,8 +115,8 @@ flood_bits_down(uint64_t x) {
 /**
  * Returns a value such that every bit at or above the highest bit in x is 1.
  */
-INLINE uint16_t
-flood_bits_up(uint16_t x) {
+INLINE unsigned short
+flood_bits_up(unsigned short x) {
   x |= (x << 1);
   x |= (x << 2);
   x |= (x << 4);
@@ -97,8 +127,8 @@ flood_bits_up(uint16_t x) {
 /**
  * Returns a value such that every bit at or above the highest bit in x is 1.
  */
-INLINE uint32_t
-flood_bits_up(uint32_t x) {
+INLINE unsigned int
+flood_bits_up(unsigned int x) {
   x |= (x << 1);
   x |= (x << 2);
   x |= (x << 4);
@@ -110,8 +140,24 @@ flood_bits_up(uint32_t x) {
 /**
  * Returns a value such that every bit at or above the highest bit in x is 1.
  */
-INLINE uint64_t
-flood_bits_up(uint64_t x) {
+INLINE unsigned long
+flood_bits_up(unsigned long x) {
+  x |= (x << 1);
+  x |= (x << 2);
+  x |= (x << 4);
+  x |= (x << 8);
+  x |= (x << 16);
+#if defined(_LP64) || defined(__LP64__)
+  x |= (x << 32);
+#endif
+  return x;
+}
+
+/**
+ * Returns a value such that every bit at or above the highest bit in x is 1.
+ */
+INLINE unsigned long long
+flood_bits_up(unsigned long long x) {
   x |= (x << 1);
   x |= (x << 2);
   x |= (x << 4);
@@ -126,7 +172,7 @@ flood_bits_up(uint64_t x) {
  * no 1 bits.
  */
 INLINE int
-get_lowest_on_bit(uint16_t x) {
+get_lowest_on_bit(unsigned short x) {
 #if defined(_MSC_VER)
   unsigned long result;
   return (_BitScanForward(&result, (unsigned long) x) == 0) ? -1 : result;
@@ -137,7 +183,7 @@ get_lowest_on_bit(uint16_t x) {
     return -1;
   }
 
-  uint16_t w = (x & (~x + 1));
+  unsigned short w = (x & (~x + 1));
   return (int)num_bits_on[w - 1];
 #endif
 }
@@ -147,7 +193,7 @@ get_lowest_on_bit(uint16_t x) {
  * no 1 bits.
  */
 INLINE int
-get_lowest_on_bit(uint32_t x) {
+get_lowest_on_bit(unsigned int x) {
 #if defined(_MSC_VER)
   unsigned long result;
   return (_BitScanForward(&result, (unsigned long) x) == 0) ? -1 : result;
@@ -158,7 +204,28 @@ get_lowest_on_bit(uint32_t x) {
     return -1;
   }
 
-  uint32_t w = (x & (~x + 1));
+  unsigned int w = (x & (~x + 1));
+  return count_bits_in_word(w - 1);
+#endif
+}
+
+/**
+ * Returns the index of the lowest 1 bit in the word.  Returns -1 if there are
+ * no 1 bits.
+ */
+INLINE int
+get_lowest_on_bit(unsigned long x) {
+#if defined(_MSC_VER) && defined(_M_X64)
+  unsigned long result;
+  return (_BitScanForward(&result, x) == 0) ? -1 : result;
+#elif defined(__GNUC__)
+  return __builtin_ffsl((long) x) - 1;
+#else
+  if (x == 0) {
+    return -1;
+  }
+
+  unsigned long w = (x & (~x + 1));
   return count_bits_in_word(w - 1);
 #endif
 }
@@ -168,7 +235,7 @@ get_lowest_on_bit(uint32_t x) {
  * no 1 bits.
  */
 INLINE int
-get_lowest_on_bit(uint64_t x) {
+get_lowest_on_bit(unsigned long long x) {
 #if defined(_MSC_VER) && defined(_M_X64)
   unsigned long result;
   return (_BitScanForward64(&result, (unsigned __int64) x) == 0) ? -1 : result;
@@ -179,7 +246,7 @@ get_lowest_on_bit(uint64_t x) {
     return -1;
   }
 
-  uint64_t w = (x & (~x + 1));
+  unsigned long long w = (x & (~x + 1));
   return count_bits_in_word(w - 1);
 #endif
 }
@@ -189,14 +256,14 @@ get_lowest_on_bit(uint64_t x) {
  * are no 1 bits.
  */
 INLINE int
-get_highest_on_bit(uint16_t x) {
+get_highest_on_bit(unsigned short x) {
 #if defined(_MSC_VER)
   unsigned long result;
   return (_BitScanReverse(&result, (unsigned long) x) == 0) ? -1 : result;
 #elif defined(__GNUC__)
   return (x == 0) ? -1 : 31 - __builtin_clz((unsigned int) x);
 #else
-  uint16_t w = flood_bits_down(x);
+  unsigned short w = flood_bits_down(x);
   return count_bits_in_word(w) - 1;
 #endif
 }
@@ -206,14 +273,31 @@ get_highest_on_bit(uint16_t x) {
  * are no 1 bits.
  */
 INLINE int
-get_highest_on_bit(uint32_t x) {
+get_highest_on_bit(unsigned int x) {
 #if defined(_MSC_VER)
   unsigned long result;
   return (_BitScanReverse(&result, (unsigned long) x) == 0) ? -1 : result;
 #elif defined(__GNUC__)
-  return (x == 0) ? -1 : 31 - __builtin_clz((unsigned int) x);
+  return (x == 0) ? -1 : 31 - __builtin_clz(x);
+#else
+  unsigned int w = flood_bits_down(x);
+  return count_bits_in_word(w) - 1;
+#endif
+}
+
+/**
+ * Returns the index of the highest 1 bit in the word.  Returns -1 if there
+ * are no 1 bits.
+ */
+INLINE int
+get_highest_on_bit(unsigned long x) {
+#if defined(_MSC_VER) && defined(_M_X64)
+  unsigned long result;
+  return (_BitScanReverse(&result, (unsigned long) x) == 0) ? -1 : result;
+#elif defined(__GNUC__)
+  return (x == 0) ? -1 : 63 - __builtin_clzl(x);
 #else
-  uint32_t w = flood_bits_down(x);
+  unsigned long long w = flood_bits_down(x);
   return count_bits_in_word(w) - 1;
 #endif
 }
@@ -223,14 +307,14 @@ get_highest_on_bit(uint32_t x) {
  * are no 1 bits.
  */
 INLINE int
-get_highest_on_bit(uint64_t x) {
+get_highest_on_bit(unsigned long long x) {
 #if defined(_MSC_VER) && defined(_M_X64)
   unsigned long result;
   return (_BitScanReverse64(&result, (unsigned __int64) x) == 0) ? -1 : result;
 #elif defined(__GNUC__)
-  return (x == 0) ? -1 : 63 - __builtin_clzll((unsigned long long) x);
+  return (x == 0) ? -1 : 63 - __builtin_clzll(x);
 #else
-  uint64_t w = flood_bits_down(x);
+  unsigned long long w = flood_bits_down(x);
   return count_bits_in_word(w) - 1;
 #endif
 }
@@ -241,7 +325,17 @@ get_highest_on_bit(uint64_t x) {
  * Returns the smallest number n such that (1 << n) is larger than x.
  */
 INLINE int
-get_next_higher_bit(uint16_t x) {
+get_next_higher_bit(unsigned short x) {
+  return get_highest_on_bit(x) + 1;
+}
+
+/**
+ * Returns the smallest power of 2 greater than x.
+ *
+ * Returns the smallest number n such that (1 << n) is larger than x.
+ */
+INLINE int
+get_next_higher_bit(unsigned int x) {
   return get_highest_on_bit(x) + 1;
 }
 
@@ -251,7 +345,7 @@ get_next_higher_bit(uint16_t x) {
  * Returns the smallest number n such that (1 << n) is larger than x.
  */
 INLINE int
-get_next_higher_bit(uint32_t x) {
+get_next_higher_bit(unsigned long x) {
   return get_highest_on_bit(x) + 1;
 }
 
@@ -261,6 +355,6 @@ get_next_higher_bit(uint32_t x) {
  * Returns the smallest number n such that (1 << n) is larger than x.
  */
 INLINE int
-get_next_higher_bit(uint64_t x) {
+get_next_higher_bit(unsigned long long x) {
   return get_highest_on_bit(x) + 1;
 }

+ 27 - 21
panda/src/putil/pbitops.h

@@ -24,27 +24,33 @@
 // This file defines a few low-level bit-operation routines, optimized all to
 // heck.
 
-INLINE int count_bits_in_word(uint16_t x);
-INLINE int count_bits_in_word(uint32_t x);
-INLINE int count_bits_in_word(uint64_t x);
-
-INLINE uint16_t flood_bits_down(uint16_t x);
-INLINE uint32_t flood_bits_down(uint32_t x);
-INLINE uint64_t flood_bits_down(uint64_t x);
-INLINE uint16_t flood_bits_up(uint16_t x);
-INLINE uint32_t flood_bits_up(uint32_t x);
-INLINE uint64_t flood_bits_up(uint64_t x);
-
-INLINE int get_lowest_on_bit(uint16_t x);
-INLINE int get_lowest_on_bit(uint32_t x);
-INLINE int get_lowest_on_bit(uint64_t x);
-INLINE int get_highest_on_bit(uint16_t x);
-INLINE int get_highest_on_bit(uint32_t x);
-INLINE int get_highest_on_bit(uint64_t x);
-
-INLINE int get_next_higher_bit(uint16_t x);
-INLINE int get_next_higher_bit(uint32_t x);
-INLINE int get_next_higher_bit(uint64_t x);
+INLINE int count_bits_in_word(unsigned short x);
+INLINE int count_bits_in_word(unsigned int x);
+INLINE int count_bits_in_word(unsigned long x);
+INLINE int count_bits_in_word(unsigned long long x);
+
+INLINE unsigned short flood_bits_down(unsigned short x);
+INLINE unsigned int flood_bits_down(unsigned int x);
+INLINE unsigned long flood_bits_down(unsigned long x);
+INLINE unsigned long long flood_bits_down(unsigned long long x);
+INLINE unsigned short flood_bits_up(unsigned short x);
+INLINE unsigned int flood_bits_up(unsigned int x);
+INLINE unsigned long flood_bits_up(unsigned long x);
+INLINE unsigned long long flood_bits_up(unsigned long long x);
+
+INLINE int get_lowest_on_bit(unsigned short x);
+INLINE int get_lowest_on_bit(unsigned int x);
+INLINE int get_lowest_on_bit(unsigned long x);
+INLINE int get_lowest_on_bit(unsigned long long x);
+INLINE int get_highest_on_bit(unsigned short x);
+INLINE int get_highest_on_bit(unsigned int x);
+INLINE int get_highest_on_bit(unsigned long x);
+INLINE int get_highest_on_bit(unsigned long long x);
+
+INLINE int get_next_higher_bit(unsigned short x);
+INLINE int get_next_higher_bit(unsigned int x);
+INLINE int get_next_higher_bit(unsigned long x);
+INLINE int get_next_higher_bit(unsigned long long x);
 
 // This table precomputes the number of on bits in each 16-bit word.
 extern EXPCL_PANDA_PUTIL const unsigned char num_bits_on[65536];