proxygen
F14Map.h
Go to the documentation of this file.
1 /*
2  * Copyright 2017-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 
30 #include <stdexcept>
31 
32 #include <folly/Traits.h>
34 #include <folly/lang/Exception.h>
35 #include <folly/lang/SafeAssert.h>
36 
40 
41 #if !FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
42 
44 
45 #include <string>
46 #include <unordered_map>
47 
48 namespace folly {
49 
50 namespace f14 {
51 namespace detail {
52 template <typename K, typename M, typename H, typename E, typename A>
53 class F14BasicMap : public std::unordered_map<K, M, H, E, A> {
54  using Super = std::unordered_map<K, M, H, E, A>;
55 
56  public:
57  using typename Super::pointer;
58  using typename Super::value_type;
59 
60  F14BasicMap() = default;
61 
62  using Super::Super;
63 
65 
66  // exact for libstdc++, approximate for others
67  std::size_t getAllocatedMemorySize() const {
68  std::size_t rv = 0;
70  [&](std::size_t bytes, std::size_t n) { rv += bytes * n; });
71  return rv;
72  }
73 
74  // exact for libstdc++, approximate for others
75  template <typename V>
76  void visitAllocationClasses(V&& visitor) const {
77  auto bc = this->bucket_count();
78  if (bc > 1) {
79  visitor(bc * sizeof(pointer), 1);
80  }
81  if (this->size() > 0) {
82  visitor(sizeof(StdNodeReplica<K, value_type, H>), this->size());
83  }
84  }
85 
86  template <typename V>
87  void visitContiguousRanges(V&& visitor) const {
88  for (value_type const& entry : *this) {
89  value_type const* b = std::addressof(entry);
90  visitor(b, b + 1);
91  }
92  }
93 };
94 } // namespace detail
95 } // namespace f14
96 
97 template <
98  typename Key,
99  typename Mapped,
100  typename Hasher,
101  typename KeyEqual,
102  typename Alloc>
103 class F14ValueMap
104  : public f14::detail::F14BasicMap<Key, Mapped, Hasher, KeyEqual, Alloc> {
106 
107  public:
108  using typename Super::value_type;
109 
110  F14ValueMap() = default;
111 
112  using Super::Super;
113 
114  F14ValueMap& operator=(std::initializer_list<value_type> ilist) {
115  Super::operator=(ilist);
116  return *this;
117  }
118 };
119 
120 template <
121  typename Key,
122  typename Mapped,
123  typename Hasher,
124  typename KeyEqual,
125  typename Alloc>
126 class F14NodeMap
127  : public f14::detail::F14BasicMap<Key, Mapped, Hasher, KeyEqual, Alloc> {
129 
130  public:
131  using typename Super::value_type;
132 
133  F14NodeMap() = default;
134 
135  using Super::Super;
136 
137  F14NodeMap& operator=(std::initializer_list<value_type> ilist) {
138  Super::operator=(ilist);
139  return *this;
140  }
141 };
142 
143 template <
144  typename Key,
145  typename Mapped,
146  typename Hasher,
147  typename KeyEqual,
148  typename Alloc>
149 class F14VectorMap
150  : public f14::detail::F14BasicMap<Key, Mapped, Hasher, KeyEqual, Alloc> {
152 
153  public:
154  using typename Super::value_type;
155 
156  F14VectorMap() = default;
157 
158  using Super::Super;
159 
160  F14VectorMap& operator=(std::initializer_list<value_type> ilist) {
161  Super::operator=(ilist);
162  return *this;
163  }
164 };
165 
166 } // namespace folly
167 
168 #else // FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
169 
171 
172 namespace folly {
173 namespace f14 {
174 namespace detail {
175 
176 template <typename Policy>
177 class F14BasicMap {
178  template <typename K, typename T>
179  using EnableHeterogeneousFind = std::enable_if_t<
180  EligibleForHeterogeneousFind<
181  typename Policy::Key,
182  typename Policy::Hasher,
183  typename Policy::KeyEqual,
184  K>::value,
185  T>;
186 
187  template <typename K, typename T>
188  using EnableHeterogeneousInsert = std::enable_if_t<
189  EligibleForHeterogeneousInsert<
190  typename Policy::Key,
191  typename Policy::Hasher,
192  typename Policy::KeyEqual,
193  K>::value,
194  T>;
195 
196  template <typename K, typename T>
197  using EnableHeterogeneousErase = std::enable_if_t<
198  EligibleForHeterogeneousFind<
199  typename Policy::Value,
200  typename Policy::Hasher,
201  typename Policy::KeyEqual,
202  K>::value &&
203  !std::is_same<typename Policy::Iter, remove_cvref_t<K>>::value &&
204  !std::is_same<typename Policy::ConstIter, remove_cvref_t<K>>::value,
205  T>;
206 
207  public:
209 
210  using key_type = typename Policy::Key;
211  using mapped_type = typename Policy::Mapped;
212  using value_type = typename Policy::Value;
213  using size_type = std::size_t;
214  using difference_type = std::ptrdiff_t;
215  using hasher = typename Policy::Hasher;
216  using key_equal = typename Policy::KeyEqual;
217  using allocator_type = typename Policy::Alloc;
218  using reference = value_type&;
219  using const_reference = value_type const&;
220  using pointer = typename Policy::AllocTraits::pointer;
221  using const_pointer = typename Policy::AllocTraits::const_pointer;
222  using iterator = typename Policy::Iter;
223  using const_iterator = typename Policy::ConstIter;
224 
225  private:
226  using ItemIter = typename Policy::ItemIter;
227 
228  public:
230 
231  F14BasicMap() noexcept(Policy::kDefaultConstructIsNoexcept)
232  : F14BasicMap(0) {}
233 
234  explicit F14BasicMap(
235  std::size_t initialCapacity,
236  hasher const& hash = hasher{},
237  key_equal const& eq = key_equal{},
238  allocator_type const& alloc = allocator_type{})
239  : table_{initialCapacity, hash, eq, alloc} {}
240 
241  explicit F14BasicMap(std::size_t initialCapacity, allocator_type const& alloc)
242  : F14BasicMap(initialCapacity, hasher{}, key_equal{}, alloc) {}
243 
244  explicit F14BasicMap(
245  std::size_t initialCapacity,
246  hasher const& hash,
247  allocator_type const& alloc)
248  : F14BasicMap(initialCapacity, hash, key_equal{}, alloc) {}
249 
250  explicit F14BasicMap(allocator_type const& alloc)
251  : F14BasicMap(0, hasher{}, key_equal{}, alloc) {}
252 
253  template <typename InputIt>
254  F14BasicMap(
255  InputIt first,
256  InputIt last,
257  std::size_t initialCapacity = 0,
258  hasher const& hash = hasher{},
259  key_equal const& eq = key_equal{},
260  allocator_type const& alloc = allocator_type{})
261  : table_{initialCapacity, hash, eq, alloc} {
262  initialInsert(first, last, initialCapacity);
263  }
264 
265  template <typename InputIt>
266  F14BasicMap(
267  InputIt first,
268  InputIt last,
269  std::size_t initialCapacity,
270  allocator_type const& alloc)
271  : table_{initialCapacity, hasher{}, key_equal{}, alloc} {
272  initialInsert(first, last, initialCapacity);
273  }
274 
275  template <typename InputIt>
276  F14BasicMap(
277  InputIt first,
278  InputIt last,
279  std::size_t initialCapacity,
280  hasher const& hash,
281  allocator_type const& alloc)
282  : table_{initialCapacity, hash, key_equal{}, alloc} {
283  initialInsert(first, last, initialCapacity);
284  }
285 
286  F14BasicMap(F14BasicMap const& rhs) = default;
287 
288  F14BasicMap(F14BasicMap const& rhs, allocator_type const& alloc)
289  : table_{rhs.table_, alloc} {}
290 
291  F14BasicMap(F14BasicMap&& rhs) = default;
292 
293  F14BasicMap(F14BasicMap&& rhs, allocator_type const& alloc) noexcept(
294  Policy::kAllocIsAlwaysEqual)
295  : table_{std::move(rhs.table_), alloc} {}
296 
297  F14BasicMap(
298  std::initializer_list<value_type> init,
299  std::size_t initialCapacity = 0,
300  hasher const& hash = hasher{},
301  key_equal const& eq = key_equal{},
302  allocator_type const& alloc = allocator_type{})
303  : table_{initialCapacity, hash, eq, alloc} {
304  initialInsert(init.begin(), init.end(), initialCapacity);
305  }
306 
307  F14BasicMap(
308  std::initializer_list<value_type> init,
309  std::size_t initialCapacity,
310  allocator_type const& alloc)
311  : table_{initialCapacity, hasher{}, key_equal{}, alloc} {
312  initialInsert(init.begin(), init.end(), initialCapacity);
313  }
314 
315  F14BasicMap(
316  std::initializer_list<value_type> init,
317  std::size_t initialCapacity,
318  hasher const& hash,
319  allocator_type const& alloc)
320  : table_{initialCapacity, hash, key_equal{}, alloc} {
321  initialInsert(init.begin(), init.end(), initialCapacity);
322  }
323 
324  F14BasicMap& operator=(F14BasicMap const&) = default;
325 
326  F14BasicMap& operator=(F14BasicMap&&) = default;
327 
328  F14BasicMap& operator=(std::initializer_list<value_type> ilist) {
329  clear();
330  bulkInsert(ilist.begin(), ilist.end(), false);
331  return *this;
332  }
333 
334  allocator_type get_allocator() const noexcept {
335  return table_.alloc();
336  }
337 
339 
340  iterator begin() noexcept {
341  return table_.makeIter(table_.begin());
342  }
343  const_iterator begin() const noexcept {
344  return cbegin();
345  }
346  const_iterator cbegin() const noexcept {
347  return table_.makeConstIter(table_.begin());
348  }
349 
350  iterator end() noexcept {
351  return table_.makeIter(table_.end());
352  }
353  const_iterator end() const noexcept {
354  return cend();
355  }
356  const_iterator cend() const noexcept {
357  return table_.makeConstIter(table_.end());
358  }
359 
361 
362  bool empty() const noexcept {
363  return table_.empty();
364  }
365 
366  std::size_t size() const noexcept {
367  return table_.size();
368  }
369 
370  std::size_t max_size() const noexcept {
371  return table_.max_size();
372  }
373 
375 
376  void clear() noexcept {
377  table_.clear();
378  }
379 
380  std::pair<iterator, bool> insert(value_type const& value) {
381  return emplace(value);
382  }
383 
384  template <typename P>
385  std::enable_if_t<
387  std::pair<iterator, bool>>
388  insert(P&& value) {
389  return emplace(std::forward<P>(value));
390  }
391 
392  // TODO(T31574848): Work around libstdc++ versions (e.g., GCC < 6) with no
393  // implementation of N4387 ("perfect initialization" for pairs and tuples).
394  template <typename U1, typename U2>
395  std::enable_if_t<
398  std::pair<iterator, bool>>
399  insert(std::pair<U1, U2> const& value) {
400  return emplace(value);
401  }
402 
403  // TODO(T31574848)
404  template <typename U1, typename U2>
405  std::enable_if_t<
408  std::pair<iterator, bool>>
409  insert(std::pair<U1, U2>&& value) {
410  return emplace(std::move(value));
411  }
412 
413  std::pair<iterator, bool> insert(value_type&& value) {
414  return emplace(std::move(value));
415  }
416 
417  // std::unordered_map's hinted insertion API is misleading. No
418  // implementation I've seen actually uses the hint. Code restructuring
419  // by the caller to use the hinted API is at best unnecessary, and at
420  // worst a pessimization. It is used, however, so we provide it.
421 
422  iterator insert(const_iterator /*hint*/, value_type const& value) {
423  return insert(value).first;
424  }
425 
426  template <typename P>
428  insert(const_iterator /*hint*/, P&& value) {
429  return insert(std::forward<P>(value)).first;
430  }
431 
432  iterator insert(const_iterator /*hint*/, value_type&& value) {
433  return insert(std::move(value)).first;
434  }
435 
436  template <class... Args>
437  iterator emplace_hint(const_iterator /*hint*/, Args&&... args) {
438  return emplace(std::forward<Args>(args)...).first;
439  }
440 
441  private:
442  template <class InputIt>
444  bulkInsert(InputIt first, InputIt last, bool autoReserve) {
445  if (autoReserve) {
446  table_.reserveForInsert(std::distance(first, last));
447  }
448  while (first != last) {
449  insert(*first);
450  ++first;
451  }
452  }
453 
454  template <class InputIt>
455  void initialInsert(InputIt first, InputIt last, std::size_t initialCapacity) {
456  FOLLY_SAFE_DCHECK(empty() && bucket_count() >= initialCapacity, "");
457 
458  // It's possible that there are a lot of duplicates in first..last and
459  // so we will oversize ourself. The common case, however, is that
460  // we can avoid a lot of rehashing if we pre-expand. The behavior
461  // is easy to disable at a particular call site by asking for an
462  // initialCapacity of 1.
463  bool autoReserve =
464  std::is_same<
465  typename std::iterator_traits<InputIt>::iterator_category,
466  std::random_access_iterator_tag>::value &&
467  initialCapacity == 0;
468  bulkInsert(first, last, autoReserve);
469  }
470 
471  public:
472  template <class InputIt>
473  void insert(InputIt first, InputIt last) {
474  // Bulk reserve is a heuristic choice, so it can backfire. We restrict
475  // ourself to situations that mimic bulk construction without an
476  // explicit initialCapacity.
477  bool autoReserve =
478  std::is_same<
479  typename std::iterator_traits<InputIt>::iterator_category,
480  std::random_access_iterator_tag>::value &&
481  bucket_count() == 0;
482  bulkInsert(first, last, autoReserve);
483  }
484 
485  void insert(std::initializer_list<value_type> ilist) {
486  insert(ilist.begin(), ilist.end());
487  }
488 
489  template <typename M>
490  std::pair<iterator, bool> insert_or_assign(key_type const& key, M&& obj) {
491  auto rv = try_emplace(key, std::forward<M>(obj));
492  if (!rv.second) {
493  rv.first->second = std::forward<M>(obj);
494  }
495  return rv;
496  }
497 
498  template <typename M>
499  std::pair<iterator, bool> insert_or_assign(key_type&& key, M&& obj) {
500  auto rv = try_emplace(std::move(key), std::forward<M>(obj));
501  if (!rv.second) {
502  rv.first->second = std::forward<M>(obj);
503  }
504  return rv;
505  }
506 
507  template <typename M>
508  iterator
509  insert_or_assign(const_iterator /*hint*/, key_type const& key, M&& obj) {
510  return insert_or_assign(key, std::move(obj)).first;
511  }
512 
513  template <typename M>
514  iterator insert_or_assign(const_iterator /*hint*/, key_type&& key, M&& obj) {
515  return insert_or_assign(std::move(key), std::move(obj)).first;
516  }
517 
518  template <typename K, typename M>
519  EnableHeterogeneousInsert<K, std::pair<iterator, bool>> insert_or_assign(
520  K&& key,
521  M&& obj) {
522  auto rv = try_emplace(std::forward<K>(key), std::forward<M>(obj));
523  if (!rv.second) {
524  rv.first->second = std::forward<M>(obj);
525  }
526  return rv;
527  }
528 
529  private:
530  std::pair<ItemIter, bool> emplaceItem() {
531  // rare but valid
532  return table_.tryEmplaceValue(key_type{});
533  }
534 
535  template <typename U1, typename U2>
536  std::pair<ItemIter, bool> emplaceItem(U1&& x, U2&& y) {
537  using K = KeyTypeForEmplace<key_type, hasher, key_equal, U1>;
538  K key(std::forward<U1>(x));
539 
540  // TODO(T31574848): piecewise_construct is to work around libstdc++ versions
541  // (e.g., GCC < 6) with no implementation of N4387 ("perfect initialization"
542  // for pairs and tuples). Otherwise we could just pass key, forwarded key,
543  // and forwarded y to tryEmplaceValue.
544  return table_.tryEmplaceValue(
545  key,
546  std::piecewise_construct,
547  std::forward_as_tuple(std::forward<K>(key)),
548  std::forward_as_tuple(std::forward<U2>(y)));
549  }
550 
551  template <typename U1, typename U2>
552  std::pair<ItemIter, bool> emplaceItem(std::pair<U1, U2> const& p) {
553  return emplaceItem(p.first, p.second);
554  }
555 
556  template <typename U1, typename U2>
557  std::pair<ItemIter, bool> emplaceItem(std::pair<U1, U2>&& p) {
558  return emplaceItem(std::move(p.first), std::move(p.second));
559  }
560 
561  template <typename Arg1, typename... Args2>
562  std::pair<ItemIter, bool> emplaceItem(
563  std::piecewise_construct_t,
564  std::tuple<Arg1>&& first_args,
565  std::tuple<Args2...>&& second_args) {
566  using K = KeyTypeForEmplace<key_type, hasher, key_equal, Arg1>;
567  K key(std::get<0>(std::move(first_args)));
568 
569  // Args2&&... holds only references even if the caller gave us a
570  // tuple that directly contains values.
571  return table_.tryEmplaceValue(
572  key,
573  std::piecewise_construct,
574  std::forward_as_tuple(std::forward<K>(key)),
575  std::tuple<Args2&&...>(std::move(second_args)));
576  }
577 
578  template <typename... Args1, typename... Args2>
579  std::enable_if_t<sizeof...(Args1) != 1, std::pair<ItemIter, bool>>
580  emplaceItem(
581  std::piecewise_construct_t,
582  std::tuple<Args1...>&& first_args,
583  std::tuple<Args2...>&& second_args) {
584  auto key = make_from_tuple<key_type>(
585  std::tuple<Args1&&...>(std::move(first_args)));
586  return table_.tryEmplaceValue(
587  key,
588  std::piecewise_construct,
589  std::forward_as_tuple(std::move(key)),
590  std::tuple<Args2&&...>(std::move(second_args)));
591  }
592 
593  public:
594  template <typename... Args>
595  std::pair<iterator, bool> emplace(Args&&... args) {
596  auto rv = emplaceItem(std::forward<Args>(args)...);
597  return std::make_pair(table_.makeIter(rv.first), rv.second);
598  }
599 
600  template <typename... Args>
601  std::pair<iterator, bool> try_emplace(key_type const& key, Args&&... args) {
602  auto rv = table_.tryEmplaceValue(
603  key,
604  std::piecewise_construct,
605  std::forward_as_tuple(key),
606  std::forward_as_tuple(std::forward<Args>(args)...));
607  return std::make_pair(table_.makeIter(rv.first), rv.second);
608  }
609 
610  template <typename... Args>
611  std::pair<iterator, bool> try_emplace(key_type&& key, Args&&... args) {
612  auto rv = table_.tryEmplaceValue(
613  key,
614  std::piecewise_construct,
615  std::forward_as_tuple(std::move(key)),
616  std::forward_as_tuple(std::forward<Args>(args)...));
617  return std::make_pair(table_.makeIter(rv.first), rv.second);
618  }
619 
620  template <typename... Args>
621  iterator
622  try_emplace(const_iterator /*hint*/, key_type const& key, Args&&... args) {
623  auto rv = table_.tryEmplaceValue(
624  key,
625  std::piecewise_construct,
626  std::forward_as_tuple(key),
627  std::forward_as_tuple(std::forward<Args>(args)...));
628  return table_.makeIter(rv.first);
629  }
630 
631  template <typename... Args>
632  iterator
633  try_emplace(const_iterator /*hint*/, key_type&& key, Args&&... args) {
634  auto rv = table_.tryEmplaceValue(
635  key,
636  std::piecewise_construct,
637  std::forward_as_tuple(std::move(key)),
638  std::forward_as_tuple(std::forward<Args>(args)...));
639  return table_.makeIter(rv.first);
640  }
641 
642  template <typename K, typename... Args>
643  EnableHeterogeneousInsert<K, std::pair<iterator, bool>> try_emplace(
644  K&& key,
645  Args&&... args) {
646  auto rv = table_.tryEmplaceValue(
647  key,
648  std::piecewise_construct,
649  std::forward_as_tuple(std::forward<K>(key)),
650  std::forward_as_tuple(std::forward<Args>(args)...));
651  return std::make_pair(table_.makeIter(rv.first), rv.second);
652  }
653 
654  FOLLY_ALWAYS_INLINE iterator erase(const_iterator pos) {
655  // If we are inlined then gcc and clang can optimize away all of the
656  // work of itemPos.advance() if our return value is discarded.
657  auto itemPos = table_.unwrapIter(pos);
658  table_.eraseIter(itemPos);
659  itemPos.advanceLikelyDead();
660  return table_.makeIter(itemPos);
661  }
662 
663  // This form avoids ambiguity when key_type has a templated constructor
664  // that accepts const_iterator
665  iterator erase(iterator pos) {
666  auto itemPos = table_.unwrapIter(pos);
667  table_.eraseIter(itemPos);
668  itemPos.advanceLikelyDead();
669  return table_.makeIter(itemPos);
670  }
671 
672  iterator erase(const_iterator first, const_iterator last) {
673  auto itemFirst = table_.unwrapIter(first);
674  auto itemLast = table_.unwrapIter(last);
675  while (itemFirst != itemLast) {
676  table_.eraseIter(itemFirst);
677  itemFirst.advance();
678  }
679  return table_.makeIter(itemFirst);
680  }
681 
682  size_type erase(key_type const& key) {
683  return table_.eraseKey(key);
684  }
685 
686  template <typename K>
687  EnableHeterogeneousErase<K, size_type> erase(K const& key) {
688  return table_.eraseKey(key);
689  }
690 
692 
693  FOLLY_ALWAYS_INLINE mapped_type& at(key_type const& key) {
694  return at(*this, key);
695  }
696 
697  FOLLY_ALWAYS_INLINE mapped_type const& at(key_type const& key) const {
698  return at(*this, key);
699  }
700 
701  template <typename K>
702  EnableHeterogeneousFind<K, mapped_type&> at(K const& key) {
703  return at(*this, key);
704  }
705 
706  template <typename K>
707  EnableHeterogeneousFind<K, mapped_type const&> at(K const& key) const {
708  return at(*this, key);
709  }
710 
711  mapped_type& operator[](key_type const& key) {
712  return try_emplace(key).first->second;
713  }
714 
715  mapped_type& operator[](key_type&& key) {
716  return try_emplace(std::move(key)).first->second;
717  }
718 
719  template <typename K>
720  EnableHeterogeneousInsert<K, mapped_type&> operator[](K&& key) {
721  return try_emplace(std::forward<K>(key)).first->second;
722  }
723 
724  FOLLY_ALWAYS_INLINE std::size_t count(key_type const& key) const {
725  return table_.find(key).atEnd() ? 0 : 1;
726  }
727 
728  template <typename K>
729  FOLLY_ALWAYS_INLINE EnableHeterogeneousFind<K, std::size_t> count(
730  K const& key) const {
731  return table_.find(key).atEnd() ? 0 : 1;
732  }
733 
734  // prehash(key) does the work of evaluating hash_function()(key)
735  // (including additional bit-mixing for non-avalanching hash functions),
736  // wraps the result of that work in a token for later reuse, and
737  // begins prefetching the first steps of looking for key into the
738  // local CPU cache.
739  //
740  // The returned token may be used at any time, may be used more than
741  // once, and may be used in other F14 sets and maps. Tokens are
742  // transferrable between any F14 containers (maps and sets) with the
743  // same key_type and equal hash_function()s.
744  //
745  // Hash tokens are not hints -- it is a bug to call any method on this
746  // class with a token t and key k where t isn't the result of a call
747  // to prehash(k2) with k2 == k.
748  F14HashToken prehash(key_type const& key) const {
749  return table_.prehash(key);
750  }
751 
752  template <typename K>
753  EnableHeterogeneousFind<K, F14HashToken> prehash(K const& key) const {
754  return table_.prehash(key);
755  }
756 
757  FOLLY_ALWAYS_INLINE iterator find(key_type const& key) {
758  return table_.makeIter(table_.find(key));
759  }
760 
761  FOLLY_ALWAYS_INLINE const_iterator find(key_type const& key) const {
762  return table_.makeConstIter(table_.find(key));
763  }
764 
765  FOLLY_ALWAYS_INLINE iterator
766  find(F14HashToken const& token, key_type const& key) {
767  return table_.makeIter(table_.find(token, key));
768  }
769 
770  FOLLY_ALWAYS_INLINE const_iterator
771  find(F14HashToken const& token, key_type const& key) const {
772  return table_.makeConstIter(table_.find(token, key));
773  }
774 
775  template <typename K>
776  FOLLY_ALWAYS_INLINE EnableHeterogeneousFind<K, iterator> find(K const& key) {
777  return table_.makeIter(table_.find(key));
778  }
779 
780  template <typename K>
781  FOLLY_ALWAYS_INLINE EnableHeterogeneousFind<K, const_iterator> find(
782  K const& key) const {
783  return table_.makeConstIter(table_.find(key));
784  }
785 
786  template <typename K>
787  FOLLY_ALWAYS_INLINE EnableHeterogeneousFind<K, iterator> find(
788  F14HashToken const& token,
789  K const& key) {
790  return table_.makeIter(table_.find(token, key));
791  }
792 
793  template <typename K>
794  FOLLY_ALWAYS_INLINE EnableHeterogeneousFind<K, const_iterator> find(
795  F14HashToken const& token,
796  K const& key) const {
797  return table_.makeConstIter(table_.find(token, key));
798  }
799 
800  std::pair<iterator, iterator> equal_range(key_type const& key) {
801  return equal_range(*this, key);
802  }
803 
804  std::pair<const_iterator, const_iterator> equal_range(
805  key_type const& key) const {
806  return equal_range(*this, key);
807  }
808 
809  template <typename K>
810  EnableHeterogeneousFind<K, std::pair<iterator, iterator>> equal_range(
811  K const& key) {
812  return equal_range(*this, key);
813  }
814 
815  template <typename K>
816  EnableHeterogeneousFind<K, std::pair<const_iterator, const_iterator>>
817  equal_range(K const& key) const {
818  return equal_range(*this, key);
819  }
820 
822 
823  std::size_t bucket_count() const noexcept {
824  return table_.bucket_count();
825  }
826 
827  std::size_t max_bucket_count() const noexcept {
828  return table_.max_bucket_count();
829  }
830 
832 
833  float load_factor() const noexcept {
834  return table_.load_factor();
835  }
836 
837  float max_load_factor() const noexcept {
838  return table_.max_load_factor();
839  }
840 
841  void max_load_factor(float v) {
842  table_.max_load_factor(v);
843  }
844 
845  void rehash(std::size_t bucketCapacity) {
846  // The standard's rehash() requires understanding the max load factor,
847  // which is easy to get wrong. Since we don't actually allow adjustment
848  // of max_load_factor there is no difference.
849  reserve(bucketCapacity);
850  }
851 
852  void reserve(std::size_t capacity) {
853  table_.reserve(capacity);
854  }
855 
857 
858  hasher hash_function() const {
859  return table_.hasher();
860  }
861 
862  key_equal key_eq() const {
863  return table_.keyEqual();
864  }
865 
867 
868  // Get memory footprint, not including sizeof(*this).
869  std::size_t getAllocatedMemorySize() const {
870  return table_.getAllocatedMemorySize();
871  }
872 
873  // Enumerates classes of allocated memory blocks currently owned
874  // by this table, calling visitor(allocationSize, allocationCount).
875  // This can be used to get a more accurate indication of memory footprint
876  // than getAllocatedMemorySize() if you have some way of computing the
877  // internal fragmentation of the allocator, such as JEMalloc's nallocx.
878  // The visitor might be called twice with the same allocationSize. The
879  // visitor's computation should produce the same result for visitor(8,
880  // 2) as for two calls to visitor(8, 1), for example. The visitor may
881  // be called with a zero allocationCount.
882  template <typename V>
883  void visitAllocationClasses(V&& visitor) const {
884  return table_.visitAllocationClasses(visitor);
885  }
886 
887  // Calls visitor with two value_type const*, b and e, such that every
888  // entry in the table is included in exactly one of the ranges [b,e).
889  // This can be used to efficiently iterate elements in bulk when crossing
890  // an API boundary that supports contiguous blocks of items.
891  template <typename V>
892  void visitContiguousRanges(V&& visitor) const;
893 
894  F14TableStats computeStats() const noexcept {
895  return table_.computeStats();
896  }
897 
898  private:
899  template <typename Self, typename K>
900  FOLLY_ALWAYS_INLINE static auto& at(Self& self, K const& key) {
901  auto iter = self.find(key);
902  if (iter == self.end()) {
903  throw_exception<std::out_of_range>("at() did not find key");
904  }
905  return iter->second;
906  }
907 
908  template <typename Self, typename K>
909  static auto equal_range(Self& self, K const& key) {
910  auto first = self.find(key);
911  auto last = first;
912  if (last != self.end()) {
913  ++last;
914  }
915  return std::make_pair(first, last);
916  }
917 
918  protected:
919  F14Table<Policy> table_;
920 };
921 
922 template <typename M>
923 bool mapsEqual(M const& lhs, M const& rhs) {
924  if (lhs.size() != rhs.size()) {
925  return false;
926  }
927  for (auto& kv : lhs) {
928  auto iter = rhs.find(kv.first);
929  if (iter == rhs.end()) {
930  return false;
931  }
932  if (std::is_same<
933  typename M::key_equal,
934  std::equal_to<typename M::key_type>>::value) {
935  // find already checked key, just check value
936  if (!(kv.second == iter->second)) {
937  return false;
938  }
939  } else {
940  // spec says we compare key with == as well as with key_eq()
941  if (!(kv == *iter)) {
942  return false;
943  }
944  }
945  }
946  return true;
947 }
948 } // namespace detail
949 } // namespace f14
950 
951 template <
952  typename Key,
953  typename Mapped,
954  typename Hasher,
955  typename KeyEqual,
956  typename Alloc>
957 class F14ValueMap
958  : public f14::detail::F14BasicMap<f14::detail::MapPolicyWithDefaults<
959  f14::detail::ValueContainerPolicy,
960  Key,
961  Mapped,
962  Hasher,
963  KeyEqual,
964  Alloc>> {
965  using Policy = f14::detail::MapPolicyWithDefaults<
966  f14::detail::ValueContainerPolicy,
967  Key,
968  Mapped,
969  Hasher,
970  KeyEqual,
971  Alloc>;
973 
974  public:
975  using typename Super::value_type;
976 
977  F14ValueMap() = default;
978 
979  using Super::Super;
980 
981  F14ValueMap& operator=(std::initializer_list<value_type> ilist) {
982  Super::operator=(ilist);
983  return *this;
984  }
985 
986  void swap(F14ValueMap& rhs) noexcept(Policy::kSwapIsNoexcept) {
987  this->table_.swap(rhs.table_);
988  }
989 
990  template <typename V>
991  void visitContiguousRanges(V&& visitor) const {
992  this->table_.visitContiguousItemRanges(visitor);
993  }
994 };
995 
996 template <typename K, typename M, typename H, typename E, typename A>
997 bool operator==(
998  F14ValueMap<K, M, H, E, A> const& lhs,
1000  return mapsEqual(lhs, rhs);
1001 }
1002 
1003 template <typename K, typename M, typename H, typename E, typename A>
1004 bool operator!=(
1005  F14ValueMap<K, M, H, E, A> const& lhs,
1006  F14ValueMap<K, M, H, E, A> const& rhs) {
1007  return !(lhs == rhs);
1008 }
1009 
1010 template <
1011  typename Key,
1012  typename Mapped,
1013  typename Hasher,
1014  typename KeyEqual,
1015  typename Alloc>
1016 class F14NodeMap
1017  : public f14::detail::F14BasicMap<f14::detail::MapPolicyWithDefaults<
1018  f14::detail::NodeContainerPolicy,
1019  Key,
1020  Mapped,
1021  Hasher,
1022  KeyEqual,
1023  Alloc>> {
1024  using Policy = f14::detail::MapPolicyWithDefaults<
1025  f14::detail::NodeContainerPolicy,
1026  Key,
1027  Mapped,
1028  Hasher,
1029  KeyEqual,
1030  Alloc>;
1032 
1033  public:
1034  using typename Super::value_type;
1035 
1036  F14NodeMap() = default;
1037 
1038  using Super::Super;
1039 
1040  F14NodeMap& operator=(std::initializer_list<value_type> ilist) {
1041  Super::operator=(ilist);
1042  return *this;
1043  }
1044 
1045  void swap(F14NodeMap& rhs) noexcept(Policy::kSwapIsNoexcept) {
1046  this->table_.swap(rhs.table_);
1047  }
1048 
1049  template <typename V>
1050  void visitContiguousRanges(V&& visitor) const {
1051  this->table_.visitItems([&](typename Policy::Item ptr) {
1052  value_type const* b = std::addressof(*ptr);
1053  visitor(b, b + 1);
1054  });
1055  }
1056 
1057  // TODO extract and node_handle insert
1058 };
1059 
1060 template <typename K, typename M, typename H, typename E, typename A>
1061 bool operator==(
1062  F14NodeMap<K, M, H, E, A> const& lhs,
1063  F14NodeMap<K, M, H, E, A> const& rhs) {
1064  return mapsEqual(lhs, rhs);
1065 }
1066 
1067 template <typename K, typename M, typename H, typename E, typename A>
1068 bool operator!=(
1069  F14NodeMap<K, M, H, E, A> const& lhs,
1070  F14NodeMap<K, M, H, E, A> const& rhs) {
1071  return !(lhs == rhs);
1072 }
1073 
1074 template <
1075  typename Key,
1076  typename Mapped,
1077  typename Hasher,
1078  typename KeyEqual,
1079  typename Alloc>
1080 class F14VectorMap
1081  : public f14::detail::F14BasicMap<f14::detail::MapPolicyWithDefaults<
1082  f14::detail::VectorContainerPolicy,
1083  Key,
1084  Mapped,
1085  Hasher,
1086  KeyEqual,
1087  Alloc>> {
1088  using Policy = f14::detail::MapPolicyWithDefaults<
1089  f14::detail::VectorContainerPolicy,
1090  Key,
1091  Mapped,
1092  Hasher,
1093  KeyEqual,
1094  Alloc>;
1096 
1097  template <typename K, typename T>
1098  using EnableHeterogeneousVectorErase = std::enable_if_t<
1099  f14::detail::EligibleForHeterogeneousFind<
1100  typename Policy::Value,
1101  typename Policy::Hasher,
1102  typename Policy::KeyEqual,
1103  K>::value &&
1104  !std::is_same<typename Policy::Iter, remove_cvref_t<K>>::value &&
1105  !std::is_same<typename Policy::ConstIter, remove_cvref_t<K>>::value &&
1106  !std::is_same<typename Policy::ReverseIter, remove_cvref_t<K>>::
1107  value &&
1108  !std::is_same<typename Policy::ConstReverseIter, remove_cvref_t<K>>::
1109  value,
1110  T>;
1111 
1112  public:
1113  using typename Super::const_iterator;
1114  using typename Super::iterator;
1115  using typename Super::key_type;
1116  using typename Super::value_type;
1117  using reverse_iterator = typename Policy::ReverseIter;
1118  using const_reverse_iterator = typename Policy::ConstReverseIter;
1119 
1120  F14VectorMap() = default;
1121 
1122  // inherit constructors
1123  using Super::Super;
1124 
1125  F14VectorMap& operator=(std::initializer_list<value_type> ilist) {
1126  Super::operator=(ilist);
1127  return *this;
1128  }
1129 
1130  void swap(F14VectorMap& rhs) noexcept(Policy::kSwapIsNoexcept) {
1131  this->table_.swap(rhs.table_);
1132  }
1133 
1134  // ITERATION ORDER
1135  //
1136  // Deterministic iteration order for insert-only workloads is part of
1137  // F14VectorMap's supported API: iterator is LIFO and reverse_iterator
1138  // is FIFO.
1139  //
1140  // If there have been no calls to erase() then iterator and
1141  // const_iterator enumerate entries in the opposite of insertion order.
1142  // begin()->first is the key most recently inserted. reverse_iterator
1143  // and reverse_const_iterator, therefore, enumerate in LIFO (insertion)
1144  // order for insert-only workloads. Deterministic iteration order is
1145  // only guaranteed if no keys were removed since the last time the
1146  // map was empty. Iteration order is preserved across rehashes and
1147  // F14VectorMap copies and moves.
1148  //
1149  // iterator uses LIFO order so that erasing while iterating with begin()
1150  // and end() is safe using the erase(it++) idiom, which is supported
1151  // by std::map and std::unordered_map. erase(iter) invalidates iter
1152  // and all iterators before iter in the non-reverse iteration order.
1153  // Every successful erase invalidates all reverse iterators.
1154 
1155  iterator begin() {
1156  return this->table_.linearBegin(this->size());
1157  }
1158  const_iterator begin() const {
1159  return cbegin();
1160  }
1161  const_iterator cbegin() const {
1162  return this->table_.linearBegin(this->size());
1163  }
1164 
1165  iterator end() {
1166  return this->table_.linearEnd();
1167  }
1168  const_iterator end() const {
1169  return cend();
1170  }
1171  const_iterator cend() const {
1172  return this->table_.linearEnd();
1173  }
1174 
1175  reverse_iterator rbegin() {
1176  return this->table_.values_;
1177  }
1178  const_reverse_iterator rbegin() const {
1179  return crbegin();
1180  }
1181  const_reverse_iterator crbegin() const {
1182  return this->table_.values_;
1183  }
1184 
1185  reverse_iterator rend() {
1186  return this->table_.values_ + this->table_.size();
1187  }
1188  const_reverse_iterator rend() const {
1189  return crend();
1190  }
1191  const_reverse_iterator crend() const {
1192  return this->table_.values_ + this->table_.size();
1193  }
1194 
1195  // explicit conversions between iterator and reverse_iterator
1196  iterator iter(reverse_iterator riter) {
1197  return this->table_.iter(riter);
1198  }
1199  const_iterator iter(const_reverse_iterator riter) const {
1200  return this->table_.iter(riter);
1201  }
1202 
1203  reverse_iterator riter(iterator it) {
1204  return this->table_.riter(it);
1205  }
1206  const_reverse_iterator riter(const_iterator it) const {
1207  return this->table_.riter(it);
1208  }
1209 
1210  private:
1211  void eraseUnderlying(typename Policy::ItemIter underlying) {
1212  Alloc& a = this->table_.alloc();
1213  auto values = this->table_.values_;
1214 
1215  // Remove the ptr from the base table and destroy the value.
1216  auto index = underlying.item();
1217  // The item still needs to be hashable during this call, so we must destroy
1218  // the value _afterwards_.
1219  this->table_.eraseIter(underlying);
1220  Policy::AllocTraits::destroy(a, std::addressof(values[index]));
1221 
1222  // move the last element in values_ down and fix up the inbound index
1223  auto tailIndex = this->size();
1224  if (tailIndex != index) {
1225  auto tail = this->table_.find(f14::detail::VectorContainerIndexSearch{
1226  static_cast<uint32_t>(tailIndex)});
1227  tail.item() = index;
1228  auto p = std::addressof(values[index]);
1229  assume(p != nullptr);
1230  this->table_.transfer(a, std::addressof(values[tailIndex]), p, 1);
1231  }
1232  }
1233 
1234  template <typename K>
1235  std::size_t eraseUnderlyingKey(K const& key) {
1236  auto underlying = this->table_.find(key);
1237  if (underlying.atEnd()) {
1238  return 0;
1239  } else {
1240  eraseUnderlying(underlying);
1241  return 1;
1242  }
1243  }
1244 
1245  public:
1246  FOLLY_ALWAYS_INLINE iterator erase(const_iterator pos) {
1247  auto index = this->table_.iterToIndex(pos);
1248  auto underlying =
1249  this->table_.find(f14::detail::VectorContainerIndexSearch{index});
1250  eraseUnderlying(underlying);
1251  return index == 0 ? end() : this->table_.indexToIter(index - 1);
1252  }
1253 
1254  // This form avoids ambiguity when key_type has a templated constructor
1255  // that accepts const_iterator
1256  FOLLY_ALWAYS_INLINE iterator erase(iterator pos) {
1257  const_iterator cpos{pos};
1258  return erase(cpos);
1259  }
1260 
1261  iterator erase(const_iterator first, const_iterator last) {
1262  while (first != last) {
1263  first = erase(first);
1264  }
1265  auto index = this->table_.iterToIndex(first);
1266  return index == 0 ? end() : this->table_.indexToIter(index - 1);
1267  }
1268 
1269  // No erase is provided for reverse_iterator or const_reverse_iterator
1270  // to make it harder to shoot yourself in the foot by erasing while
1271  // reverse-iterating. You can write that as map.erase(map.iter(riter)).
1272 
1273  std::size_t erase(key_type const& key) {
1274  return eraseUnderlyingKey(key);
1275  }
1276 
1277  template <typename K>
1278  EnableHeterogeneousVectorErase<K, std::size_t> erase(K const& key) {
1279  return eraseUnderlyingKey(key);
1280  }
1281 
1282  template <typename V>
1283  void visitContiguousRanges(V&& visitor) const {
1284  auto n = this->table_.size();
1285  if (n > 0) {
1286  value_type const* b = std::addressof(this->table_.values_[0]);
1287  visitor(b, b + n);
1288  }
1289  }
1290 };
1291 
1292 template <typename K, typename M, typename H, typename E, typename A>
1293 bool operator==(
1294  F14VectorMap<K, M, H, E, A> const& lhs,
1295  F14VectorMap<K, M, H, E, A> const& rhs) {
1296  return mapsEqual(lhs, rhs);
1297 }
1298 
1299 template <typename K, typename M, typename H, typename E, typename A>
1300 bool operator!=(
1301  F14VectorMap<K, M, H, E, A> const& lhs,
1302  F14VectorMap<K, M, H, E, A> const& rhs) {
1303  return !(lhs == rhs);
1304 }
1305 
1306 } // namespace folly
1307 
1308 #endif // FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
1309 
1310 namespace folly {
1311 
1312 template <
1313  typename Key,
1314  typename Mapped,
1315  typename Hasher,
1316  typename KeyEqual,
1317  typename Alloc>
1318 class F14FastMap : public std::conditional_t<
1319  sizeof(std::pair<Key const, Mapped>) < 24,
1320  F14ValueMap<Key, Mapped, Hasher, KeyEqual, Alloc>,
1321  F14VectorMap<Key, Mapped, Hasher, KeyEqual, Alloc>> {
1322  using Super = std::conditional_t<
1323  sizeof(std::pair<Key const, Mapped>) < 24,
1324  F14ValueMap<Key, Mapped, Hasher, KeyEqual, Alloc>,
1325  F14VectorMap<Key, Mapped, Hasher, KeyEqual, Alloc>>;
1326 
1327  public:
1328  using typename Super::value_type;
1329 
1330  F14FastMap() = default;
1331 
1332  using Super::Super;
1333 
1334  F14FastMap& operator=(std::initializer_list<value_type> ilist) {
1335  Super::operator=(ilist);
1336  return *this;
1337  }
1338 };
1339 
1340 template <typename K, typename M, typename H, typename E, typename A>
1341 void swap(
1342  F14ValueMap<K, M, H, E, A>& lhs,
1343  F14ValueMap<K, M, H, E, A>& rhs) noexcept(noexcept(lhs.swap(rhs))) {
1344  lhs.swap(rhs);
1345 }
1346 
1347 template <typename K, typename M, typename H, typename E, typename A>
1348 void swap(
1349  F14NodeMap<K, M, H, E, A>& lhs,
1350  F14NodeMap<K, M, H, E, A>& rhs) noexcept(noexcept(lhs.swap(rhs))) {
1351  lhs.swap(rhs);
1352 }
1353 
1354 template <typename K, typename M, typename H, typename E, typename A>
1355 void swap(
1356  F14VectorMap<K, M, H, E, A>& lhs,
1357  F14VectorMap<K, M, H, E, A>& rhs) noexcept(noexcept(lhs.swap(rhs))) {
1358  lhs.swap(rhs);
1359 }
1360 
1361 template <typename K, typename M, typename H, typename E, typename A>
1362 void swap(
1363  F14FastMap<K, M, H, E, A>& lhs,
1364  F14FastMap<K, M, H, E, A>& rhs) noexcept(noexcept(lhs.swap(rhs))) {
1365  lhs.swap(rhs);
1366 }
1367 
1368 } // namespace folly
Definition: InvokeTest.cpp:58
void * ptr
#define FOLLY_ALWAYS_INLINE
Definition: CPortability.h:151
char b
bool operator!=(SwapTrackingAlloc< T1 > const &, SwapTrackingAlloc< T2 > const &)
Definition: F14TestUtil.h:427
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
internal::KeyMatcher< M > Key(M inner_matcher)
auto begin(TestAdlIterable &instance)
Definition: ForeachTest.cpp:56
folly::std T
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
FOLLY_PUSH_WARNING RHS rhs
Definition: Traits.h:649
static void destroy()
void init(int *argc, char ***argv, bool removeFlags)
Definition: Init.cpp:34
void visitContiguousRanges(V &&visitor) const
Definition: F14Map.h:87
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
constexpr auto empty(C const &c) -> decltype(c.empty())
Definition: Access.h:55
def Iter(n, format, sep='')
bool Value(const T &value, M matcher)
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
std::enable_if< std::is_integral< Src >::value &&IsSomeString< Tgt >::value &&sizeof(Src)< 4 >::typetoAppend(Src value, Tgt *result){typedef typename std::conditional< std::is_signed< Src >::value, int64_t, uint64_t >::type Intermediate;toAppend< Tgt >static_cast< Intermediate >value), result);}template< class Src >typename std::enable_if< std::is_integral< Src >::value &&sizeof(Src)< 4 &&!std::is_same< Src, char >::value, size_t >::typeestimateSpaceNeeded(Src value){typedef typename std::conditional< std::is_signed< Src >::value, int64_t, uint64_t >::type Intermediate;return estimateSpaceNeeded(static_cast< Intermediate >value));}template< class Tgt, class Src >typename std::enable_if< std::is_enum< Src >::value &&IsSomeString< Tgt >::value >::typetoAppend(Src value, Tgt *result){toAppend(static_cast< typename std::underlying_type< Src >::type >value), result);}template< class Src >typename std::enable_if< std::is_enum< Src >::value, size_t >::typeestimateSpaceNeeded(Src value){return estimateSpaceNeeded(static_cast< typename std::underlying_type< Src >::type >value));}namespace detail{constexpr int kConvMaxDecimalInShortestLow=-6;constexpr int kConvMaxDecimalInShortestHigh=21;}template< class Tgt, class Src >typename std::enable_if< std::is_floating_point< Src >::value &&IsSomeString< Tgt >::value >::typetoAppend(Src value, Tgt *result, double_conversion::DoubleToStringConverter::DtoaMode mode, unsigned int numDigits){using namespace double_conversion;DoubleToStringConverter conv(DoubleToStringConverter::NO_FLAGS,"Infinity","NaN", 'E', detail::kConvMaxDecimalInShortestLow, detail::kConvMaxDecimalInShortestHigh, 6, 1);char buffer[256];StringBuilder builder(buffer, sizeof(buffer));switch(mode){case DoubleToStringConverter::SHORTEST:conv.ToShortest(value,&builder);break;case DoubleToStringConverter::SHORTEST_SINGLE:conv.ToShortestSingle(static_cast< float >value),&builder);break;case DoubleToStringConverter::FIXED:conv.ToFixed(value, int(numDigits),&builder);break;default:CHECK(mode==DoubleToStringConverter::PRECISION);conv.ToPrecision(value, int(numDigits),&builder);break;}const size_t length=size_t(builder.position());builder.Finalize();result->append(buffer, length);}template< class Tgt, class Src >typename std::enable_if< std::is_floating_point< Src >::value &&IsSomeString< Tgt >::value >::typetoAppend(Src value, Tgt *result){toAppend(value, result, double_conversion::DoubleToStringConverter::SHORTEST, 0);}template< class Src >typename std::enable_if< std::is_floating_point< Src >::value, size_t >::typeestimateSpaceNeeded(Src value){constexpr int kMaxMantissaSpace=double_conversion::DoubleToStringConverter::kBase10MaximalLength+1;constexpr int kMaxExponentSpace=2+3;static const int kMaxPositiveSpace=std::max({kMaxMantissaSpace+kMaxExponentSpace, kMaxMantissaSpace-detail::kConvMaxDecimalInShortestLow, detail::kConvMaxDecimalInShortestHigh,});return size_t(kMaxPositiveSpace+(value< 0?1:0));}template< class Src >struct HasLengthEstimator:std::false_type{};template< class Src >constexpr typename std::enable_if< !std::is_fundamental< Src >::value &&!IsSomeString< Src >::value &&!std::is_convertible< Src, const char * >::value &&!std::is_convertible< Src, StringPiece >::value &&!std::is_enum< Src >::value &&!HasLengthEstimator< Src >::value, size_t >::typeestimateSpaceNeeded(const Src &){return sizeof(Src)+1;}namespace detail{template< class Tgt >typename std::enable_if< IsSomeString< Tgt >::value, size_t >::typeestimateSpaceToReserve(size_t sofar, Tgt *){return sofar;}template< class T, class...Ts >size_t estimateSpaceToReserve(size_t sofar, const T &v, const Ts &...vs){return estimateSpaceToReserve(sofar+estimateSpaceNeeded(v), vs...);}template< class...Ts >void reserveInTarget(const Ts &...vs){getLastElement(vs...) -> reserve(estimateSpaceToReserve(0, vs...))
Definition: Conv.h:792
char a
static const char *const value
Definition: Conv.cpp:50
void visitAllocationClasses(V &&visitor) const
Definition: F14Map.h:76
**Optimized Holders **The template hazptr_array< M > provides most of the functionality *of M hazptr_holder s but with faster construction destruction *for M
Definition: Hazptr.h:104
F14NodeMap & operator=(std::initializer_list< value_type > ilist)
Definition: F14Map.h:137
int * count
F14ValueMap & operator=(std::initializer_list< value_type > ilist)
Definition: F14Map.h:114
std::size_t getAllocatedMemorySize() const
Definition: F14Map.h:67
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
Definition: InvokeTest.cpp:65
std::unordered_map< Key, Mapped, Hasher, KeyEqual, Alloc > Super
Definition: F14Map.h:54
void swap(SwapTrackingAlloc< T > &, SwapTrackingAlloc< T > &)
Definition: F14TestUtil.h:414
FOLLY_ALWAYS_INLINE void assume(bool cond)
Definition: Assume.h:41
F14VectorMap & operator=(std::initializer_list< value_type > ilist)
Definition: F14Map.h:160
#define FOLLY_SAFE_DCHECK(expr, msg)
Definition: SafeAssert.h:42
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
std::vector< int > values(1'000)
constexpr detail::First first
Definition: Base-inl.h:2553
bool operator==(SwapTrackingAlloc< T1 > const &, SwapTrackingAlloc< T2 > const &)
Definition: F14TestUtil.h:422