proxygen
Bits.h
Go to the documentation of this file.
1 /*
2  * Copyright 2012-present Facebook, Inc.
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 
17 #pragma once
18 
19 #include <cstddef>
20 #include <limits>
21 #include <type_traits>
22 
23 #include <glog/logging.h>
24 
25 #include <folly/Portability.h>
26 #include <folly/Range.h>
27 #include <folly/lang/Bits.h>
28 
29 namespace folly {
30 
31 template <class T>
32 struct UnalignedNoASan : public Unaligned<T> {};
33 
34 // As a general rule, bit operations work on unsigned values only;
35 // right-shift is arithmetic for signed values, and that can lead to
36 // unpleasant bugs.
37 
38 namespace detail {
39 
45 template <class T, class Enable = void>
46 struct BitsTraits;
47 
48 // Partial specialization for Unaligned<T>, where T is unsigned integral
49 // loadRMW is the same as load, but it indicates that it loads for a
50 // read-modify-write operation (we write back the bits we won't change);
51 // silence the GCC warning in that case.
52 template <class T>
53 struct BitsTraits<
54  Unaligned<T>,
55  typename std::enable_if<(std::is_integral<T>::value)>::type> {
56  typedef T UnderlyingType;
57  static T load(const Unaligned<T>& x) {
58  return x.value;
59  }
60  static void store(Unaligned<T>& x, T v) {
61  x.value = v;
62  }
63  static T loadRMW(const Unaligned<T>& x) {
65  FOLLY_GNU_DISABLE_WARNING("-Wuninitialized")
66  FOLLY_GCC_DISABLE_WARNING("-Wmaybe-uninitialized")
67  return x.value;
69  }
70 };
71 
72 // Special version that allows one to disable address sanitizer on demand.
73 template <class T>
74 struct BitsTraits<
76  typename std::enable_if<(std::is_integral<T>::value)>::type> {
77  typedef T UnderlyingType;
79  return x.value;
80  }
83  x.value = v;
84  }
88  FOLLY_GNU_DISABLE_WARNING("-Wuninitialized")
89  FOLLY_GCC_DISABLE_WARNING("-Wmaybe-uninitialized")
90  return x.value;
92  }
93 };
94 
95 // Partial specialization for T, where T is unsigned integral
96 template <class T>
97 struct BitsTraits<
98  T,
99  typename std::enable_if<(std::is_integral<T>::value)>::type> {
100  typedef T UnderlyingType;
101  static T load(const T& x) {
102  return x;
103  }
104  static void store(T& x, T v) {
105  x = v;
106  }
107  static T loadRMW(const T& x) {
109  FOLLY_GNU_DISABLE_WARNING("-Wuninitialized")
110  FOLLY_GCC_DISABLE_WARNING("-Wmaybe-uninitialized")
111  return x;
113  }
114 };
115 
116 } // namespace detail
117 
124 template <class T, class Traits = detail::BitsTraits<T>>
125 struct Bits {
126  typedef typename Traits::UnderlyingType UnderlyingType;
127  typedef T type;
128  static_assert(sizeof(T) == sizeof(UnderlyingType), "Size mismatch");
129 
133  static constexpr size_t bitsPerBlock = std::numeric_limits<
135 
139  static constexpr size_t blockIndex(size_t bit) {
140  return bit / bitsPerBlock;
141  }
142 
146  static constexpr size_t bitOffset(size_t bit) {
147  return bit % bitsPerBlock;
148  }
149 
153  static constexpr size_t blockCount(size_t nbits) {
154  return nbits / bitsPerBlock + (nbits % bitsPerBlock != 0);
155  }
156 
160  static void set(T* p, size_t bit);
161 
165  static void clear(T* p, size_t bit);
166 
170  static bool test(const T* p, size_t bit);
171 
179  static void set(T* p, size_t bitStart, size_t count, UnderlyingType value);
180 
185  static UnderlyingType get(const T* p, size_t bitStart, size_t count);
186 
190  static size_t count(const T* begin, const T* end);
191 
192  private:
193  // Same as set, assumes all bits are in the same block.
194  // (bitStart < sizeof(T) * 8, bitStart + count <= sizeof(T) * 8)
195  static void
196  innerSet(T* p, size_t bitStart, size_t count, UnderlyingType value);
197 
198  // Same as get, assumes all bits are in the same block.
199  // (bitStart < sizeof(T) * 8, bitStart + count <= sizeof(T) * 8)
200  static UnderlyingType innerGet(const T* p, size_t bitStart, size_t count);
201 
202  static constexpr UnderlyingType zero = UnderlyingType(0);
203  static constexpr UnderlyingType one = UnderlyingType(1);
204 
206  static constexpr UnderlyingType ones(size_t count) {
207  return (count < bitsPerBlock)
208  ? static_cast<UnderlyingType>((UnsignedType{1} << count) - 1)
209  : ~zero;
210  }
211 };
212 
213 // gcc 4.8 needs more -Wmaybe-uninitialized tickling, as it propagates the
214 // taint upstream from loadRMW
216 FOLLY_GNU_DISABLE_WARNING("-Wuninitialized")
217 FOLLY_GCC_DISABLE_WARNING("-Wmaybe-uninitialized")
218 
219 template <class T, class Traits>
220 inline void Bits<T, Traits>::set(T* p, size_t bit) {
221  T& block = p[blockIndex(bit)];
222  Traits::store(block, Traits::loadRMW(block) | (one << bitOffset(bit)));
223 }
224 
225 template <class T, class Traits>
226 inline void Bits<T, Traits>::clear(T* p, size_t bit) {
227  T& block = p[blockIndex(bit)];
228  Traits::store(block, Traits::loadRMW(block) & ~(one << bitOffset(bit)));
229 }
230 
231 template <class T, class Traits>
233  T* p,
234  size_t bitStart,
235  size_t count,
236  UnderlyingType value) {
237  DCHECK_LE(count, sizeof(UnderlyingType) * 8);
238  size_t cut = bitsPerBlock - count;
239  if (cut != 8 * sizeof(UnderlyingType)) {
240  using U = typename std::make_unsigned<UnderlyingType>::type;
241  DCHECK_EQ(value, UnderlyingType(U(value) << cut) >> cut);
242  }
243  size_t idx = blockIndex(bitStart);
244  size_t offset = bitOffset(bitStart);
246  value &= ones(count);
247  }
248  if (offset + count <= bitsPerBlock) {
249  innerSet(p + idx, offset, count, value);
250  } else {
251  size_t countInThisBlock = bitsPerBlock - offset;
252  size_t countInNextBlock = count - countInThisBlock;
253 
254  UnderlyingType thisBlock = UnderlyingType(value & ones(countInThisBlock));
255  UnderlyingType nextBlock = UnderlyingType(value >> countInThisBlock);
257  nextBlock &= ones(countInNextBlock);
258  }
259  innerSet(p + idx, offset, countInThisBlock, thisBlock);
260  innerSet(p + idx + 1, 0, countInNextBlock, nextBlock);
261  }
262 }
263 
264 template <class T, class Traits>
266  T* p,
267  size_t offset,
268  size_t count,
269  UnderlyingType value) {
270  // Mask out bits and set new value
271  UnderlyingType v = Traits::loadRMW(*p);
272  v &= ~(ones(count) << offset);
273  v |= (value << offset);
274  Traits::store(*p, v);
275 }
276 
278 
279 template <class T, class Traits>
280 inline bool Bits<T, Traits>::test(const T* p, size_t bit) {
281  return Traits::load(p[blockIndex(bit)]) & (one << bitOffset(bit));
282 }
283 
284 template <class T, class Traits>
285 inline auto Bits<T, Traits>::get(const T* p, size_t bitStart, size_t count)
286  -> UnderlyingType {
287  if (count == 0) {
288  return UnderlyingType{};
289  }
290 
291  DCHECK_LE(count, sizeof(UnderlyingType) * 8);
292  size_t idx = blockIndex(bitStart);
293  size_t offset = bitOffset(bitStart);
294  UnderlyingType ret;
295  if (offset + count <= bitsPerBlock) {
296  ret = innerGet(p + idx, offset, count);
297  } else {
298  size_t countInThisBlock = bitsPerBlock - offset;
299  size_t countInNextBlock = count - countInThisBlock;
300  UnderlyingType thisBlockValue = innerGet(p + idx, offset, countInThisBlock);
301  UnderlyingType nextBlockValue = innerGet(p + idx + 1, 0, countInNextBlock);
302  ret = (nextBlockValue << countInThisBlock) | thisBlockValue;
303  }
305  size_t emptyBits = bitsPerBlock - count;
306  ret <<= emptyBits;
307  ret >>= emptyBits;
308  }
309  return ret;
310 }
311 
312 template <class T, class Traits>
313 inline auto Bits<T, Traits>::innerGet(const T* p, size_t offset, size_t count)
314  -> UnderlyingType {
315  return (Traits::load(*p) >> offset) & ones(count);
316 }
317 
318 template <class T, class Traits>
319 inline size_t Bits<T, Traits>::count(const T* begin, const T* end) {
320  size_t n = 0;
321  for (; begin != end; ++begin) {
322  n += popcount(Traits::load(*begin));
323  }
324  return n;
325 }
326 
327 } // namespace folly
constexpr unsigned int popcount(T const v)
Definition: Bits.h:130
Definition: InvokeTest.cpp:58
static T load(const T &x)
Definition: Bits.h:101
static T FOLLY_DISABLE_ADDRESS_SANITIZER load(const UnalignedNoASan< T > &x)
Definition: Bits.h:78
#define FOLLY_GNU_DISABLE_WARNING(warningName)
Definition: Portability.h:180
#define FOLLY_DISABLE_ADDRESS_SANITIZER
Definition: CPortability.h:99
#define FOLLY_POP_WARNING
Definition: Portability.h:179
auto v
static void set(T *p, size_t bit)
Definition: Bits.h:220
#define FOLLY_PUSH_WARNING
Definition: Portability.h:178
static UnderlyingType get(const T *p, size_t bitStart, size_t count)
Definition: Bits.h:285
PskType type
static constexpr UnderlyingType ones(size_t count)
Definition: Bits.h:206
static uint64_t test(std::string name, bool fc_, bool dedicated_, bool tc_, bool syncops_, uint64_t base)
const int x
static constexpr size_t blockCount(size_t nbits)
Definition: Bits.h:153
STL namespace.
auto begin(TestAdlIterable &instance)
Definition: ForeachTest.cpp:56
folly::std T
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
def load()
Definition: deadlock.py:441
static UnderlyingType innerGet(const T *p, size_t bitStart, size_t count)
Definition: Bits.h:313
static void innerSet(T *p, size_t bitStart, size_t count, UnderlyingType value)
Definition: Bits.h:265
typename std::make_unsigned< UnderlyingType >::type UnsignedType
Definition: Bits.h:205
Traits::UnderlyingType UnderlyingType
Definition: Bits.h:126
static T loadRMW(const T &x)
Definition: Bits.h:107
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
static void FOLLY_DISABLE_ADDRESS_SANITIZER store(UnalignedNoASan< T > &x, T v)
Definition: Bits.h:82
static size_t count(const T *begin, const T *end)
Definition: Bits.h:319
T type
Definition: Bits.h:127
static void clear(T *p, size_t bit)
Definition: Bits.h:226
static bool test(const T *p, size_t bit)
Definition: Bits.h:280
static const char *const value
Definition: Conv.cpp:50
static void store(Unaligned< T > &x, T v)
Definition: Bits.h:60
int * count
static T load(const Unaligned< T > &x)
Definition: Bits.h:57
static constexpr size_t blockIndex(size_t bit)
Definition: Bits.h:139
static T loadRMW(const Unaligned< T > &x)
Definition: Bits.h:63
static T FOLLY_DISABLE_ADDRESS_SANITIZER loadRMW(const UnalignedNoASan< T > &x)
Definition: Bits.h:86
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
static constexpr size_t bitOffset(size_t bit)
Definition: Bits.h:146
static void store(T &x, T v)
Definition: Bits.h:104
#define FOLLY_GCC_DISABLE_WARNING(warningName)
Definition: Portability.h:181