• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // This file defines some bit utilities.
6 
7 #ifndef THIRD_PARTY_BASE_BITS_H_
8 #define THIRD_PARTY_BASE_BITS_H_
9 
10 #include <stddef.h>
11 #include <stdint.h>
12 
13 #include <type_traits>
14 
15 #include "third_party/base/compiler_specific.h"
16 #include "third_party/base/logging.h"
17 
18 #if defined(COMPILER_MSVC)
19 #include <intrin.h>
20 #endif
21 
22 namespace pdfium {
23 namespace base {
24 namespace bits {
25 
26 // Returns true iff |value| is a power of 2.
27 template <typename T,
28           typename = typename std::enable_if<std::is_integral<T>::value>>
IsPowerOfTwo(T value)29 constexpr inline bool IsPowerOfTwo(T value) {
30   // From "Hacker's Delight": Section 2.1 Manipulating Rightmost Bits.
31   //
32   // Only positive integers with a single bit set are powers of two. If only one
33   // bit is set in x (e.g. 0b00000100000000) then |x-1| will have that bit set
34   // to zero and all bits to its right set to 1 (e.g. 0b00000011111111). Hence
35   // |x & (x-1)| is 0 iff x is a power of two.
36   return value > 0 && (value & (value - 1)) == 0;
37 }
38 
39 // Round up |size| to a multiple of alignment, which must be a power of two.
Align(size_t size,size_t alignment)40 inline size_t Align(size_t size, size_t alignment) {
41   DCHECK(IsPowerOfTwo(alignment));
42   return (size + alignment - 1) & ~(alignment - 1);
43 }
44 
45 // CountLeadingZeroBits(value) returns the number of zero bits following the
46 // most significant 1 bit in |value| if |value| is non-zero, otherwise it
47 // returns {sizeof(T) * 8}.
48 // Example: 00100010 -> 2
49 //
50 // CountTrailingZeroBits(value) returns the number of zero bits preceding the
51 // least significant 1 bit in |value| if |value| is non-zero, otherwise it
52 // returns {sizeof(T) * 8}.
53 // Example: 00100010 -> 1
54 //
55 // C does not have an operator to do this, but fortunately the various
56 // compilers have built-ins that map to fast underlying processor instructions.
57 #if defined(COMPILER_MSVC)
58 
59 template <typename T, unsigned bits = sizeof(T) * 8>
60 ALWAYS_INLINE
61     typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 4,
62                             unsigned>::type
CountLeadingZeroBits(T x)63     CountLeadingZeroBits(T x) {
64   static_assert(bits > 0, "invalid instantiation");
65   unsigned long index;
66   return LIKELY(_BitScanReverse(&index, static_cast<uint32_t>(x)))
67              ? (31 - index - (32 - bits))
68              : bits;
69 }
70 
71 template <typename T, unsigned bits = sizeof(T) * 8>
72 ALWAYS_INLINE
73     typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) == 8,
74                             unsigned>::type
CountLeadingZeroBits(T x)75     CountLeadingZeroBits(T x) {
76   static_assert(bits > 0, "invalid instantiation");
77   unsigned long index;
78   return LIKELY(_BitScanReverse64(&index, static_cast<uint64_t>(x)))
79              ? (63 - index)
80              : 64;
81 }
82 
83 template <typename T, unsigned bits = sizeof(T) * 8>
84 ALWAYS_INLINE
85     typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 4,
86                             unsigned>::type
CountTrailingZeroBits(T x)87     CountTrailingZeroBits(T x) {
88   static_assert(bits > 0, "invalid instantiation");
89   unsigned long index;
90   return LIKELY(_BitScanForward(&index, static_cast<uint32_t>(x))) ? index
91                                                                    : bits;
92 }
93 
94 template <typename T, unsigned bits = sizeof(T) * 8>
95 ALWAYS_INLINE
96     typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) == 8,
97                             unsigned>::type
CountTrailingZeroBits(T x)98     CountTrailingZeroBits(T x) {
99   static_assert(bits > 0, "invalid instantiation");
100   unsigned long index;
101   return LIKELY(_BitScanForward64(&index, static_cast<uint64_t>(x))) ? index
102                                                                      : 64;
103 }
104 
CountLeadingZeroBits32(uint32_t x)105 ALWAYS_INLINE uint32_t CountLeadingZeroBits32(uint32_t x) {
106   return CountLeadingZeroBits(x);
107 }
108 
109 #if defined(ARCH_CPU_64_BITS)
110 
111 // MSVC only supplies _BitScanForward64 when building for a 64-bit target.
CountLeadingZeroBits64(uint64_t x)112 ALWAYS_INLINE uint64_t CountLeadingZeroBits64(uint64_t x) {
113   return CountLeadingZeroBits(x);
114 }
115 
116 #endif
117 
118 #elif defined(COMPILER_GCC)
119 
120 // __builtin_clz has undefined behaviour for an input of 0, even though there's
121 // clearly a return value that makes sense, and even though some processor clz
122 // instructions have defined behaviour for 0. We could drop to raw __asm__ to
123 // do better, but we'll avoid doing that unless we see proof that we need to.
124 template <typename T, unsigned bits = sizeof(T) * 8>
125 ALWAYS_INLINE
126     typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 8,
127                             unsigned>::type
CountLeadingZeroBits(T value)128     CountLeadingZeroBits(T value) {
129   static_assert(bits > 0, "invalid instantiation");
130   return LIKELY(value)
131              ? bits == 64
132                    ? __builtin_clzll(static_cast<uint64_t>(value))
133                    : __builtin_clz(static_cast<uint32_t>(value)) - (32 - bits)
134              : bits;
135 }
136 
137 template <typename T, unsigned bits = sizeof(T) * 8>
138 ALWAYS_INLINE
139     typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 8,
140                             unsigned>::type
CountTrailingZeroBits(T value)141     CountTrailingZeroBits(T value) {
142   return LIKELY(value) ? bits == 64
143                              ? __builtin_ctzll(static_cast<uint64_t>(value))
144                              : __builtin_ctz(static_cast<uint32_t>(value))
145                        : bits;
146 }
147 
CountLeadingZeroBits32(uint32_t x)148 ALWAYS_INLINE uint32_t CountLeadingZeroBits32(uint32_t x) {
149   return CountLeadingZeroBits(x);
150 }
151 
152 #if defined(ARCH_CPU_64_BITS)
153 
CountLeadingZeroBits64(uint64_t x)154 ALWAYS_INLINE uint64_t CountLeadingZeroBits64(uint64_t x) {
155   return CountLeadingZeroBits(x);
156 }
157 
158 #endif
159 
160 #endif
161 
CountLeadingZeroBitsSizeT(size_t x)162 ALWAYS_INLINE size_t CountLeadingZeroBitsSizeT(size_t x) {
163   return CountLeadingZeroBits(x);
164 }
165 
CountTrailingZeroBitsSizeT(size_t x)166 ALWAYS_INLINE size_t CountTrailingZeroBitsSizeT(size_t x) {
167   return CountTrailingZeroBits(x);
168 }
169 
170 // Returns the integer i such as 2^i <= n < 2^(i+1)
Log2Floor(uint32_t n)171 inline int Log2Floor(uint32_t n) {
172   return 31 - CountLeadingZeroBits(n);
173 }
174 
175 // Returns the integer i such as 2^(i-1) < n <= 2^i
Log2Ceiling(uint32_t n)176 inline int Log2Ceiling(uint32_t n) {
177   // When n == 0, we want the function to return -1.
178   // When n == 0, (n - 1) will underflow to 0xFFFFFFFF, which is
179   // why the statement below starts with (n ? 32 : -1).
180   return (n ? 32 : -1) - CountLeadingZeroBits(n - 1);
181 }
182 
183 }  // namespace bits
184 }  // namespace base
185 }  // namespace pdfium
186 
187 #endif  // THIRD_PARTY_BASE_BITS_H_
188