bits.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #ifndef IPHONE_FIRESTORE_PORT_BITS_H_
  17. #define IPHONE_FIRESTORE_PORT_BITS_H_
  18. // Various bit-twiddling functions, all of which are static members of the Bits
  19. // class (making it effectively a namespace). Operands are unsigned integers.
  20. // Munging bits in _signed_ integers is fraught with peril! For example,
  21. // -5 << n has undefined behavior (for some values of n).
  22. #include <stdint.h>
  23. class Bits_Port32_Test;
  24. class Bits_Port64_Test;
  25. namespace Firestore {
  26. class Bits {
  27. public:
  28. // Return floor(log2(n)) for positive integer n. Returns -1 iff n == 0.
  29. static int Log2Floor(uint32_t n);
  30. static int Log2Floor64(uint64_t n);
  31. // Potentially faster version of Log2Floor() that returns an
  32. // undefined value if n == 0
  33. static int Log2FloorNonZero(uint32_t n);
  34. static int Log2FloorNonZero64(uint64_t n);
  35. private:
  36. // Portable implementations.
  37. static int Log2Floor_Portable(uint32_t n);
  38. static int Log2Floor64_Portable(uint64_t n);
  39. static int Log2FloorNonZero_Portable(uint32_t n);
  40. static int Log2FloorNonZero64_Portable(uint64_t n);
  41. Bits(Bits const&) = delete;
  42. void operator=(Bits const&) = delete;
  43. // Allow tests to call _Portable variants directly.
  44. friend class ::Bits_Port32_Test;
  45. friend class ::Bits_Port64_Test;
  46. };
  47. // ------------------------------------------------------------------------
  48. // Implementation details follow
  49. // ------------------------------------------------------------------------
  50. #if defined(__GNUC__)
  51. inline int Bits::Log2Floor(uint32_t n) {
  52. return n == 0 ? -1 : 31 ^ __builtin_clz(n);
  53. }
  54. inline int Bits::Log2FloorNonZero(uint32_t n) {
  55. return 31 ^ __builtin_clz(n);
  56. }
  57. inline int Bits::Log2Floor64(uint64_t n) {
  58. return n == 0 ? -1 : 63 ^ __builtin_clzll(n);
  59. }
  60. inline int Bits::Log2FloorNonZero64(uint64_t n) {
  61. return 63 ^ __builtin_clzll(n);
  62. }
  63. #elif defined(COMPILER_MSVC)
  64. inline int Bits::Log2FloorNonZero(uint32 n) {
  65. #ifdef _M_IX86
  66. _asm {
  67. bsr ebx, n
  68. mov n, ebx
  69. }
  70. return n;
  71. #else
  72. return Bits::Log2FloorNonZero_Portable(n);
  73. #endif
  74. }
  75. inline int Bits::Log2Floor(uint32 n) {
  76. #ifdef _M_IX86
  77. _asm {
  78. xor ebx, ebx
  79. mov eax, n
  80. and eax, eax
  81. jz return_ebx
  82. bsr ebx, eax
  83. return_ebx:
  84. mov n, ebx
  85. }
  86. return n;
  87. #else
  88. return Bits::Log2Floor_Portable(n);
  89. #endif
  90. }
  91. inline int Bits::Log2Floor64(uint64_t n) {
  92. return Bits::Log2Floor64_Portable(n);
  93. }
  94. inline int Bits::Log2FloorNonZero64(uint64_t n) {
  95. return Bits::Log2FloorNonZero64_Portable(n);
  96. }
  97. #else // !__GNUC__ && !COMPILER_MSVC
  98. inline int Bits::Log2Floor64(uint64_t n) {
  99. return Bits::Log2Floor64_Portable(n);
  100. }
  101. inline int Bits::Log2FloorNonZero64(uint64_t n) {
  102. return Bits::Log2FloorNonZero64_Portable(n);
  103. }
  104. #endif
  105. inline int Bits::Log2FloorNonZero_Portable(uint32_t n) {
  106. // Just use the common routine
  107. return Log2Floor(n);
  108. }
  109. // Log2Floor64() is defined in terms of Log2Floor32(), Log2FloorNonZero32()
  110. inline int Bits::Log2Floor64_Portable(uint64_t n) {
  111. const uint32_t topbits = static_cast<uint32_t>(n >> 32);
  112. if (topbits == 0) {
  113. // Top bits are zero, so scan in bottom bits
  114. return Log2Floor(static_cast<uint32_t>(n));
  115. } else {
  116. return 32 + Log2FloorNonZero(topbits);
  117. }
  118. }
  119. // Log2FloorNonZero64() is defined in terms of Log2FloorNonZero32()
  120. inline int Bits::Log2FloorNonZero64_Portable(uint64_t n) {
  121. const uint32_t topbits = static_cast<uint32_t>(n >> 32);
  122. if (topbits == 0) {
  123. // Top bits are zero, so scan in bottom bits
  124. return Log2FloorNonZero(static_cast<uint32_t>(n));
  125. } else {
  126. return 32 + Log2FloorNonZero(topbits);
  127. }
  128. }
  129. } // namespace Firestore
  130. #endif // IPHONE_FIRESTORE_PORT_BITS_H_