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