proxygen
Padded.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 <algorithm>
20 #include <cassert>
21 #include <cstdint>
22 #include <cstring>
23 #include <functional>
24 #include <iterator>
25 #include <limits>
26 #include <type_traits>
27 
28 #include <boost/iterator/iterator_adaptor.hpp>
29 
30 #include <folly/Portability.h>
31 #include <folly/Traits.h>
32 
44 namespace folly {
45 namespace padded {
46 
56 template <class T, size_t NS, class Enable = void>
57 class Node;
58 
59 namespace detail {
60 // Shortcut to avoid writing the long enable_if expression every time
61 template <class T, size_t NS, class Enable = void>
62 struct NodeValid;
63 template <class T, size_t NS>
64 struct NodeValid<
65  T,
66  NS,
67  typename std::enable_if<(
68  std::is_trivial<T>::value && sizeof(T) <= NS &&
69  NS % alignof(T) == 0)>::type> {
70  typedef void type;
71 };
72 } // namespace detail
73 
74 template <class T, size_t NS>
75 class Node<T, NS, typename detail::NodeValid<T, NS>::type> {
76  public:
77  typedef T value_type;
78  static constexpr size_t kNodeSize = NS;
79  static constexpr size_t kElementCount = NS / sizeof(T);
80  static constexpr size_t kPaddingBytes = NS % sizeof(T);
81 
82  T* data() {
83  return storage_.data;
84  }
85  const T* data() const {
86  return storage_.data;
87  }
88 
89  bool operator==(const Node& other) const {
90  return memcmp(data(), other.data(), sizeof(T) * kElementCount) == 0;
91  }
92  bool operator!=(const Node& other) const {
93  return !(*this == other);
94  }
95 
99  static constexpr size_t nodeCount(size_t n) {
100  return (n + kElementCount - 1) / kElementCount;
101  }
102 
107  static constexpr size_t paddedByteSize(size_t n) {
108  return nodeCount(n) * NS;
109  }
110 
117  static constexpr size_t paddingBytes(size_t n) {
118  return (
119  n ? (kPaddingBytes +
120  (kElementCount - 1 - (n - 1) % kElementCount) * sizeof(T))
121  : 0);
122  }
123 
131  static constexpr size_t unpaddedByteSize(size_t n) {
132  return paddedByteSize(n) - paddingBytes(n);
133  }
134 
135  private:
136  union Storage {
137  unsigned char bytes[NS];
138  T data[kElementCount];
139  } storage_;
140 };
141 
142 // We must define kElementCount and kPaddingBytes to work around a bug
143 // in gtest that odr-uses them.
144 template <class T, size_t NS>
145 constexpr size_t
147 template <class T, size_t NS>
148 constexpr size_t
150 template <class T, size_t NS>
151 constexpr size_t
153 
154 template <class Iter>
155 class Iterator;
156 
157 namespace detail {
158 
159 template <typename Void, typename Container, typename... Args>
161  static decltype(auto) go(Container& container, Args&&... args) {
162  using Value = typename Container::value_type;
163  return container.push_back(Value(std::forward<Args>(args)...));
164  }
165 };
166 
167 template <typename Container, typename... Args>
169  void_t<decltype(
170  std::declval<Container&>().emplace_back(std::declval<Args>()...))>,
171  Container,
172  Args...> {
173  static decltype(auto) go(Container& container, Args&&... args) {
174  return container.emplace_back(std::forward<Args>(args)...);
175  }
176 };
177 
178 template <typename Container, typename... Args>
180  Container& container,
181  Args&&... args) {
182  using impl = padded_emplace_back_or_push_back_<void, Container, Args...>;
183  return impl::go(container, std::forward<Args>(args)...);
184 }
185 
186 // Helper class to transfer the constness from From (a lvalue reference)
187 // and create a lvalue reference to To.
188 //
189 // TransferReferenceConstness<const string&, int> -> const int&
190 // TransferReferenceConstness<string&, int> -> int&
191 // TransferReferenceConstness<string&, const int> -> const int&
192 template <class From, class To, class Enable = void>
194 
195 template <class From, class To>
197  From,
198  To,
199  typename std::enable_if<std::is_const<
200  typename std::remove_reference<From>::type>::value>::type> {
201  typedef typename std::add_lvalue_reference<
203 };
204 
205 template <class From, class To>
207  From,
208  To,
209  typename std::enable_if<!std::is_const<
210  typename std::remove_reference<From>::type>::value>::type> {
212 };
213 
214 // Helper class template to define a base class for Iterator (below) and save
215 // typing.
216 template <class Iter>
217 struct IteratorBase {
218  typedef boost::iterator_adaptor<
219  // CRTC
221  // Base iterator type
222  Iter,
223  // Value type
224  typename std::iterator_traits<Iter>::value_type::value_type,
225  // Category or traversal
226  boost::use_default,
227  // Reference type
229  typename std::iterator_traits<Iter>::reference,
230  typename std::iterator_traits<Iter>::value_type::value_type>::type>
232 };
233 
234 } // namespace detail
235 
240 template <class Iter>
241 class Iterator : public detail::IteratorBase<Iter>::type {
243 
244  public:
245  typedef typename std::iterator_traits<Iter>::value_type Node;
246 
247  Iterator() : pos_(0) {}
248 
249  explicit Iterator(Iter base) : Super(base), pos_(0) {}
250 
251  // Return the current node and the position inside the node
252  const Node& node() const {
253  return *this->base_reference();
254  }
255  size_t pos() const {
256  return pos_;
257  }
258 
259  private:
260  typename Super::reference dereference() const {
261  return (*this->base_reference()).data()[pos_];
262  }
263 
264  bool equal(const Iterator& other) const {
265  return (
266  this->base_reference() == other.base_reference() && pos_ == other.pos_);
267  }
268 
269  void advance(typename Super::difference_type n) {
270  constexpr ssize_t elementCount = Node::kElementCount; // signed!
271  ssize_t newPos = pos_ + n;
272  if (newPos >= 0 && newPos < elementCount) {
273  pos_ = newPos;
274  return;
275  }
276  ssize_t nblocks = newPos / elementCount;
277  newPos %= elementCount;
278  if (newPos < 0) {
279  --nblocks; // negative
280  newPos += elementCount;
281  }
282  this->base_reference() += nblocks;
283  pos_ = newPos;
284  }
285 
286  void increment() {
287  if (++pos_ == Node::kElementCount) {
288  ++this->base_reference();
289  pos_ = 0;
290  }
291  }
292 
293  void decrement() {
294  if (--pos_ == -1) {
295  --this->base_reference();
296  pos_ = Node::kElementCount - 1;
297  }
298  }
299 
300  typename Super::difference_type distance_to(const Iterator& other) const {
301  constexpr ssize_t elementCount = Node::kElementCount; // signed!
302  ssize_t nblocks =
303  std::distance(this->base_reference(), other.base_reference());
304  return nblocks * elementCount + (other.pos_ - pos_);
305  }
306 
307  friend class boost::iterator_core_access;
308  ssize_t pos_; // signed for easier advance() implementation
309 };
310 
318 template <class Container>
321 }
322 
323 template <class Container>
326 }
327 
328 template <class Container>
330  return cbegin(c);
331 }
332 
333 template <class Container>
335  return cend(c);
336 }
337 
338 template <class Container>
341 }
342 
343 template <class Container>
346 }
347 
371 template <class Container>
372 class Adaptor {
373  public:
374  typedef typename Container::value_type Node;
375  typedef typename Node::value_type value_type;
376  typedef value_type& reference;
377  typedef const value_type& const_reference;
380  typedef typename const_iterator::difference_type difference_type;
381  typedef typename Container::size_type size_type;
382 
383  static constexpr size_t kElementsPerNode = Node::kElementCount;
384  // Constructors
385  Adaptor() : lastCount_(Node::kElementCount) {}
386  explicit Adaptor(Container c, size_t lastCount = Node::kElementCount)
387  : c_(std::move(c)), lastCount_(lastCount) {}
388  explicit Adaptor(size_t n, const value_type& value = value_type())
389  : c_(Node::nodeCount(n), fullNode(value)) {
390  const auto count = n % Node::kElementCount;
391  lastCount_ = count != 0 ? count : Node::kElementCount;
392  }
393 
394  Adaptor(const Adaptor&) = default;
395  Adaptor& operator=(const Adaptor&) = default;
397  : c_(std::move(other.c_)), lastCount_(other.lastCount_) {
398  other.lastCount_ = Node::kElementCount;
399  }
401  if (this != &other) {
402  c_ = std::move(other.c_);
403  lastCount_ = other.lastCount_;
404  other.lastCount_ = Node::kElementCount;
405  }
406  return *this;
407  }
408 
409  // Iterators
410  const_iterator cbegin() const {
411  return const_iterator(c_.begin());
412  }
413  const_iterator cend() const {
414  auto it = const_iterator(c_.end());
415  if (lastCount_ != Node::kElementCount) {
416  it -= (Node::kElementCount - lastCount_);
417  }
418  return it;
419  }
420  const_iterator begin() const {
421  return cbegin();
422  }
423  const_iterator end() const {
424  return cend();
425  }
426  iterator begin() {
427  return iterator(c_.begin());
428  }
429  iterator end() {
430  auto it = iterator(c_.end());
431  if (lastCount_ != Node::kElementCount) {
432  it -= difference_type(Node::kElementCount - lastCount_);
433  }
434  return it;
435  }
436  void swap(Adaptor& other) {
437  using std::swap;
438  swap(c_, other.c_);
439  swap(lastCount_, other.lastCount_);
440  }
441  bool empty() const {
442  return c_.empty();
443  }
444  size_type size() const {
445  return (
446  c_.empty() ? 0 : (c_.size() - 1) * Node::kElementCount + lastCount_);
447  }
448  size_type max_size() const {
449  return (
450  (c_.max_size() <=
451  std::numeric_limits<size_type>::max() / Node::kElementCount)
452  ? c_.max_size() * Node::kElementCount
454  }
455 
456  const value_type& front() const {
457  assert(!empty());
458  return c_.front().data()[0];
459  }
460  value_type& front() {
461  assert(!empty());
462  return c_.front().data()[0];
463  }
464 
465  const value_type& back() const {
466  assert(!empty());
467  return c_.back().data()[lastCount_ - 1];
468  }
469  value_type& back() {
470  assert(!empty());
471  return c_.back().data()[lastCount_ - 1];
472  }
473 
474  template <typename... Args>
475  void emplace_back(Args&&... args) {
476  new (allocate_back()) value_type(std::forward<Args>(args)...);
477  }
478 
479  void push_back(value_type x) {
480  emplace_back(std::move(x));
481  }
482 
483  void pop_back() {
484  assert(!empty());
485  if (--lastCount_ == 0) {
486  c_.pop_back();
487  lastCount_ = Node::kElementCount;
488  }
489  }
490 
491  void clear() {
492  c_.clear();
493  lastCount_ = Node::kElementCount;
494  }
495 
496  void reserve(size_type n) {
497  assert(n >= 0);
498  c_.reserve(Node::nodeCount(n));
499  }
500 
501  size_type capacity() const {
502  return c_.capacity() * Node::kElementCount;
503  }
504 
505  const value_type& operator[](size_type idx) const {
506  return c_[idx / Node::kElementCount].data()[idx % Node::kElementCount];
507  }
508  value_type& operator[](size_type idx) {
509  return c_[idx / Node::kElementCount].data()[idx % Node::kElementCount];
510  }
511 
517  std::pair<Container, size_t> move() {
518  std::pair<Container, size_t> p(std::move(c_), lastCount_);
519  lastCount_ = Node::kElementCount;
520  return std::move(p);
521  }
522 
527  std::pair<const Container&, size_t> peek() const {
528  return std::make_pair(std::cref(c_), lastCount_);
529  }
530 
531  void padToFullNode(const value_type& padValue) {
532  // the if is necessary because c_ may be empty so we can't call c_.back()
533  if (lastCount_ != Node::kElementCount) {
534  auto last = c_.back().data();
535  std::fill(last + lastCount_, last + Node::kElementCount, padValue);
536  lastCount_ = Node::kElementCount;
537  }
538  }
539 
540  private:
541  value_type* allocate_back() {
542  if (lastCount_ == Node::kElementCount) {
544  lastCount_ = 0;
545  }
546  return &c_.back().data()[lastCount_++];
547  }
548 
549  static Node fullNode(const value_type& value) {
550  Node n;
551  std::fill(n.data(), n.data() + kElementsPerNode, value);
552  return n;
553  }
554  Container c_; // container of Nodes
555  size_t lastCount_; // number of elements in last Node
556 };
557 
558 } // namespace padded
559 } // namespace folly
std::pair< Container, size_t > move()
Definition: Padded.h:517
Definition: InvokeTest.cpp:58
value_type & front()
Definition: Padded.h:460
void emplace_back(Args &&...args)
Definition: Padded.h:475
Iterator< typename Container::iterator > iterator
Definition: Padded.h:378
bool equal(const Iterator &other) const
Definition: Padded.h:264
value_type * allocate_back()
Definition: Padded.h:541
LogLevel max
Definition: LogLevel.cpp:31
Node::value_type value_type
Definition: Padded.h:375
const_iterator cend() const
Definition: Padded.h:413
size_t pos() const
Definition: Padded.h:255
Iterator< typename Container::const_iterator > begin(const Container &c)
Definition: Padded.h:329
const value_type & const_reference
Definition: Padded.h:377
const value_type & operator[](size_type idx) const
Definition: Padded.h:505
PskType type
Container::value_type Node
Definition: Padded.h:374
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
Iterator(Iter base)
Definition: Padded.h:249
value_type & back()
Definition: Padded.h:469
value_type & operator[](size_type idx)
Definition: Padded.h:508
STL namespace.
folly::std T
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void advance(typename Super::difference_type n)
Definition: Padded.h:269
requires E e noexcept(noexcept(s.error(std::move(e))))
Iterator< typename Container::const_iterator > const_iterator
Definition: Padded.h:379
const_iterator begin() const
Definition: Padded.h:420
static Count c_
Definition: HazptrTest.cpp:94
void clear() noexcept
Definition: HazptrTest.cpp:63
std::iterator_traits< Iter >::value_type Node
Definition: Padded.h:245
size_type max_size() const
Definition: Padded.h:448
Adaptor(Container c, size_t lastCount=Node::kElementCount)
Definition: Padded.h:386
size_type size() const
Definition: Padded.h:444
const value_type & front() const
Definition: Padded.h:456
static Node fullNode(const value_type &value)
Definition: Padded.h:549
void reserve(size_type n)
Definition: Padded.h:496
void swap(Adaptor &other)
Definition: Padded.h:436
void push_back(value_type x)
Definition: Padded.h:479
constexpr auto empty(C const &c) -> decltype(c.empty())
Definition: Access.h:55
def Iter(n, format, sep='')
Adaptor(Adaptor &&other) noexcept
Definition: Padded.h:396
boost::iterator_adaptor< Iterator< Iter >, Iter, typename std::iterator_traits< Iter >::value_type::value_type, boost::use_default, typename detail::TransferReferenceConstness< typename std::iterator_traits< Iter >::reference, typename std::iterator_traits< Iter >::value_type::value_type >::type > type
Definition: Padded.h:231
bool Value(const T &value, M matcher)
const_iterator cbegin() const
Definition: Padded.h:410
Super::reference dereference() const
Definition: Padded.h:260
constexpr auto data(C &c) -> decltype(c.data())
Definition: Access.h:71
iterator begin()
Definition: Padded.h:426
const value_type & back() const
Definition: Padded.h:465
size_type capacity() const
Definition: Padded.h:501
value_type & reference
Definition: Padded.h:376
int * count
void swap(exception_wrapper &a, exception_wrapper &b) noexcept
detail::IteratorBase< Iter >::type Super
Definition: Padded.h:242
void padToFullNode(const value_type &padValue)
Definition: Padded.h:531
std::pair< const Container &, size_t > peek() const
Definition: Padded.h:527
const Node & node() const
Definition: Padded.h:252
Super::difference_type distance_to(const Iterator &other) const
Definition: Padded.h:300
Iterator< typename Container::iterator > begin(Container &c)
Definition: Padded.h:339
Container::size_type size_type
Definition: Padded.h:381
iterator end()
Definition: Padded.h:429
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
const_iterator::difference_type difference_type
Definition: Padded.h:380
Adaptor(size_t n, const value_type &value=value_type())
Definition: Padded.h:388
const_iterator end() const
Definition: Padded.h:423
void swap(SwapTrackingAlloc< T > &, SwapTrackingAlloc< T > &)
Definition: F14TestUtil.h:414
Iterator< typename Container::const_iterator > end(const Container &c)
Definition: Padded.h:334
char c
Adaptor & operator=(Adaptor &&other)
Definition: Padded.h:400
decltype(auto) padded_emplace_back_or_push_back(Container &container, Args &&...args)
Definition: Padded.h:179
Iterator< typename Container::iterator > end(Container &c)
Definition: Padded.h:344
Iterator< typename Container::const_iterator > cbegin(const Container &c)
Definition: Padded.h:319
Iterator< typename Container::const_iterator > cend(const Container &c)
Definition: Padded.h:324
bool empty() const
Definition: Padded.h:441