Padded.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  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. #pragma once
  17. #include <algorithm>
  18. #include <cassert>
  19. #include <cstdint>
  20. #include <cstring>
  21. #include <functional>
  22. #include <iterator>
  23. #include <limits>
  24. #include <type_traits>
  25. #include <boost/iterator/iterator_adaptor.hpp>
  26. #include <folly/Portability.h>
  27. #include <folly/Traits.h>
  28. /**
  29. * Code that aids in storing data aligned on block (possibly cache-line)
  30. * boundaries, perhaps with padding.
  31. *
  32. * Class Node represents one block. Given an iterator to a container of
  33. * Node, class Iterator encapsulates an iterator to the underlying elements.
  34. * Adaptor converts a sequence of Node into a sequence of underlying elements
  35. * (not fully compatible with STL container requirements, see comments
  36. * near the Node class declaration).
  37. */
  38. namespace folly {
  39. namespace padded {
  40. /**
  41. * A Node is a fixed-size container of as many objects of type T as would
  42. * fit in a region of memory of size NS. The last NS % sizeof(T)
  43. * bytes are ignored and uninitialized.
  44. *
  45. * Node only works for trivial types, which is usually not a concern. This
  46. * is intentional: Node itself is trivial, which means that it can be
  47. * serialized / deserialized using a simple memcpy.
  48. */
  49. template <class T, size_t NS, class Enable = void>
  50. class Node;
  51. namespace detail {
  52. // Shortcut to avoid writing the long enable_if expression every time
  53. template <class T, size_t NS, class Enable = void>
  54. struct NodeValid;
  55. template <class T, size_t NS>
  56. struct NodeValid<
  57. T,
  58. NS,
  59. typename std::enable_if<(
  60. std::is_trivial<T>::value && sizeof(T) <= NS &&
  61. NS % alignof(T) == 0)>::type> {
  62. typedef void type;
  63. };
  64. } // namespace detail
  65. template <class T, size_t NS>
  66. class Node<T, NS, typename detail::NodeValid<T, NS>::type> {
  67. public:
  68. typedef T value_type;
  69. static constexpr size_t kNodeSize = NS;
  70. static constexpr size_t kElementCount = NS / sizeof(T);
  71. static constexpr size_t kPaddingBytes = NS % sizeof(T);
  72. T* data() {
  73. return storage_.data;
  74. }
  75. const T* data() const {
  76. return storage_.data;
  77. }
  78. bool operator==(const Node& other) const {
  79. return memcmp(data(), other.data(), sizeof(T) * kElementCount) == 0;
  80. }
  81. bool operator!=(const Node& other) const {
  82. return !(*this == other);
  83. }
  84. /**
  85. * Return the number of nodes needed to represent n values. Rounds up.
  86. */
  87. static constexpr size_t nodeCount(size_t n) {
  88. return (n + kElementCount - 1) / kElementCount;
  89. }
  90. /**
  91. * Return the total byte size needed to represent n values, rounded up
  92. * to the nearest full node.
  93. */
  94. static constexpr size_t paddedByteSize(size_t n) {
  95. return nodeCount(n) * NS;
  96. }
  97. /**
  98. * Return the number of bytes used for padding n values.
  99. * Note that, even if n is a multiple of kElementCount, this may
  100. * return non-zero if kPaddingBytes != 0, as the padding at the end of
  101. * the last node is not included in the result.
  102. */
  103. static constexpr size_t paddingBytes(size_t n) {
  104. return (
  105. n ? (kPaddingBytes +
  106. (kElementCount - 1 - (n - 1) % kElementCount) * sizeof(T))
  107. : 0);
  108. }
  109. /**
  110. * Return the minimum byte size needed to represent n values.
  111. * Does not round up. Even if n is a multiple of kElementCount, this
  112. * may be different from paddedByteSize() if kPaddingBytes != 0, as
  113. * the padding at the end of the last node is not included in the result.
  114. * Note that the calculation below works for n=0 correctly (returns 0).
  115. */
  116. static constexpr size_t unpaddedByteSize(size_t n) {
  117. return paddedByteSize(n) - paddingBytes(n);
  118. }
  119. private:
  120. union Storage {
  121. unsigned char bytes[NS];
  122. T data[kElementCount];
  123. } storage_;
  124. };
  125. // We must define kElementCount and kPaddingBytes to work around a bug
  126. // in gtest that odr-uses them.
  127. template <class T, size_t NS>
  128. constexpr size_t
  129. Node<T, NS, typename detail::NodeValid<T, NS>::type>::kNodeSize;
  130. template <class T, size_t NS>
  131. constexpr size_t
  132. Node<T, NS, typename detail::NodeValid<T, NS>::type>::kElementCount;
  133. template <class T, size_t NS>
  134. constexpr size_t
  135. Node<T, NS, typename detail::NodeValid<T, NS>::type>::kPaddingBytes;
  136. template <class Iter>
  137. class Iterator;
  138. namespace detail {
  139. template <typename Void, typename Container, typename... Args>
  140. struct padded_emplace_back_or_push_back_ {
  141. static decltype(auto) go(Container& container, Args&&... args) {
  142. using Value = typename Container::value_type;
  143. return container.push_back(Value(std::forward<Args>(args)...));
  144. }
  145. };
  146. template <typename Container, typename... Args>
  147. struct padded_emplace_back_or_push_back_<
  148. void_t<decltype(
  149. std::declval<Container&>().emplace_back(std::declval<Args>()...))>,
  150. Container,
  151. Args...> {
  152. static decltype(auto) go(Container& container, Args&&... args) {
  153. return container.emplace_back(std::forward<Args>(args)...);
  154. }
  155. };
  156. template <typename Container, typename... Args>
  157. decltype(auto) padded_emplace_back_or_push_back(
  158. Container& container,
  159. Args&&... args) {
  160. using impl = padded_emplace_back_or_push_back_<void, Container, Args...>;
  161. return impl::go(container, std::forward<Args>(args)...);
  162. }
  163. // Helper class to transfer the constness from From (a lvalue reference)
  164. // and create a lvalue reference to To.
  165. //
  166. // TransferReferenceConstness<const string&, int> -> const int&
  167. // TransferReferenceConstness<string&, int> -> int&
  168. // TransferReferenceConstness<string&, const int> -> const int&
  169. template <class From, class To, class Enable = void>
  170. struct TransferReferenceConstness;
  171. template <class From, class To>
  172. struct TransferReferenceConstness<
  173. From,
  174. To,
  175. typename std::enable_if<std::is_const<
  176. typename std::remove_reference<From>::type>::value>::type> {
  177. typedef typename std::add_lvalue_reference<
  178. typename std::add_const<To>::type>::type type;
  179. };
  180. template <class From, class To>
  181. struct TransferReferenceConstness<
  182. From,
  183. To,
  184. typename std::enable_if<!std::is_const<
  185. typename std::remove_reference<From>::type>::value>::type> {
  186. typedef typename std::add_lvalue_reference<To>::type type;
  187. };
  188. // Helper class template to define a base class for Iterator (below) and save
  189. // typing.
  190. template <class Iter>
  191. struct IteratorBase {
  192. typedef boost::iterator_adaptor<
  193. // CRTC
  194. Iterator<Iter>,
  195. // Base iterator type
  196. Iter,
  197. // Value type
  198. typename std::iterator_traits<Iter>::value_type::value_type,
  199. // Category or traversal
  200. boost::use_default,
  201. // Reference type
  202. typename detail::TransferReferenceConstness<
  203. typename std::iterator_traits<Iter>::reference,
  204. typename std::iterator_traits<Iter>::value_type::value_type>::type>
  205. type;
  206. };
  207. } // namespace detail
  208. /**
  209. * Wrapper around iterators to Node to return iterators to the underlying
  210. * node elements.
  211. */
  212. template <class Iter>
  213. class Iterator : public detail::IteratorBase<Iter>::type {
  214. typedef typename detail::IteratorBase<Iter>::type Super;
  215. public:
  216. typedef typename std::iterator_traits<Iter>::value_type Node;
  217. Iterator() : pos_(0) {}
  218. explicit Iterator(Iter base) : Super(base), pos_(0) {}
  219. // Return the current node and the position inside the node
  220. const Node& node() const {
  221. return *this->base_reference();
  222. }
  223. size_t pos() const {
  224. return pos_;
  225. }
  226. private:
  227. typename Super::reference dereference() const {
  228. return (*this->base_reference()).data()[pos_];
  229. }
  230. bool equal(const Iterator& other) const {
  231. return (
  232. this->base_reference() == other.base_reference() && pos_ == other.pos_);
  233. }
  234. void advance(typename Super::difference_type n) {
  235. constexpr ssize_t elementCount = Node::kElementCount; // signed!
  236. ssize_t newPos = pos_ + n;
  237. if (newPos >= 0 && newPos < elementCount) {
  238. pos_ = newPos;
  239. return;
  240. }
  241. ssize_t nblocks = newPos / elementCount;
  242. newPos %= elementCount;
  243. if (newPos < 0) {
  244. --nblocks; // negative
  245. newPos += elementCount;
  246. }
  247. this->base_reference() += nblocks;
  248. pos_ = newPos;
  249. }
  250. void increment() {
  251. if (++pos_ == Node::kElementCount) {
  252. ++this->base_reference();
  253. pos_ = 0;
  254. }
  255. }
  256. void decrement() {
  257. if (--pos_ == -1) {
  258. --this->base_reference();
  259. pos_ = Node::kElementCount - 1;
  260. }
  261. }
  262. typename Super::difference_type distance_to(const Iterator& other) const {
  263. constexpr ssize_t elementCount = Node::kElementCount; // signed!
  264. ssize_t nblocks =
  265. std::distance(this->base_reference(), other.base_reference());
  266. return nblocks * elementCount + (other.pos_ - pos_);
  267. }
  268. friend class boost::iterator_core_access;
  269. ssize_t pos_; // signed for easier advance() implementation
  270. };
  271. /**
  272. * Given a container to Node, return iterators to the first element in
  273. * the first Node / one past the last element in the last Node.
  274. * Note that the last node is assumed to be full; if that's not the case,
  275. * subtract from end() as appropriate.
  276. */
  277. template <class Container>
  278. Iterator<typename Container::const_iterator> cbegin(const Container& c) {
  279. return Iterator<typename Container::const_iterator>(std::begin(c));
  280. }
  281. template <class Container>
  282. Iterator<typename Container::const_iterator> cend(const Container& c) {
  283. return Iterator<typename Container::const_iterator>(std::end(c));
  284. }
  285. template <class Container>
  286. Iterator<typename Container::const_iterator> begin(const Container& c) {
  287. return cbegin(c);
  288. }
  289. template <class Container>
  290. Iterator<typename Container::const_iterator> end(const Container& c) {
  291. return cend(c);
  292. }
  293. template <class Container>
  294. Iterator<typename Container::iterator> begin(Container& c) {
  295. return Iterator<typename Container::iterator>(std::begin(c));
  296. }
  297. template <class Container>
  298. Iterator<typename Container::iterator> end(Container& c) {
  299. return Iterator<typename Container::iterator>(std::end(c));
  300. }
  301. /**
  302. * Adaptor around a STL sequence container.
  303. *
  304. * Converts a sequence of Node into a sequence of its underlying elements
  305. * (with enough functionality to make it useful, although it's not fully
  306. * compatible with the STL containre requiremenets, see below).
  307. *
  308. * Provides iterators (of the same category as those of the underlying
  309. * container), size(), front(), back(), push_back(), pop_back(), and const /
  310. * non-const versions of operator[] (if the underlying container supports
  311. * them). Does not provide push_front() / pop_front() or arbitrary insert /
  312. * emplace / erase. Also provides reserve() / capacity() if supported by the
  313. * underlying container.
  314. *
  315. * Yes, it's called Adaptor, not Adapter, as that's the name used by the STL
  316. * and by boost. Deal with it.
  317. *
  318. * Internally, we hold a container of Node and the number of elements in
  319. * the last block. We don't keep empty blocks, so the number of elements in
  320. * the last block is always between 1 and Node::kElementCount (inclusive).
  321. * (this is true if the container is empty as well to make push_back() simpler,
  322. * see the implementation of the size() method for details).
  323. */
  324. template <class Container>
  325. class Adaptor {
  326. public:
  327. typedef typename Container::value_type Node;
  328. typedef typename Node::value_type value_type;
  329. typedef value_type& reference;
  330. typedef const value_type& const_reference;
  331. typedef Iterator<typename Container::iterator> iterator;
  332. typedef Iterator<typename Container::const_iterator> const_iterator;
  333. typedef typename const_iterator::difference_type difference_type;
  334. typedef typename Container::size_type size_type;
  335. static constexpr size_t kElementsPerNode = Node::kElementCount;
  336. // Constructors
  337. Adaptor() : lastCount_(Node::kElementCount) {}
  338. explicit Adaptor(Container c, size_t lastCount = Node::kElementCount)
  339. : c_(std::move(c)), lastCount_(lastCount) {}
  340. explicit Adaptor(size_t n, const value_type& value = value_type())
  341. : c_(Node::nodeCount(n), fullNode(value)) {
  342. const auto count = n % Node::kElementCount;
  343. lastCount_ = count != 0 ? count : Node::kElementCount;
  344. }
  345. Adaptor(const Adaptor&) = default;
  346. Adaptor& operator=(const Adaptor&) = default;
  347. Adaptor(Adaptor&& other) noexcept
  348. : c_(std::move(other.c_)), lastCount_(other.lastCount_) {
  349. other.lastCount_ = Node::kElementCount;
  350. }
  351. Adaptor& operator=(Adaptor&& other) {
  352. if (this != &other) {
  353. c_ = std::move(other.c_);
  354. lastCount_ = other.lastCount_;
  355. other.lastCount_ = Node::kElementCount;
  356. }
  357. return *this;
  358. }
  359. // Iterators
  360. const_iterator cbegin() const {
  361. return const_iterator(c_.begin());
  362. }
  363. const_iterator cend() const {
  364. auto it = const_iterator(c_.end());
  365. if (lastCount_ != Node::kElementCount) {
  366. it -= (Node::kElementCount - lastCount_);
  367. }
  368. return it;
  369. }
  370. const_iterator begin() const {
  371. return cbegin();
  372. }
  373. const_iterator end() const {
  374. return cend();
  375. }
  376. iterator begin() {
  377. return iterator(c_.begin());
  378. }
  379. iterator end() {
  380. auto it = iterator(c_.end());
  381. if (lastCount_ != Node::kElementCount) {
  382. it -= difference_type(Node::kElementCount - lastCount_);
  383. }
  384. return it;
  385. }
  386. void swap(Adaptor& other) {
  387. using std::swap;
  388. swap(c_, other.c_);
  389. swap(lastCount_, other.lastCount_);
  390. }
  391. bool empty() const {
  392. return c_.empty();
  393. }
  394. size_type size() const {
  395. return (
  396. c_.empty() ? 0 : (c_.size() - 1) * Node::kElementCount + lastCount_);
  397. }
  398. size_type max_size() const {
  399. return (
  400. (c_.max_size() <=
  401. std::numeric_limits<size_type>::max() / Node::kElementCount)
  402. ? c_.max_size() * Node::kElementCount
  403. : std::numeric_limits<size_type>::max());
  404. }
  405. const value_type& front() const {
  406. assert(!empty());
  407. return c_.front().data()[0];
  408. }
  409. value_type& front() {
  410. assert(!empty());
  411. return c_.front().data()[0];
  412. }
  413. const value_type& back() const {
  414. assert(!empty());
  415. return c_.back().data()[lastCount_ - 1];
  416. }
  417. value_type& back() {
  418. assert(!empty());
  419. return c_.back().data()[lastCount_ - 1];
  420. }
  421. template <typename... Args>
  422. void emplace_back(Args&&... args) {
  423. new (allocate_back()) value_type(std::forward<Args>(args)...);
  424. }
  425. void push_back(value_type x) {
  426. emplace_back(std::move(x));
  427. }
  428. void pop_back() {
  429. assert(!empty());
  430. if (--lastCount_ == 0) {
  431. c_.pop_back();
  432. lastCount_ = Node::kElementCount;
  433. }
  434. }
  435. void clear() {
  436. c_.clear();
  437. lastCount_ = Node::kElementCount;
  438. }
  439. void reserve(size_type n) {
  440. assert(n >= 0);
  441. c_.reserve(Node::nodeCount(n));
  442. }
  443. size_type capacity() const {
  444. return c_.capacity() * Node::kElementCount;
  445. }
  446. const value_type& operator[](size_type idx) const {
  447. return c_[idx / Node::kElementCount].data()[idx % Node::kElementCount];
  448. }
  449. value_type& operator[](size_type idx) {
  450. return c_[idx / Node::kElementCount].data()[idx % Node::kElementCount];
  451. }
  452. /**
  453. * Return the underlying container and number of elements in the last block,
  454. * and clear *this. Useful when you want to process the data as Nodes
  455. * (again) and want to avoid copies.
  456. */
  457. std::pair<Container, size_t> move() {
  458. std::pair<Container, size_t> p(std::move(c_), lastCount_);
  459. lastCount_ = Node::kElementCount;
  460. return std::move(p);
  461. }
  462. /**
  463. * Return a const reference to the underlying container and the current
  464. * number of elements in the last block.
  465. */
  466. std::pair<const Container&, size_t> peek() const {
  467. return std::make_pair(std::cref(c_), lastCount_);
  468. }
  469. void padToFullNode(const value_type& padValue) {
  470. // the if is necessary because c_ may be empty so we can't call c_.back()
  471. if (lastCount_ != Node::kElementCount) {
  472. auto last = c_.back().data();
  473. std::fill(last + lastCount_, last + Node::kElementCount, padValue);
  474. lastCount_ = Node::kElementCount;
  475. }
  476. }
  477. private:
  478. value_type* allocate_back() {
  479. if (lastCount_ == Node::kElementCount) {
  480. detail::padded_emplace_back_or_push_back(c_);
  481. lastCount_ = 0;
  482. }
  483. return &c_.back().data()[lastCount_++];
  484. }
  485. static Node fullNode(const value_type& value) {
  486. Node n;
  487. std::fill(n.data(), n.data() + kElementsPerNode, value);
  488. return n;
  489. }
  490. Container c_; // container of Nodes
  491. size_t lastCount_; // number of elements in last Node
  492. };
  493. } // namespace padded
  494. } // namespace folly