proxygen
sorted_vector_types.h
Go to the documentation of this file.
1 /*
2  * Copyright 2011-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 /*
18  * This header defines two classes that very nearly model
19  * AssociativeContainer (but not quite). These implement set-like and
20  * map-like behavior on top of a sorted vector, instead of using
21  * rb-trees like std::set and std::map.
22  *
23  * This is potentially useful in cases where the number of elements in
24  * the set or map is small, or when you want to avoid using more
25  * memory than necessary and insertions/deletions are much more rare
26  * than lookups (these classes have O(N) insertions/deletions).
27  *
28  * In the interest of using these in conditions where the goal is to
29  * minimize memory usage, they support a GrowthPolicy parameter, which
30  * is a class defining a single function called increase_capacity,
31  * which will be called whenever we are about to insert something: you
32  * can then decide to call reserve() based on the current capacity()
33  * and size() of the passed in vector-esque Container type. An
34  * example growth policy that grows one element at a time:
35  *
36  * struct OneAtATimePolicy {
37  * template <class Container>
38  * void increase_capacity(Container& c) {
39  * if (c.size() == c.capacity()) {
40  * c.reserve(c.size() + 1);
41  * }
42  * }
43  * };
44  *
45  * typedef sorted_vector_set<int,
46  * std::less<int>,
47  * std::allocator<int>,
48  * OneAtATimePolicy>
49  * OneAtATimeIntSet;
50  *
51  * Important differences from std::set and std::map:
52  * - insert() and erase() invalidate iterators and references.
53  erase(iterator) returns an iterator pointing to the next valid element.
54  * - insert() and erase() are O(N)
55  * - our iterators model RandomAccessIterator
56  * - sorted_vector_map::value_type is pair<K,V>, not pair<const K,V>.
57  * (This is basically because we want to store the value_type in
58  * std::vector<>, which requires it to be Assignable.)
59  */
60 
61 #pragma once
62 
63 #include <algorithm>
64 #include <cassert>
65 #include <initializer_list>
66 #include <iterator>
67 #include <stdexcept>
68 #include <type_traits>
69 #include <utility>
70 #include <vector>
71 
72 #include <folly/Traits.h>
73 #include <folly/Utility.h>
74 #include <folly/lang/Exception.h>
75 
76 namespace folly {
77 
79 
80 namespace detail {
81 
82 template <typename, typename Compare, typename Key, typename T>
84 
85 template <typename Compare, typename Key, typename T>
87  void_t<typename Compare::is_transparent>,
88  Compare,
89  Key,
90  T> {
91  using type = T;
92 };
93 
94 // This wrapper goes around a GrowthPolicy and provides iterator
95 // preservation semantics, but only if the growth policy is not the
96 // default (i.e. nothing).
97 template <class Policy>
98 struct growth_policy_wrapper : private Policy {
99  template <class Container, class Iterator>
100  Iterator increase_capacity(Container& c, Iterator desired_insertion) {
101  typedef typename Container::difference_type diff_t;
102  diff_t d = desired_insertion - c.begin();
103  Policy::increase_capacity(c);
104  return c.begin() + d;
105  }
106 };
107 template <>
108 struct growth_policy_wrapper<void> {
109  template <class Container, class Iterator>
110  Iterator increase_capacity(Container&, Iterator it) {
111  return it;
112  }
113 };
114 
115 /*
116  * This helper returns the distance between two iterators if it is
117  * possible to figure it out without messing up the range
118  * (i.e. unless they are InputIterators). Otherwise this returns
119  * -1.
120  */
121 template <class Iterator>
122 int distance_if_multipass(Iterator first, Iterator last) {
123  typedef typename std::iterator_traits<Iterator>::iterator_category categ;
125  return -1;
126  }
127  return std::distance(first, last);
128 }
129 
130 template <class OurContainer, class Vector, class GrowthPolicy>
131 typename OurContainer::iterator insert_with_hint(
132  OurContainer& sorted,
133  Vector& cont,
134  typename OurContainer::iterator hint,
135  typename OurContainer::value_type&& value,
136  GrowthPolicy& po) {
137  const typename OurContainer::value_compare& cmp(sorted.value_comp());
138  if (hint == cont.end() || cmp(value, *hint)) {
139  if (hint == cont.begin() || cmp(*(hint - 1), value)) {
140  hint = po.increase_capacity(cont, hint);
141  return cont.insert(hint, std::move(value));
142  } else {
143  return sorted.insert(std::move(value)).first;
144  }
145  }
146 
147  if (cmp(*hint, value)) {
148  if (hint + 1 == cont.end() || cmp(value, *(hint + 1))) {
149  hint = po.increase_capacity(cont, hint + 1);
150  return cont.insert(hint, std::move(value));
151  } else {
152  return sorted.insert(std::move(value)).first;
153  }
154  }
155 
156  // Value and *hint did not compare, so they are equal keys.
157  return hint;
158 }
159 
160 template <class OurContainer, class Vector, class InputIterator>
162  OurContainer& sorted,
163  Vector& cont,
164  InputIterator first,
165  InputIterator last) {
166  // prevent deref of middle where middle == cont.end()
167  if (first == last) {
168  return;
169  }
170 
171  auto const& cmp(sorted.value_comp());
172 
173  int const d = distance_if_multipass(first, last);
174  if (d != -1) {
175  cont.reserve(cont.size() + d);
176  }
177  auto const prev_size = cont.size();
178 
179  std::copy(first, last, std::back_inserter(cont));
180  auto const middle = cont.begin() + prev_size;
181  if (!std::is_sorted(middle, cont.end(), cmp)) {
182  std::sort(middle, cont.end(), cmp);
183  }
184  if (middle != cont.begin() && !cmp(*(middle - 1), *middle)) {
185  std::inplace_merge(cont.begin(), middle, cont.end(), cmp);
186  }
187  cont.erase(
188  std::unique(
189  cont.begin(),
190  cont.end(),
191  [&](typename OurContainer::value_type const& a,
192  typename OurContainer::value_type const& b) {
193  return !cmp(a, b) && !cmp(b, a);
194  }),
195  cont.end());
196 }
197 
198 template <typename Container, typename Compare>
199 Container&& as_sorted(Container&& container, Compare const& comp) {
200  using namespace std;
201  std::sort(begin(container), end(container), comp);
202  return static_cast<Container&&>(container);
203 }
204 } // namespace detail
205 
207 
222 template <
223  class T,
224  class Compare = std::less<T>,
225  class Allocator = std::allocator<T>,
226  class GrowthPolicy = void,
227  class Container = std::vector<T, Allocator>>
230  return *this;
231  }
232 
233  template <typename K, typename V, typename C = Compare>
234  using if_is_transparent =
236 
237  public:
238  typedef T value_type;
239  typedef T key_type;
240  typedef Compare key_compare;
241  typedef Compare value_compare;
242 
243  typedef typename Container::pointer pointer;
244  typedef typename Container::reference reference;
245  typedef typename Container::const_reference const_reference;
246  /*
247  * XXX: Our normal iterator ought to also be a constant iterator
248  * (cf. Defect Report 103 for std::set), but this is a bit more of a
249  * pain.
250  */
251  typedef typename Container::iterator iterator;
252  typedef typename Container::const_iterator const_iterator;
253  typedef typename Container::difference_type difference_type;
254  typedef typename Container::size_type size_type;
255  typedef typename Container::reverse_iterator reverse_iterator;
256  typedef typename Container::const_reverse_iterator const_reverse_iterator;
257 
259  const Compare& comp = Compare(),
260  const Allocator& alloc = Allocator())
261  : m_(comp, alloc) {}
262 
263  template <class InputIterator>
265  InputIterator first,
266  InputIterator last,
267  const Compare& comp = Compare(),
268  const Allocator& alloc = Allocator())
269  : m_(comp, alloc) {
270  // This is linear if [first, last) is already sorted (and if we
271  // can figure out the distance between the two iterators).
272  insert(first, last);
273  }
274 
275  /* implicit */ sorted_vector_set(
276  std::initializer_list<value_type> list,
277  const Compare& comp = Compare(),
278  const Allocator& alloc = Allocator())
279  : m_(comp, alloc) {
280  insert(list.begin(), list.end());
281  }
282 
283  // Construct a sorted_vector_set by stealing the storage of a prefilled
284  // container. The container need not be sorted already. This supports
285  // bulk construction of sorted_vector_set with zero allocations, not counting
286  // those performed by the caller. (The iterator range constructor performs at
287  // least one allocation).
288  //
289  // Note that `sorted_vector_set(const Container& container)` is not provided,
290  // since the purpose of this constructor is to avoid an unnecessary copy.
292  Container&& container,
293  const Compare& comp = Compare())
295  presorted,
296  detail::as_sorted(std::move(container), comp),
297  comp) {}
298 
299  // Construct a sorted_vector_set by stealing the storage of a prefilled
300  // container. The container must be sorted, as presorted_t hints. Supports
301  // bulk construction of sorted_vector_set with zero allocations, not counting
302  // those performed by the caller. (The iterator range constructor performs at
303  // least one allocation).
304  //
305  // Note that `sorted_vector_set(presorted_t, const Container& container)` is
306  // not provided, since the purpose of this constructor is to avoid an extra
307  // copy.
309  presorted_t,
310  Container&& container,
311  const Compare& comp = Compare())
312  : m_(comp, container.get_allocator()) {
313  assert(std::is_sorted(container.begin(), container.end(), value_comp()));
314  m_.cont_.swap(container);
315  }
316 
317  sorted_vector_set& operator=(std::initializer_list<value_type> ilist) {
318  clear();
319  insert(ilist.begin(), ilist.end());
320  return *this;
321  }
322 
323  key_compare key_comp() const {
324  return m_;
325  }
326  value_compare value_comp() const {
327  return m_;
328  }
329 
330  iterator begin() {
331  return m_.cont_.begin();
332  }
333  iterator end() {
334  return m_.cont_.end();
335  }
336  const_iterator cbegin() const {
337  return m_.cont_.cbegin();
338  }
339  const_iterator begin() const {
340  return m_.cont_.begin();
341  }
342  const_iterator cend() const {
343  return m_.cont_.cend();
344  }
345  const_iterator end() const {
346  return m_.cont_.end();
347  }
348  reverse_iterator rbegin() {
349  return m_.cont_.rbegin();
350  }
351  reverse_iterator rend() {
352  return m_.cont_.rend();
353  }
354  const_reverse_iterator rbegin() const {
355  return m_.cont_.rbegin();
356  }
357  const_reverse_iterator rend() const {
358  return m_.cont_.rend();
359  }
360 
361  void clear() {
362  return m_.cont_.clear();
363  }
364  size_type size() const {
365  return m_.cont_.size();
366  }
367  size_type max_size() const {
368  return m_.cont_.max_size();
369  }
370  bool empty() const {
371  return m_.cont_.empty();
372  }
373  void reserve(size_type s) {
374  return m_.cont_.reserve(s);
375  }
376  void shrink_to_fit() {
377  m_.cont_.shrink_to_fit();
378  }
379  size_type capacity() const {
380  return m_.cont_.capacity();
381  }
382 
383  std::pair<iterator, bool> insert(const value_type& value) {
384  return insert(std::move(value_type(value)));
385  }
386 
387  std::pair<iterator, bool> insert(value_type&& value) {
388  iterator it = lower_bound(value);
389  if (it == end() || value_comp()(value, *it)) {
390  it = get_growth_policy().increase_capacity(m_.cont_, it);
391  return std::make_pair(m_.cont_.insert(it, std::move(value)), true);
392  }
393  return std::make_pair(it, false);
394  }
395 
396  iterator insert(iterator hint, const value_type& value) {
397  return insert(hint, std::move(value_type(value)));
398  }
399 
400  iterator insert(iterator hint, value_type&& value) {
402  *this, m_.cont_, hint, std::move(value), get_growth_policy());
403  }
404 
405  template <class InputIterator>
406  void insert(InputIterator first, InputIterator last) {
407  detail::bulk_insert(*this, m_.cont_, first, last);
408  }
409 
410  size_type erase(const key_type& key) {
411  iterator it = find(key);
412  if (it == end()) {
413  return 0;
414  }
415  m_.cont_.erase(it);
416  return 1;
417  }
418 
419  iterator erase(iterator it) {
420  return m_.cont_.erase(it);
421  }
422 
423  iterator erase(iterator first, iterator last) {
424  return m_.cont_.erase(first, last);
425  }
426 
427  iterator find(const key_type& key) {
428  return find(*this, key);
429  }
430 
431  const_iterator find(const key_type& key) const {
432  return find(*this, key);
433  }
434 
435  template <typename K>
437  return find(*this, key);
438  }
439 
440  template <typename K>
442  return find(*this, key);
443  }
444 
445  size_type count(const key_type& key) const {
446  return find(key) == end() ? 0 : 1;
447  }
448 
449  template <typename K>
451  return find(key) == end() ? 0 : 1;
452  }
453 
454  iterator lower_bound(const key_type& key) {
455  return std::lower_bound(begin(), end(), key, key_comp());
456  }
457 
458  const_iterator lower_bound(const key_type& key) const {
459  return std::lower_bound(begin(), end(), key, key_comp());
460  }
461 
462  template <typename K>
464  return std::lower_bound(begin(), end(), key, key_comp());
465  }
466 
467  template <typename K>
469  return std::lower_bound(begin(), end(), key, key_comp());
470  }
471 
472  iterator upper_bound(const key_type& key) {
473  return std::upper_bound(begin(), end(), key, key_comp());
474  }
475 
476  const_iterator upper_bound(const key_type& key) const {
477  return std::upper_bound(begin(), end(), key, key_comp());
478  }
479 
480  template <typename K>
482  return std::upper_bound(begin(), end(), key, key_comp());
483  }
484 
485  template <typename K>
487  return std::upper_bound(begin(), end(), key, key_comp());
488  }
489 
490  std::pair<iterator, iterator> equal_range(const key_type& key) {
491  return std::equal_range(begin(), end(), key, key_comp());
492  }
493 
494  std::pair<const_iterator, const_iterator> equal_range(
495  const key_type& key) const {
496  return std::equal_range(begin(), end(), key, key_comp());
497  }
498 
499  template <typename K>
501  const K& key) {
502  return std::equal_range(begin(), end(), key, key_comp());
503  }
504 
505  template <typename K>
507  const K& key) const {
508  return std::equal_range(begin(), end(), key, key_comp());
509  }
510 
511  // Nothrow as long as swap() on the Compare type is nothrow.
513  using std::swap; // Allow ADL for swap(); fall back to std::swap().
514  Compare& a = m_;
515  Compare& b = o.m_;
516  swap(a, b);
517  m_.cont_.swap(o.m_.cont_);
518  }
519 
520  bool operator==(const sorted_vector_set& other) const {
521  return other.m_.cont_ == m_.cont_;
522  }
523  bool operator!=(const sorted_vector_set& other) const {
524  return !operator==(other);
525  }
526 
527  bool operator<(const sorted_vector_set& other) const {
528  return m_.cont_ < other.m_.cont_;
529  }
530  bool operator>(const sorted_vector_set& other) const {
531  return other < *this;
532  }
533  bool operator<=(const sorted_vector_set& other) const {
534  return !operator>(other);
535  }
536  bool operator>=(const sorted_vector_set& other) const {
537  return !operator<(other);
538  }
539 
540  const value_type* data() const noexcept {
541  return m_.cont_.data();
542  }
543 
544  private:
545  /*
546  * This structure derives from the comparison object in order to
547  * make use of the empty base class optimization if our comparison
548  * functor is an empty class (usual case).
549  *
550  * Wrapping up this member like this is better than deriving from
551  * the Compare object ourselves (there are some perverse edge cases
552  * involving virtual functions).
553  *
554  * More info: http://www.cantrip.org/emptyopt.html
555  */
556  struct EBO : Compare {
557  explicit EBO(const Compare& c, const Allocator& alloc)
558  : Compare(c), cont_(alloc) {}
559  Container cont_;
560  } m_;
561 
562  template <typename Self>
563  using self_iterator_t = _t<
564  std::conditional<std::is_const<Self>::value, const_iterator, iterator>>;
565 
566  template <typename Self, typename K>
567  static self_iterator_t<Self> find(Self& self, K const& key) {
568  auto end = self.end();
569  auto it = self.lower_bound(key);
570  if (it == end || !self.key_comp()(key, *it)) {
571  return it;
572  }
573  return end;
574  }
575 };
576 
577 // Swap function that can be found using ADL.
578 template <class T, class C, class A, class G>
579 inline void swap(
582  return a.swap(b);
583 }
584 
586 
602 template <
603  class Key,
604  class Value,
605  class Compare = std::less<Key>,
606  class Allocator = std::allocator<std::pair<Key, Value>>,
607  class GrowthPolicy = void,
608  class Container = std::vector<std::pair<Key, Value>, Allocator>>
611  return *this;
612  }
613 
614  template <typename K, typename V, typename C = Compare>
615  using if_is_transparent =
617 
618  public:
619  typedef Key key_type;
620  typedef Value mapped_type;
621  typedef typename Container::value_type value_type;
622  typedef Compare key_compare;
623 
624  struct value_compare : private Compare {
625  bool operator()(const value_type& a, const value_type& b) const {
626  return Compare::operator()(a.first, b.first);
627  }
628 
629  protected:
630  friend class sorted_vector_map;
631  explicit value_compare(const Compare& c) : Compare(c) {}
632  };
633 
634  typedef typename Container::pointer pointer;
635  typedef typename Container::reference reference;
636  typedef typename Container::const_reference const_reference;
637  typedef typename Container::iterator iterator;
638  typedef typename Container::const_iterator const_iterator;
639  typedef typename Container::difference_type difference_type;
640  typedef typename Container::size_type size_type;
641  typedef typename Container::reverse_iterator reverse_iterator;
642  typedef typename Container::const_reverse_iterator const_reverse_iterator;
643 
645  const Compare& comp = Compare(),
646  const Allocator& alloc = Allocator())
647  : m_(value_compare(comp), alloc) {}
648 
649  template <class InputIterator>
651  InputIterator first,
652  InputIterator last,
653  const Compare& comp = Compare(),
654  const Allocator& alloc = Allocator())
655  : m_(value_compare(comp), alloc) {
656  insert(first, last);
657  }
658 
660  std::initializer_list<value_type> list,
661  const Compare& comp = Compare(),
662  const Allocator& alloc = Allocator())
663  : m_(value_compare(comp), alloc) {
664  insert(list.begin(), list.end());
665  }
666 
667  // Construct a sorted_vector_map by stealing the storage of a prefilled
668  // container. The container need not be sorted already. This supports
669  // bulk construction of sorted_vector_map with zero allocations, not counting
670  // those performed by the caller. (The iterator range constructor performs at
671  // least one allocation).
672  //
673  // Note that `sorted_vector_map(const Container& container)` is not provided,
674  // since the purpose of this constructor is to avoid an unnecessary copy.
676  Container&& container,
677  const Compare& comp = Compare())
679  presorted,
680  detail::as_sorted(std::move(container), value_compare(comp)),
681  comp) {}
682 
683  // Construct a sorted_vector_map by stealing the storage of a prefilled
684  // container. The container must be sorted, as presorted_t hints. S supports
685  // bulk construction of sorted_vector_map with zero allocations, not counting
686  // those performed by the caller. (The iterator range constructor performs at
687  // least one allocation).
688  //
689  // Note that `sorted_vector_map(presorted_t, const Container& container)` is
690  // not provided, since the purpose of this constructor is to avoid an extra
691  // copy.
693  presorted_t,
694  Container&& container,
695  const Compare& comp = Compare())
696  : m_(value_compare(comp), container.get_allocator()) {
697  assert(std::is_sorted(container.begin(), container.end(), value_comp()));
698  m_.cont_.swap(container);
699  }
700 
701  sorted_vector_map& operator=(std::initializer_list<value_type> ilist) {
702  clear();
703  insert(ilist.begin(), ilist.end());
704  return *this;
705  }
706 
707  key_compare key_comp() const {
708  return m_;
709  }
710  value_compare value_comp() const {
711  return m_;
712  }
713 
714  iterator begin() {
715  return m_.cont_.begin();
716  }
717  iterator end() {
718  return m_.cont_.end();
719  }
720  const_iterator cbegin() const {
721  return m_.cont_.cbegin();
722  }
723  const_iterator begin() const {
724  return m_.cont_.begin();
725  }
726  const_iterator cend() const {
727  return m_.cont_.cend();
728  }
729  const_iterator end() const {
730  return m_.cont_.end();
731  }
732  reverse_iterator rbegin() {
733  return m_.cont_.rbegin();
734  }
735  reverse_iterator rend() {
736  return m_.cont_.rend();
737  }
738  const_reverse_iterator rbegin() const {
739  return m_.cont_.rbegin();
740  }
741  const_reverse_iterator rend() const {
742  return m_.cont_.rend();
743  }
744 
745  void clear() {
746  return m_.cont_.clear();
747  }
748  size_type size() const {
749  return m_.cont_.size();
750  }
751  size_type max_size() const {
752  return m_.cont_.max_size();
753  }
754  bool empty() const {
755  return m_.cont_.empty();
756  }
757  void reserve(size_type s) {
758  return m_.cont_.reserve(s);
759  }
760  void shrink_to_fit() {
761  m_.cont_.shrink_to_fit();
762  }
763  size_type capacity() const {
764  return m_.cont_.capacity();
765  }
766 
767  std::pair<iterator, bool> insert(const value_type& value) {
768  return insert(std::move(value_type(value)));
769  }
770 
771  std::pair<iterator, bool> insert(value_type&& value) {
772  iterator it = lower_bound(value.first);
773  if (it == end() || value_comp()(value, *it)) {
774  it = get_growth_policy().increase_capacity(m_.cont_, it);
775  return std::make_pair(m_.cont_.insert(it, std::move(value)), true);
776  }
777  return std::make_pair(it, false);
778  }
779 
780  iterator insert(iterator hint, const value_type& value) {
781  return insert(hint, std::move(value_type(value)));
782  }
783 
784  iterator insert(iterator hint, value_type&& value) {
786  *this, m_.cont_, hint, std::move(value), get_growth_policy());
787  }
788 
789  template <class InputIterator>
790  void insert(InputIterator first, InputIterator last) {
791  detail::bulk_insert(*this, m_.cont_, first, last);
792  }
793 
794  size_type erase(const key_type& key) {
795  iterator it = find(key);
796  if (it == end()) {
797  return 0;
798  }
799  m_.cont_.erase(it);
800  return 1;
801  }
802 
803  iterator erase(iterator it) {
804  return m_.cont_.erase(it);
805  }
806 
807  iterator erase(iterator first, iterator last) {
808  return m_.cont_.erase(first, last);
809  }
810 
811  iterator find(const key_type& key) {
812  return find(*this, key);
813  }
814 
815  const_iterator find(const key_type& key) const {
816  return find(*this, key);
817  }
818 
819  template <typename K>
821  return find(*this, key);
822  }
823 
824  template <typename K>
826  return find(*this, key);
827  }
828 
829  mapped_type& at(const key_type& key) {
830  iterator it = find(key);
831  if (it != end()) {
832  return it->second;
833  }
834  throw_exception<std::out_of_range>("sorted_vector_map::at");
835  }
836 
837  const mapped_type& at(const key_type& key) const {
838  const_iterator it = find(key);
839  if (it != end()) {
840  return it->second;
841  }
842  throw_exception<std::out_of_range>("sorted_vector_map::at");
843  }
844 
845  size_type count(const key_type& key) const {
846  return find(key) == end() ? 0 : 1;
847  }
848 
849  template <typename K>
851  return find(key) == end() ? 0 : 1;
852  }
853 
854  iterator lower_bound(const key_type& key) {
855  return lower_bound(*this, key);
856  }
857 
858  const_iterator lower_bound(const key_type& key) const {
859  return lower_bound(*this, key);
860  }
861 
862  template <typename K>
864  return lower_bound(*this, key);
865  }
866 
867  template <typename K>
869  return lower_bound(*this, key);
870  }
871 
872  iterator upper_bound(const key_type& key) {
873  return upper_bound(*this, key);
874  }
875 
876  const_iterator upper_bound(const key_type& key) const {
877  return upper_bound(*this, key);
878  }
879 
880  template <typename K>
882  return upper_bound(*this, key);
883  }
884 
885  template <typename K>
887  return upper_bound(*this, key);
888  }
889 
890  std::pair<iterator, iterator> equal_range(const key_type& key) {
891  return equal_range(*this, key);
892  }
893 
894  std::pair<const_iterator, const_iterator> equal_range(
895  const key_type& key) const {
896  return equal_range(*this, key);
897  }
898 
899  template <typename K>
901  const K& key) {
902  return equal_range(*this, key);
903  }
904 
905  template <typename K>
907  const K& key) const {
908  return equal_range(*this, key);
909  }
910 
911  // Nothrow as long as swap() on the Compare type is nothrow.
913  using std::swap; // Allow ADL for swap(); fall back to std::swap().
914  Compare& a = m_;
915  Compare& b = o.m_;
916  swap(a, b);
917  m_.cont_.swap(o.m_.cont_);
918  }
919 
920  mapped_type& operator[](const key_type& key) {
921  iterator it = lower_bound(key);
922  if (it == end() || key_comp()(key, it->first)) {
923  return insert(it, value_type(key, mapped_type()))->second;
924  }
925  return it->second;
926  }
927 
928  bool operator==(const sorted_vector_map& other) const {
929  return m_.cont_ == other.m_.cont_;
930  }
931  bool operator!=(const sorted_vector_map& other) const {
932  return !operator==(other);
933  }
934 
935  bool operator<(const sorted_vector_map& other) const {
936  return m_.cont_ < other.m_.cont_;
937  }
938  bool operator>(const sorted_vector_map& other) const {
939  return other < *this;
940  }
941  bool operator<=(const sorted_vector_map& other) const {
942  return !operator>(other);
943  }
944  bool operator>=(const sorted_vector_map& other) const {
945  return !operator<(other);
946  }
947 
948  const value_type* data() const noexcept {
949  return m_.cont_.data();
950  }
951 
952  private:
953  // This is to get the empty base optimization; see the comment in
954  // sorted_vector_set.
955  struct EBO : value_compare {
956  explicit EBO(const value_compare& c, const Allocator& alloc)
957  : value_compare(c), cont_(alloc) {}
958  Container cont_;
959  } m_;
960 
961  template <typename Self>
962  using self_iterator_t = _t<
963  std::conditional<std::is_const<Self>::value, const_iterator, iterator>>;
964 
965  template <typename Self, typename K>
966  static self_iterator_t<Self> find(Self& self, K const& key) {
967  auto end = self.end();
968  auto it = self.lower_bound(key);
969  if (it == end || !self.key_comp()(key, it->first)) {
970  return it;
971  }
972  return end;
973  }
974 
975  template <typename Self, typename K>
976  static self_iterator_t<Self> lower_bound(Self& self, K const& key) {
977  auto f = [c = self.key_comp()](value_type const& a, K const& b) {
978  return c(a.first, b);
979  };
980  return std::lower_bound(self.begin(), self.end(), key, f);
981  }
982 
983  template <typename Self, typename K>
984  static self_iterator_t<Self> upper_bound(Self& self, K const& key) {
985  auto f = [c = self.key_comp()](K const& a, value_type const& b) {
986  return c(a, b.first);
987  };
988  return std::upper_bound(self.begin(), self.end(), key, f);
989  }
990 
991  template <typename Self, typename K>
992  static std::pair<self_iterator_t<Self>, self_iterator_t<Self>> equal_range(
993  Self& self,
994  K const& key) {
995  // Note: std::equal_range can't be passed a functor that takes
996  // argument types different from the iterator value_type, so we
997  // have to do this.
998  return {lower_bound(self, key), upper_bound(self, key)};
999  }
1000 };
1001 
1002 // Swap function that can be found using ADL.
1003 template <class K, class V, class C, class A, class G>
1004 inline void swap(
1007  return a.swap(b);
1008 }
1009 
1011 
1012 } // namespace folly
Container::iterator iterator
EBO(const value_compare &c, const Allocator &alloc)
Container::difference_type difference_type
bool operator>(const Expected< Value, Error > &lhs, const Expected< Value, Error > &rhs)
Definition: Expected.h:1349
if_is_transparent< K, const_iterator > lower_bound(const K &key) const
Container::reference reference
const_iterator cend() const
iterator insert(iterator hint, const value_type &value)
int distance_if_multipass(Iterator first, Iterator last)
bool operator>=(const sorted_vector_set &other) const
if_is_transparent< K, const_iterator > find(const K &key) const
if_is_transparent< K, size_type > count(const K &key) const
const_reverse_iterator rend() const
sorted_vector_map(presorted_t, Container &&container, const Compare &comp=Compare())
Container::const_reverse_iterator const_reverse_iterator
Container::const_reference const_reference
bool operator!=(const sorted_vector_map &other) const
bool operator()(const value_type &a, const value_type &b) const
auto f
detail::growth_policy_wrapper< GrowthPolicy > & get_growth_policy()
sorted_vector_set & operator=(std::initializer_list< value_type > ilist)
sorted_vector_set(presorted_t, Container &&container, const Compare &comp=Compare())
size_type erase(const key_type &key)
iterator erase(iterator first, iterator last)
_t< std::conditional< std::is_const< Self >::value, const_iterator, iterator >> self_iterator_t
bool operator<(const sorted_vector_set &other) const
if_is_transparent< K, size_type > count(const K &key) const
if_is_transparent< K, const_iterator > upper_bound(const K &key) const
Container::const_iterator const_iterator
Container::const_iterator const_iterator
if_is_transparent< K, std::pair< iterator, iterator > > equal_range(const K &key)
std::pair< iterator, iterator > equal_range(const key_type &key)
Container::size_type size_type
char b
iterator lower_bound(const key_type &key)
static self_iterator_t< Self > upper_bound(Self &self, K const &key)
std::pair< iterator, iterator > equal_range(const key_type &key)
std::pair< const_iterator, const_iterator > equal_range(const key_type &key) const
mapped_type & at(const key_type &key)
size_type count(const key_type &key) const
size_type erase(const key_type &key)
const_reverse_iterator rbegin() const
value_compare value_comp() const
void swap(sorted_vector_map< K, V, C, A, G > &a, sorted_vector_map< K, V, C, A, G > &b)
const mapped_type & at(const key_type &key) const
std::pair< const_iterator, const_iterator > equal_range(const key_type &key) const
if_is_transparent< K, const_iterator > find(const K &key) const
const_iterator lower_bound(const key_type &key) const
if_is_transparent< K, std::pair< const_iterator, const_iterator > > equal_range(const K &key) const
iterator insert(iterator hint, value_type &&value)
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
const_iterator find(const key_type &key) const
internal::KeyMatcher< M > Key(M inner_matcher)
static self_iterator_t< Self > find(Self &self, K const &key)
bool operator==(const sorted_vector_map &other) const
STL namespace.
sorted_vector_set(const Compare &comp=Compare(), const Allocator &alloc=Allocator())
auto begin(TestAdlIterable &instance)
Definition: ForeachTest.cpp:56
Iterator increase_capacity(Container &c, Iterator desired_insertion)
iterator insert(iterator hint, const value_type &value)
sorted_vector_map(const Compare &comp=Compare(), const Allocator &alloc=Allocator())
folly::std T
Container::iterator iterator
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
std::pair< iterator, bool > insert(const value_type &value)
Container::reverse_iterator reverse_iterator
std::pair< iterator, bool > insert(value_type &&value)
requires E e noexcept(noexcept(s.error(std::move(e))))
bool operator<(const sorted_vector_map &other) const
OurContainer::iterator insert_with_hint(OurContainer &sorted, Vector &cont, typename OurContainer::iterator hint, typename OurContainer::value_type &&value, GrowthPolicy &po)
sorted_vector_map(std::initializer_list< value_type > list, const Compare &comp=Compare(), const Allocator &alloc=Allocator())
bool operator>=(const sorted_vector_map &other) const
static self_iterator_t< Self > lower_bound(Self &self, K const &key)
const value_type * data() const noexcept
bool operator>(const sorted_vector_set &other) const
sorted_vector_set(Container &&container, const Compare &comp=Compare())
sorted_vector_map(InputIterator first, InputIterator last, const Compare &comp=Compare(), const Allocator &alloc=Allocator())
iterator find(const key_type &key)
folly::sorted_vector_set::EBO m_
void insert(InputIterator first, InputIterator last)
value_compare value_comp() const
constexpr std::decay< T >::type copy(T &&value) noexcept(noexcept(typename std::decay< T >::type(std::forward< T >(value))))
Definition: Utility.h:72
const_iterator cbegin() const
bool operator<=(const sorted_vector_set &other) const
iterator lower_bound(const key_type &key)
const_reverse_iterator rbegin() const
iterator erase(iterator it)
const_iterator end() const
const_iterator begin() const
const_iterator cend() const
bool Value(const T &value, M matcher)
typename T::type _t
Definition: Traits.h:171
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
if_is_transparent< K, iterator > lower_bound(const K &key)
std::pair< iterator, bool > insert(const value_type &value)
if_is_transparent< K, iterator > find(const K &key)
Encoder::MutableCompressedList list
Container::size_type size_type
sorted_vector_map & operator=(std::initializer_list< value_type > ilist)
void insert(InputIterator first, InputIterator last)
type_t< void, Ts... > void_t
Definition: Traits.h:302
sorted_vector_map(Container &&container, const Compare &comp=Compare())
char a
const_iterator upper_bound(const key_type &key) const
Container::difference_type difference_type
const_reverse_iterator rend() const
sorted_vector_set(std::initializer_list< value_type > list, const Compare &comp=Compare(), const Allocator &alloc=Allocator())
if_is_transparent< K, iterator > upper_bound(const K &key)
const_iterator cbegin() const
if_is_transparent< K, iterator > upper_bound(const K &key)
static const char *const value
Definition: Conv.cpp:50
if_is_transparent< K, iterator > lower_bound(const K &key)
bool operator==(const sorted_vector_set &other) const
bool operator>(const sorted_vector_map &other) const
const_iterator find(const key_type &key) const
Container::reference reference
const_iterator begin() const
Iterator increase_capacity(Container &, Iterator it)
iterator insert(iterator hint, value_type &&value)
key_compare key_comp() const
void swap(exception_wrapper &a, exception_wrapper &b) noexcept
if_is_transparent< K, std::pair< iterator, iterator > > equal_range(const K &key)
bool operator==(const Unexpected< Error > &lhs, const Unexpected< Error > &rhs)
Definition: Expected.h:758
iterator upper_bound(const key_type &key)
_t< detail::sorted_vector_enable_if_is_transparent< void, C, K, V >> if_is_transparent
constexpr presorted_t presorted
Definition: Utility.h:311
const_iterator end() const
const_iterator lower_bound(const key_type &key) const
size_type count(const key_type &key) const
Container::reverse_iterator reverse_iterator
Container::value_type value_type
iterator upper_bound(const key_type &key)
if_is_transparent< K, std::pair< const_iterator, const_iterator > > equal_range(const K &key) const
static set< string > s
mapped_type & operator[](const key_type &key)
const
Definition: upload.py:398
void swap(sorted_vector_map &o)
iterator erase(iterator first, iterator last)
Container::const_reverse_iterator const_reverse_iterator
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
_t< std::conditional< std::is_const< Self >::value, const_iterator, iterator >> self_iterator_t
static self_iterator_t< Self > find(Self &self, K const &key)
Container && as_sorted(Container &&container, Compare const &comp)
EBO(const Compare &c, const Allocator &alloc)
if_is_transparent< K, const_iterator > upper_bound(const K &key) const
bool operator!=(const sorted_vector_set &other) const
folly::sorted_vector_map::EBO m_
detail::growth_policy_wrapper< GrowthPolicy > & get_growth_policy()
iterator find(const key_type &key)
sorted_vector_set(InputIterator first, InputIterator last, const Compare &comp=Compare(), const Allocator &alloc=Allocator())
bool operator<=(const sorted_vector_map &other) const
iterator erase(iterator it)
std::pair< iterator, bool > insert(value_type &&value)
char c
if_is_transparent< K, const_iterator > lower_bound(const K &key) const
void bulk_insert(OurContainer &sorted, Vector &cont, InputIterator first, InputIterator last)
const_iterator upper_bound(const key_type &key) const
const value_type * data() const noexcept
Container::const_reference const_reference
void swap(sorted_vector_set &o)
std::enable_if< IsLessThanComparable< Value >::value, bool >::type operator<(const Expected< Value, Error > &lhs, const Expected< Value, Error > &rhs)
Definition: Expected.h:1321
key_compare key_comp() const
constexpr detail::First first
Definition: Base-inl.h:2553
static std::pair< self_iterator_t< Self >, self_iterator_t< Self > > equal_range(Self &self, K const &key)
_t< detail::sorted_vector_enable_if_is_transparent< void, C, K, V >> if_is_transparent
if_is_transparent< K, iterator > find(const K &key)