1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
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  *   - insert() single key variants, emplace(), and emplace_hint() only provide
60  *     the strong exception guarantee (unchanged when exception is thrown) when
61  *     std::is_nothrow_move_constructible<value_type>::value is true.
62  */
63 
64 #pragma once
65 
66 #include <algorithm>
67 #include <cassert>
68 #include <initializer_list>
69 #include <iterator>
70 #include <memory>
71 #include <stdexcept>
72 #include <type_traits>
73 #include <utility>
74 #include <vector>
75 
76 #include <folly/ScopeGuard.h>
77 #include <folly/Traits.h>
78 #include <folly/Utility.h>
79 #include <folly/lang/Exception.h>
80 #include <folly/memory/MemoryResource.h>
81 
82 namespace folly {
83 
84 //////////////////////////////////////////////////////////////////////
85 
86 namespace detail {
87 
88 template <typename, typename Compare, typename Key, typename T>
89 struct sorted_vector_enable_if_is_transparent {};
90 
91 template <typename Compare, typename Key, typename T>
92 struct sorted_vector_enable_if_is_transparent<
93     void_t<typename Compare::is_transparent>,
94     Compare,
95     Key,
96     T> {
97   using type = T;
98 };
99 
100 // This wrapper goes around a GrowthPolicy and provides iterator
101 // preservation semantics, but only if the growth policy is not the
102 // default (i.e. nothing).
103 template <class Policy>
104 struct growth_policy_wrapper : private Policy {
105   template <class Container, class Iterator>
106   Iterator increase_capacity(Container& c, Iterator desired_insertion) {
107     typedef typename Container::difference_type diff_t;
108     diff_t d = desired_insertion - c.begin();
109     Policy::increase_capacity(c);
110     return c.begin() + d;
111   }
112 };
113 template <>
114 struct growth_policy_wrapper<void> {
115   template <class Container, class Iterator>
116   Iterator increase_capacity(Container&, Iterator it) {
117     return it;
118   }
119 };
120 
121 /*
122  * This helper returns the distance between two iterators if it is
123  * possible to figure it out without messing up the range
124  * (i.e. unless they are InputIterators).  Otherwise this returns
125  * -1.
126  */
127 template <class Iterator>
128 typename std::iterator_traits<Iterator>::difference_type distance_if_multipass(
129     Iterator first, Iterator last) {
130   typedef typename std::iterator_traits<Iterator>::iterator_category categ;
131   if (std::is_same<categ, std::input_iterator_tag>::value) {
132     return -1;
133   }
134   return std::distance(first, last);
135 }
136 
137 template <class OurContainer, class Vector, class GrowthPolicy, class Value>
138 typename OurContainer::iterator insert_with_hint(
139     OurContainer& sorted,
140     Vector& cont,
141     typename OurContainer::const_iterator hint,
142     Value&& value,
143     GrowthPolicy& po) {
144   const typename OurContainer::value_compare& cmp(sorted.value_comp());
145   if (hint == cont.end() || cmp(value, *hint)) {
146     if (hint == cont.begin() || cmp(*(hint - 1), value)) {
147       hint = po.increase_capacity(cont, hint);
148       return cont.emplace(hint, std::forward<Value>(value));
149     } else {
150       return sorted.emplace(std::forward<Value>(value)).first;
151     }
152   }
153 
154   if (cmp(*hint, value)) {
155     if (hint + 1 == cont.end() || cmp(value, *(hint + 1))) {
156       hint = po.increase_capacity(cont, hint + 1);
157       return cont.emplace(hint, std::forward<Value>(value));
158     } else {
159       return sorted.emplace(std::forward<Value>(value)).first;
160     }
161   }
162 
163   // Value and *hint did not compare, so they are equal keys.
164   return sorted.begin() + std::distance(sorted.cbegin(), hint);
165 }
166 
167 template <class OurContainer, class Vector, class InputIterator>
168 void bulk_insert(
169     OurContainer& sorted,
170     Vector& cont,
171     InputIterator first,
172     InputIterator last) {
173   // prevent deref of middle where middle == cont.end()
174   if (first == last) {
175     return;
176   }
177 
178   auto const& cmp(sorted.value_comp());
179 
180   auto const d = distance_if_multipass(first, last);
181   if (d != -1) {
182     cont.reserve(cont.size() + d);
183   }
184   auto const prev_size = cont.size();
185 
186   std::copy(first, last, std::back_inserter(cont));
187   auto const middle = cont.begin() + prev_size;
188   if (!std::is_sorted(middle, cont.end(), cmp)) {
189     std::sort(middle, cont.end(), cmp);
190   }
191   if (middle != cont.begin() && !cmp(*(middle - 1), *middle)) {
192     std::inplace_merge(cont.begin(), middle, cont.end(), cmp);
193   }
194   cont.erase(
195       std::unique(
196           cont.begin(),
197           cont.end(),
198           [&](typename OurContainer::value_type const& a,
199               typename OurContainer::value_type const& b) {
200             return !cmp(a, b) && !cmp(b, a);
201           }),
202       cont.end());
203 }
204 
205 template <typename Container, typename Compare>
206 bool is_sorted_unique(Container const& container, Compare const& comp) {
207   if (container.empty()) {
208     return true;
209   }
210   auto const e = container.end();
211   for (auto a = container.begin(), b = std::next(a); b != e; ++a, ++b) {
212     if (!comp(*a, *b)) {
213       return false;
214     }
215   }
216   return true;
217 }
218 
219 template <typename Container, typename Compare>
220 Container&& as_sorted_unique(Container&& container, Compare const& comp) {
221   std::sort(container.begin(), container.end(), comp);
222   container.erase(
223       std::unique(
224           container.begin(),
225           container.end(),
226           [&](auto const& a, auto const& b) {
227             return !comp(a, b) && !comp(b, a);
228           }),
229       container.end());
230   return static_cast<Container&&>(container);
231 }
232 } // namespace detail
233 
234 //////////////////////////////////////////////////////////////////////
235 
236 /**
237  * A sorted_vector_set is a container similar to std::set<>, but
238  * implemented as a sorted array with std::vector<>.
239  *
240  * @tparam T               Data type to store
241  * @tparam Compare         Comparison function that imposes a
242  *                              strict weak ordering over instances of T
243  * @tparam Allocator       allocation policy
244  * @tparam GrowthPolicy    policy object to control growth
245  *
246  * @author Aditya Agarwal <aditya@fb.com>
247  * @author Akhil Wable    <akhil@fb.com>
248  * @author Jordan DeLong  <delong.j@fb.com>
249  */
250 template <
251     class T,
252     class Compare = std::less<T>,
253     class Allocator = std::allocator<T>,
254     class GrowthPolicy = void,
255     class Container = std::vector<T, Allocator>>
256 class sorted_vector_set : detail::growth_policy_wrapper<GrowthPolicy> {
257   detail::growth_policy_wrapper<GrowthPolicy>& get_growth_policy() {
258     return *this;
259   }
260 
261   template <typename K, typename V, typename C = Compare>
262   using if_is_transparent =
263       _t<detail::sorted_vector_enable_if_is_transparent<void, C, K, V>>;
264 
265   struct EBO;
266 
267  public:
268   typedef T value_type;
269   typedef T key_type;
270   typedef Compare key_compare;
271   typedef Compare value_compare;
272   typedef Allocator allocator_type;
273   typedef Container container_type;
274 
275   typedef typename Container::pointer pointer;
276   typedef typename Container::reference reference;
277   typedef typename Container::const_reference const_reference;
278   /*
279    * XXX: Our normal iterator ought to also be a constant iterator
280    * (cf. Defect Report 103 for std::set), but this is a bit more of a
281    * pain.
282    */
283   typedef typename Container::iterator iterator;
284   typedef typename Container::const_iterator const_iterator;
285   typedef typename Container::difference_type difference_type;
286   typedef typename Container::size_type size_type;
287   typedef typename Container::reverse_iterator reverse_iterator;
288   typedef typename Container::const_reverse_iterator const_reverse_iterator;
289 
290   sorted_vector_set() : m_(Compare(), Allocator()) {}
291 
292   sorted_vector_set(const sorted_vector_set&) = default;
293 
294   sorted_vector_set(const sorted_vector_set& other, const Allocator& alloc)
295       : m_(other.m_, alloc) {}
296 
297   sorted_vector_set(sorted_vector_set&&) = default;
298 
299   sorted_vector_set(sorted_vector_set&& other, const Allocator& alloc) noexcept(
300       std::is_nothrow_constructible<EBO, EBO&&, const Allocator&>::value)
301       : m_(std::move(other.m_), alloc) {}
302 
303   explicit sorted_vector_set(const Allocator& alloc) : m_(Compare(), alloc) {}
304 
305   explicit sorted_vector_set(
306       const Compare& comp, const Allocator& alloc = Allocator())
307       : m_(comp, alloc) {}
308 
309   template <class InputIterator>
310   sorted_vector_set(
311       InputIterator first,
312       InputIterator last,
313       const Compare& comp = Compare(),
314       const Allocator& alloc = Allocator())
315       : m_(comp, alloc) {
316     // This is linear if [first, last) is already sorted (and if we
317     // can figure out the distance between the two iterators).
318     insert(first, last);
319   }
320 
321   template <class InputIterator>
322   sorted_vector_set(
323       InputIterator first, InputIterator last, const Allocator& alloc)
324       : m_(Compare(), alloc) {
325     // This is linear if [first, last) is already sorted (and if we
326     // can figure out the distance between the two iterators).
327     insert(first, last);
328   }
329 
330   /* implicit */ sorted_vector_set(
331       std::initializer_list<value_type> list,
332       const Compare& comp = Compare(),
333       const Allocator& alloc = Allocator())
334       : m_(comp, alloc) {
335     insert(list.begin(), list.end());
336   }
337 
338   sorted_vector_set(
339       std::initializer_list<value_type> list, const Allocator& alloc)
340       : m_(Compare(), alloc) {
341     insert(list.begin(), list.end());
342   }
343 
344   // Construct a sorted_vector_set by stealing the storage of a prefilled
345   // container. The container need not be sorted already. This supports
346   // bulk construction of sorted_vector_set with zero allocations, not counting
347   // those performed by the caller. (The iterator range constructor performs at
348   // least one allocation).
349   //
350   // Note that `sorted_vector_set(const Container& container)` is not provided,
351   // since the purpose of this constructor is to avoid an unnecessary copy.
352   explicit sorted_vector_set(
353       Container&& container, const Compare& comp = Compare())
354       : sorted_vector_set(
355             sorted_unique,
356             detail::as_sorted_unique(std::move(container), comp),
357             comp) {}
358 
359   // Construct a sorted_vector_set by stealing the storage of a prefilled
360   // container. Its elements must be sorted and unique, as sorted_unique_t
361   // hints. Supports bulk construction of sorted_vector_set with zero
362   // allocations, not counting those performed by the caller. (The iterator
363   // range constructor performs at least one allocation).
364   //
365   // Note that `sorted_vector_set(sorted_unique_t, const Container& container)`
366   // is not provided, since the purpose of this constructor is to avoid an extra
367   // copy.
368   sorted_vector_set(
369       sorted_unique_t,
370       Container&& container,
371       const Compare& comp = Compare()) noexcept(std::
372                                                     is_nothrow_constructible<
373                                                         EBO,
374                                                         const Compare&,
375                                                         Container&&>::value)
376       : m_(comp, std::move(container)) {
377     assert(detail::is_sorted_unique(m_.cont_, value_comp()));
378   }
379 
380   Allocator get_allocator() const { return m_.cont_.get_allocator(); }
381 
382   sorted_vector_set& operator=(const sorted_vector_set& other) = default;
383 
384   sorted_vector_set& operator=(sorted_vector_set&& other) = default;
385 
386   sorted_vector_set& operator=(std::initializer_list<value_type> ilist) {
387     clear();
388     insert(ilist.begin(), ilist.end());
389     return *this;
390   }
391 
392   key_compare key_comp() const { return m_; }
393   value_compare value_comp() const { return m_; }
394 
395   iterator begin() { return m_.cont_.begin(); }
396   iterator end() { return m_.cont_.end(); }
397   const_iterator cbegin() const { return m_.cont_.cbegin(); }
398   const_iterator begin() const { return m_.cont_.begin(); }
399   const_iterator cend() const { return m_.cont_.cend(); }
400   const_iterator end() const { return m_.cont_.end(); }
401   reverse_iterator rbegin() { return m_.cont_.rbegin(); }
402   reverse_iterator rend() { return m_.cont_.rend(); }
403   const_reverse_iterator rbegin() const { return m_.cont_.rbegin(); }
404   const_reverse_iterator rend() const { return m_.cont_.rend(); }
405 
406   void clear() { return m_.cont_.clear(); }
407   size_type size() const { return m_.cont_.size(); }
408   size_type max_size() const { return m_.cont_.max_size(); }
409   bool empty() const { return m_.cont_.empty(); }
410   void reserve(size_type s) { return m_.cont_.reserve(s); }
411   void shrink_to_fit() { m_.cont_.shrink_to_fit(); }
412   size_type capacity() const { return m_.cont_.capacity(); }
413 
414   std::pair<iterator, bool> insert(const value_type& value) {
415     iterator it = lower_bound(value);
416     if (it == end() || value_comp()(value, *it)) {
417       it = get_growth_policy().increase_capacity(m_.cont_, it);
418       return std::make_pair(m_.cont_.emplace(it, value), true);
419     }
420     return std::make_pair(it, false);
421   }
422 
423   std::pair<iterator, bool> insert(value_type&& value) {
424     iterator it = lower_bound(value);
425     if (it == end() || value_comp()(value, *it)) {
426       it = get_growth_policy().increase_capacity(m_.cont_, it);
427       return std::make_pair(m_.cont_.emplace(it, std::move(value)), true);
428     }
429     return std::make_pair(it, false);
430   }
431 
432   iterator insert(const_iterator hint, const value_type& value) {
433     return detail::insert_with_hint(
434         *this, m_.cont_, hint, value, get_growth_policy());
435   }
436 
437   iterator insert(const_iterator hint, value_type&& value) {
438     return detail::insert_with_hint(
439         *this, m_.cont_, hint, std::move(value), get_growth_policy());
440   }
441 
442   template <class InputIterator>
443   void insert(InputIterator first, InputIterator last) {
444     detail::bulk_insert(*this, m_.cont_, first, last);
445   }
446 
447   void insert(std::initializer_list<value_type> ilist) {
448     insert(ilist.begin(), ilist.end());
449   }
450 
451   // emplace isn't better than insert for sorted_vector_set, but aids
452   // compatibility
453   template <typename... Args>
454   std::pair<iterator, bool> emplace(Args&&... args) {
455     std::aligned_storage_t<sizeof(value_type), alignof(value_type)> b;
456     value_type* p = static_cast<value_type*>(static_cast<void*>(&b));
457     auto a = get_allocator();
458     std::allocator_traits<allocator_type>::construct(
459         a, p, std::forward<Args>(args)...);
460     auto g = makeGuard(
461         [&]() { std::allocator_traits<allocator_type>::destroy(a, p); });
462     return insert(std::move(*p));
463   }
464 
465   std::pair<iterator, bool> emplace(const value_type& value) {
466     return insert(value);
467   }
468 
469   std::pair<iterator, bool> emplace(value_type&& value) {
470     return insert(std::move(value));
471   }
472 
473   // emplace_hint isn't better than insert for sorted_vector_set, but aids
474   // compatibility
475   template <typename... Args>
476   iterator emplace_hint(const_iterator hint, Args&&... args) {
477     std::aligned_storage_t<sizeof(value_type), alignof(value_type)> b;
478     value_type* p = static_cast<value_type*>(static_cast<void*>(&b));
479     auto a = get_allocator();
480     std::allocator_traits<allocator_type>::construct(
481         a, p, std::forward<Args>(args)...);
482     auto g = makeGuard(
483         [&]() { std::allocator_traits<allocator_type>::destroy(a, p); });
484     return insert(hint, std::move(*p));
485   }
486 
487   iterator emplace_hint(const_iterator hint, const value_type& value) {
488     return insert(hint, value);
489   }
490 
491   iterator emplace_hint(const_iterator hint, value_type&& value) {
492     return insert(hint, std::move(value));
493   }
494 
495   size_type erase(const key_type& key) {
496     iterator it = find(key);
497     if (it == end()) {
498       return 0;
499     }
500     m_.cont_.erase(it);
501     return 1;
502   }
503 
504   iterator erase(const_iterator it) { return m_.cont_.erase(it); }
505 
506   iterator erase(const_iterator first, const_iterator last) {
507     return m_.cont_.erase(first, last);
508   }
509 
510   iterator find(const key_type& key) { return find_(*this, key); }
511 
512   const_iterator find(const key_type& key) const { return find_(*this, key); }
513 
514   template <typename K>
515   if_is_transparent<K, iterator> find(const K& key) {
516     return find_(*this, key);
517   }
518 
519   template <typename K>
520   if_is_transparent<K, const_iterator> find(const K& key) const {
521     return find_(*this, key);
522   }
523 
524   size_type count(const key_type& key) const {
525     return find(key) == end() ? 0 : 1;
526   }
527 
528   template <typename K>
529   if_is_transparent<K, size_type> count(const K& key) const {
530     return find(key) == end() ? 0 : 1;
531   }
532 
533   bool contains(const key_type& key) const { return find(key) != end(); }
534 
535   template <typename K>
536   if_is_transparent<K, bool> contains(const K& key) const {
537     return find(key) != end();
538   }
539 
540   iterator lower_bound(const key_type& key) {
541     return std::lower_bound(begin(), end(), key, key_comp());
542   }
543 
544   const_iterator lower_bound(const key_type& key) const {
545     return std::lower_bound(begin(), end(), key, key_comp());
546   }
547 
548   template <typename K>
549   if_is_transparent<K, iterator> lower_bound(const K& key) {
550     return std::lower_bound(begin(), end(), key, key_comp());
551   }
552 
553   template <typename K>
554   if_is_transparent<K, const_iterator> lower_bound(const K& key) const {
555     return std::lower_bound(begin(), end(), key, key_comp());
556   }
557 
558   iterator upper_bound(const key_type& key) {
559     return std::upper_bound(begin(), end(), key, key_comp());
560   }
561 
562   const_iterator upper_bound(const key_type& key) const {
563     return std::upper_bound(begin(), end(), key, key_comp());
564   }
565 
566   template <typename K>
567   if_is_transparent<K, iterator> upper_bound(const K& key) {
568     return std::upper_bound(begin(), end(), key, key_comp());
569   }
570 
571   template <typename K>
572   if_is_transparent<K, const_iterator> upper_bound(const K& key) const {
573     return std::upper_bound(begin(), end(), key, key_comp());
574   }
575 
576   std::pair<iterator, iterator> equal_range(const key_type& key) {
577     return std::equal_range(begin(), end(), key, key_comp());
578   }
579 
580   std::pair<const_iterator, const_iterator> equal_range(
581       const key_type& key) const {
582     return std::equal_range(begin(), end(), key, key_comp());
583   }
584 
585   template <typename K>
586   if_is_transparent<K, std::pair<iterator, iterator>> equal_range(
587       const K& key) {
588     return std::equal_range(begin(), end(), key, key_comp());
589   }
590 
591   template <typename K>
592   if_is_transparent<K, std::pair<const_iterator, const_iterator>> equal_range(
593       const K& key) const {
594     return std::equal_range(begin(), end(), key, key_comp());
595   }
596 
597   void swap(sorted_vector_set& o) noexcept(
598       IsNothrowSwappable<Compare>::value&& noexcept(
599           std::declval<Container&>().swap(o.m_.cont_))) {
600     using std::swap; // Allow ADL for swap(); fall back to std::swap().
601     Compare& a = m_;
602     Compare& b = o.m_;
603     swap(a, b);
604     m_.cont_.swap(o.m_.cont_);
605   }
606 
607   bool operator==(const sorted_vector_set& other) const {
608     return other.m_.cont_ == m_.cont_;
609   }
610   bool operator!=(const sorted_vector_set& other) const {
611     return !operator==(other);
612   }
613 
614   bool operator<(const sorted_vector_set& other) const {
615     return m_.cont_ < other.m_.cont_;
616   }
617   bool operator>(const sorted_vector_set& other) const { return other < *this; }
618   bool operator<=(const sorted_vector_set& other) const {
619     return !operator>(other);
620   }
621   bool operator>=(const sorted_vector_set& other) const {
622     return !operator<(other);
623   }
624 
625   const value_type* data() const noexcept { return m_.cont_.data(); }
626 
627  private:
628   /*
629    * This structure derives from the comparison object in order to
630    * make use of the empty base class optimization if our comparison
631    * functor is an empty class (usual case).
632    *
633    * Wrapping up this member like this is better than deriving from
634    * the Compare object ourselves (there are some perverse edge cases
635    * involving virtual functions).
636    *
637    * More info:  http://www.cantrip.org/emptyopt.html
638    */
639   struct EBO : Compare {
640     explicit EBO(const Compare& c, const Allocator& alloc) noexcept(
641         std::is_nothrow_default_constructible<Container>::value)
642         : Compare(c), cont_(alloc) {}
643     EBO(const EBO& other, const Allocator& alloc)
644     noexcept(std::is_nothrow_constructible<
645              Container,
646              const Container&,
647              const Allocator&>::value)
648         : Compare(static_cast<const Compare&>(other)),
649           cont_(other.cont_, alloc) {}
650     EBO(EBO&& other, const Allocator& alloc)
651     noexcept(std::is_nothrow_constructible<
652              Container,
653              Container&&,
654              const Allocator&>::value)
655         : Compare(static_cast<Compare&&>(other)),
656           cont_(std::move(other.cont_), alloc) {}
657     EBO(const Compare& c, Container&& cont)
658     noexcept(std::is_nothrow_move_constructible<Container>::value)
659         : Compare(c), cont_(std::move(cont)) {}
660     Container cont_;
661   } m_;
662 
663   template <typename Self>
664   using self_iterator_t = _t<
665       std::conditional<std::is_const<Self>::value, const_iterator, iterator>>;
666 
667   template <typename Self, typename K>
668   static self_iterator_t<Self> find_(Self& self, K const& key) {
669     auto end = self.end();
670     auto it = self.lower_bound(key);
671     if (it == end || !self.key_comp()(key, *it)) {
672       return it;
673     }
674     return end;
675   }
676 };
677 
678 // Swap function that can be found using ADL.
679 template <class T, class C, class A, class G>
680 inline void swap(
681     sorted_vector_set<T, C, A, G>& a, sorted_vector_set<T, C, A, G>& b) {
682   return a.swap(b);
683 }
684 
685 #if FOLLY_HAS_MEMORY_RESOURCE
686 
687 namespace pmr {
688 
689 template <
690     class T,
691     class Compare = std::less<T>,
692     class GrowthPolicy = void,
693     class Container =
694         std::vector<T, folly::detail::std_pmr::polymorphic_allocator<T>>>
695 using sorted_vector_set = folly::sorted_vector_set<
696     T,
697     Compare,
698     folly::detail::std_pmr::polymorphic_allocator<T>,
699     GrowthPolicy,
700     Container>;
701 
702 } // namespace pmr
703 
704 #endif
705 
706 //////////////////////////////////////////////////////////////////////
707 
708 /**
709  * A sorted_vector_map is similar to a sorted_vector_set but stores
710  * <key,value> pairs instead of single elements.
711  *
712  * @tparam Key           Key type
713  * @tparam Value         Value type
714  * @tparam Compare       Function that can compare key types and impose
715  *                            a strict weak ordering over them.
716  * @tparam Allocator     allocation policy
717  * @tparam GrowthPolicy  policy object to control growth
718  *
719  * @author Aditya Agarwal <aditya@fb.com>
720  * @author Akhil Wable    <akhil@fb.com>
721  * @author Jordan DeLong  <delong.j@fb.com>
722  */
723 template <
724     class Key,
725     class Value,
726     class Compare = std::less<Key>,
727     class Allocator = std::allocator<std::pair<Key, Value>>,
728     class GrowthPolicy = void,
729     class Container = std::vector<std::pair<Key, Value>, Allocator>>
730 class sorted_vector_map : detail::growth_policy_wrapper<GrowthPolicy> {
731   detail::growth_policy_wrapper<GrowthPolicy>& get_growth_policy() {
732     return *this;
733   }
734 
735   template <typename K, typename V, typename C = Compare>
736   using if_is_transparent =
737       _t<detail::sorted_vector_enable_if_is_transparent<void, C, K, V>>;
738 
739   struct EBO;
740 
741  public:
742   typedef Key key_type;
743   typedef Value mapped_type;
744   typedef typename Container::value_type value_type;
745   typedef Compare key_compare;
746   typedef Allocator allocator_type;
747   typedef Container container_type;
748 
749   struct value_compare : private Compare {
750     bool operator()(const value_type& a, const value_type& b) const {
751       return Compare::operator()(a.first, b.first);
752     }
753 
754    protected:
755     friend class sorted_vector_map;
756     explicit value_compare(const Compare& c) : Compare(c) {}
757   };
758 
759   typedef typename Container::pointer pointer;
760   typedef typename Container::reference reference;
761   typedef typename Container::const_reference const_reference;
762   typedef typename Container::iterator iterator;
763   typedef typename Container::const_iterator const_iterator;
764   typedef typename Container::difference_type difference_type;
765   typedef typename Container::size_type size_type;
766   typedef typename Container::reverse_iterator reverse_iterator;
767   typedef typename Container::const_reverse_iterator const_reverse_iterator;
768 
769   sorted_vector_map() noexcept(
770       std::is_nothrow_constructible<EBO, value_compare, Allocator>::value)
771       : m_(value_compare(Compare()), Allocator()) {}
772 
773   sorted_vector_map(const sorted_vector_map&) = default;
774 
775   sorted_vector_map(const sorted_vector_map& other, const Allocator& alloc)
776       : m_(other.m_, alloc) {}
777 
778   sorted_vector_map(sorted_vector_map&&) = default;
779 
780   sorted_vector_map(sorted_vector_map&& other, const Allocator& alloc) noexcept(
781       std::is_nothrow_constructible<EBO, EBO&&, const Allocator&>::value)
782       : m_(std::move(other.m_), alloc) {}
783 
784   explicit sorted_vector_map(const Allocator& alloc)
785       : m_(value_compare(Compare()), alloc) {}
786 
787   explicit sorted_vector_map(
788       const Compare& comp, const Allocator& alloc = Allocator())
789       : m_(value_compare(comp), alloc) {}
790 
791   template <class InputIterator>
792   explicit sorted_vector_map(
793       InputIterator first,
794       InputIterator last,
795       const Compare& comp = Compare(),
796       const Allocator& alloc = Allocator())
797       : m_(value_compare(comp), alloc) {
798     insert(first, last);
799   }
800 
801   template <class InputIterator>
802   sorted_vector_map(
803       InputIterator first, InputIterator last, const Allocator& alloc)
804       : m_(value_compare(Compare()), alloc) {
805     insert(first, last);
806   }
807 
808   /* implicit */ sorted_vector_map(
809       std::initializer_list<value_type> list,
810       const Compare& comp = Compare(),
811       const Allocator& alloc = Allocator())
812       : m_(value_compare(comp), alloc) {
813     insert(list.begin(), list.end());
814   }
815 
816   sorted_vector_map(
817       std::initializer_list<value_type> list, const Allocator& alloc)
818       : m_(value_compare(Compare()), alloc) {
819     insert(list.begin(), list.end());
820   }
821 
822   // Construct a sorted_vector_map by stealing the storage of a prefilled
823   // container. The container need not be sorted already. This supports
824   // bulk construction of sorted_vector_map with zero allocations, not counting
825   // those performed by the caller. (The iterator range constructor performs at
826   // least one allocation).
827   //
828   // Note that `sorted_vector_map(const Container& container)` is not provided,
829   // since the purpose of this constructor is to avoid an unnecessary copy.
830   explicit sorted_vector_map(
831       Container&& container, const Compare& comp = Compare())
832       : sorted_vector_map(
833             sorted_unique,
834             detail::as_sorted_unique(std::move(container), value_compare(comp)),
835             comp) {}
836 
837   // Construct a sorted_vector_map by stealing the storage of a prefilled
838   // container. Its elements must be sorted and unique, as sorted_unique_t
839   // hints. Supports bulk construction of sorted_vector_map with zero
840   // allocations, not counting those performed by the caller. (The iterator
841   // range constructor performs at least one allocation).
842   //
843   // Note that `sorted_vector_map(sorted_unique_t, const Container& container)`
844   // is not provided, since the purpose of this constructor is to avoid an extra
845   // copy.
846   sorted_vector_map(
847       sorted_unique_t,
848       Container&& container,
849       const Compare& comp = Compare()) noexcept(std::
850                                                     is_nothrow_constructible<
851                                                         EBO,
852                                                         value_compare,
853                                                         Container&&>::value)
854       : m_(value_compare(comp), std::move(container)) {
855     assert(std::is_sorted(m_.cont_.begin(), m_.cont_.end(), value_comp()));
856     assert(detail::is_sorted_unique(m_.cont_, value_comp()));
857   }
858 
859   Allocator get_allocator() const { return m_.cont_.get_allocator(); }
860 
861   sorted_vector_map& operator=(const sorted_vector_map& other) = default;
862 
863   sorted_vector_map& operator=(sorted_vector_map&& other) = default;
864 
865   sorted_vector_map& operator=(std::initializer_list<value_type> ilist) {
866     clear();
867     insert(ilist.begin(), ilist.end());
868     return *this;
869   }
870 
871   key_compare key_comp() const { return m_; }
872   value_compare value_comp() const { return m_; }
873 
874   iterator begin() { return m_.cont_.begin(); }
875   iterator end() { return m_.cont_.end(); }
876   const_iterator cbegin() const { return m_.cont_.cbegin(); }
877   const_iterator begin() const { return m_.cont_.begin(); }
878   const_iterator cend() const { return m_.cont_.cend(); }
879   const_iterator end() const { return m_.cont_.end(); }
880   reverse_iterator rbegin() { return m_.cont_.rbegin(); }
881   reverse_iterator rend() { return m_.cont_.rend(); }
882   const_reverse_iterator crbegin() const { return m_.cont_.crbegin(); }
883   const_reverse_iterator rbegin() const { return m_.cont_.rbegin(); }
884   const_reverse_iterator crend() const { return m_.cont_.crend(); }
885   const_reverse_iterator rend() const { return m_.cont_.rend(); }
886 
887   void clear() { return m_.cont_.clear(); }
888   size_type size() const { return m_.cont_.size(); }
889   size_type max_size() const { return m_.cont_.max_size(); }
890   bool empty() const { return m_.cont_.empty(); }
891   void reserve(size_type s) { return m_.cont_.reserve(s); }
892   void shrink_to_fit() { m_.cont_.shrink_to_fit(); }
893   size_type capacity() const { return m_.cont_.capacity(); }
894 
895   std::pair<iterator, bool> insert(const value_type& value) {
896     iterator it = lower_bound(value.first);
897     if (it == end() || value_comp()(value, *it)) {
898       it = get_growth_policy().increase_capacity(m_.cont_, it);
899       return std::make_pair(m_.cont_.emplace(it, value), true);
900     }
901     return std::make_pair(it, false);
902   }
903 
904   std::pair<iterator, bool> insert(value_type&& value) {
905     iterator it = lower_bound(value.first);
906     if (it == end() || value_comp()(value, *it)) {
907       it = get_growth_policy().increase_capacity(m_.cont_, it);
908       return std::make_pair(m_.cont_.emplace(it, std::move(value)), true);
909     }
910     return std::make_pair(it, false);
911   }
912 
913   iterator insert(const_iterator hint, const value_type& value) {
914     return detail::insert_with_hint(
915         *this, m_.cont_, hint, value, get_growth_policy());
916   }
917 
918   iterator insert(const_iterator hint, value_type&& value) {
919     return detail::insert_with_hint(
920         *this, m_.cont_, hint, std::move(value), get_growth_policy());
921   }
922 
923   template <class InputIterator>
924   void insert(InputIterator first, InputIterator last) {
925     detail::bulk_insert(*this, m_.cont_, first, last);
926   }
927 
928   void insert(std::initializer_list<value_type> ilist) {
929     insert(ilist.begin(), ilist.end());
930   }
931 
932   // emplace isn't better than insert for sorted_vector_map, but aids
933   // compatibility
934   template <typename... Args>
935   std::pair<iterator, bool> emplace(Args&&... args) {
936     std::aligned_storage_t<sizeof(value_type), alignof(value_type)> b;
937     value_type* p = static_cast<value_type*>(static_cast<void*>(&b));
938     auto a = get_allocator();
939     std::allocator_traits<allocator_type>::construct(
940         a, p, std::forward<Args>(args)...);
941     auto g = makeGuard(
942         [&]() { std::allocator_traits<allocator_type>::destroy(a, p); });
943     return insert(std::move(*p));
944   }
945 
946   std::pair<iterator, bool> emplace(const value_type& value) {
947     return insert(value);
948   }
949 
950   std::pair<iterator, bool> emplace(value_type&& value) {
951     return insert(std::move(value));
952   }
953 
954   // emplace_hint isn't better than insert for sorted_vector_set, but aids
955   // compatibility
956   template <typename... Args>
957   iterator emplace_hint(const_iterator hint, Args&&... args) {
958     std::aligned_storage_t<sizeof(value_type), alignof(value_type)> b;
959     value_type* p = static_cast<value_type*>(static_cast<void*>(&b));
960     auto a = get_allocator();
961     std::allocator_traits<allocator_type>::construct(
962         a, p, std::forward<Args>(args)...);
963     auto g = makeGuard(
964         [&]() { std::allocator_traits<allocator_type>::destroy(a, p); });
965     return insert(hint, std::move(*p));
966   }
967 
968   iterator emplace_hint(const_iterator hint, const value_type& value) {
969     return insert(hint, value);
970   }
971 
972   iterator emplace_hint(const_iterator hint, value_type&& value) {
973     return insert(hint, std::move(value));
974   }
975 
976   size_type erase(const key_type& key) {
977     iterator it = find(key);
978     if (it == end()) {
979       return 0;
980     }
981     m_.cont_.erase(it);
982     return 1;
983   }
984 
985   iterator erase(const_iterator it) { return m_.cont_.erase(it); }
986 
987   iterator erase(const_iterator first, const_iterator last) {
988     return m_.cont_.erase(first, last);
989   }
990 
991   iterator find(const key_type& key) { return find_(*this, key); }
992 
993   const_iterator find(const key_type& key) const { return find_(*this, key); }
994 
995   template <typename K>
996   if_is_transparent<K, iterator> find(const K& key) {
997     return find_(*this, key);
998   }
999 
1000   template <typename K>
1001   if_is_transparent<K, const_iterator> find(const K& key) const {
1002     return find_(*this, key);
1003   }
1004 
1005   mapped_type& at(const key_type& key) {
1006     iterator it = find(key);
1007     if (it != end()) {
1008       return it->second;
1009     }
1010     throw_exception<std::out_of_range>("sorted_vector_map::at");
1011   }
1012 
1013   const mapped_type& at(const key_type& key) const {
1014     const_iterator it = find(key);
1015     if (it != end()) {
1016       return it->second;
1017     }
1018     throw_exception<std::out_of_range>("sorted_vector_map::at");
1019   }
1020 
1021   size_type count(const key_type& key) const {
1022     return find(key) == end() ? 0 : 1;
1023   }
1024 
1025   template <typename K>
1026   if_is_transparent<K, size_type> count(const K& key) const {
1027     return find(key) == end() ? 0 : 1;
1028   }
1029 
1030   bool contains(const key_type& key) const { return find(key) != end(); }
1031 
1032   template <typename K>
1033   if_is_transparent<K, bool> contains(const K& key) const {
1034     return find(key) != end();
1035   }
1036 
1037   iterator lower_bound(const key_type& key) { return lower_bound(*this, key); }
1038 
1039   const_iterator lower_bound(const key_type& key) const {
1040     return lower_bound(*this, key);
1041   }
1042 
1043   template <typename K>
1044   if_is_transparent<K, iterator> lower_bound(const K& key) {
1045     return lower_bound(*this, key);
1046   }
1047 
1048   template <typename K>
1049   if_is_transparent<K, const_iterator> lower_bound(const K& key) const {
1050     return lower_bound(*this, key);
1051   }
1052 
1053   iterator upper_bound(const key_type& key) { return upper_bound(*this, key); }
1054 
1055   const_iterator upper_bound(const key_type& key) const {
1056     return upper_bound(*this, key);
1057   }
1058 
1059   template <typename K>
1060   if_is_transparent<K, iterator> upper_bound(const K& key) {
1061     return upper_bound(*this, key);
1062   }
1063 
1064   template <typename K>
1065   if_is_transparent<K, const_iterator> upper_bound(const K& key) const {
1066     return upper_bound(*this, key);
1067   }
1068 
1069   std::pair<iterator, iterator> equal_range(const key_type& key) {
1070     return equal_range(*this, key);
1071   }
1072 
1073   std::pair<const_iterator, const_iterator> equal_range(
1074       const key_type& key) const {
1075     return equal_range(*this, key);
1076   }
1077 
1078   template <typename K>
1079   if_is_transparent<K, std::pair<iterator, iterator>> equal_range(
1080       const K& key) {
1081     return equal_range(*this, key);
1082   }
1083 
1084   template <typename K>
1085   if_is_transparent<K, std::pair<const_iterator, const_iterator>> equal_range(
1086       const K& key) const {
1087     return equal_range(*this, key);
1088   }
1089 
1090   // Nothrow as long as swap() on the Compare type is nothrow.
1091   void swap(sorted_vector_map& o) {
1092     using std::swap; // Allow ADL for swap(); fall back to std::swap().
1093     Compare& a = m_;
1094     Compare& b = o.m_;
1095     swap(a, b);
1096     m_.cont_.swap(o.m_.cont_);
1097   }
1098 
1099   mapped_type& operator[](const key_type& key) {
1100     iterator it = lower_bound(key);
1101     if (it == end() || key_comp()(key, it->first)) {
1102       return insert(it, value_type(key, mapped_type()))->second;
1103     }
1104     return it->second;
1105   }
1106 
1107   bool operator==(const sorted_vector_map& other) const {
1108     return m_.cont_ == other.m_.cont_;
1109   }
1110   bool operator!=(const sorted_vector_map& other) const {
1111     return !operator==(other);
1112   }
1113 
1114   bool operator<(const sorted_vector_map& other) const {
1115     return m_.cont_ < other.m_.cont_;
1116   }
1117   bool operator>(const sorted_vector_map& other) const { return other < *this; }
1118   bool operator<=(const sorted_vector_map& other) const {
1119     return !operator>(other);
1120   }
1121   bool operator>=(const sorted_vector_map& other) const {
1122     return !operator<(other);
1123   }
1124 
1125   const value_type* data() const noexcept { return m_.cont_.data(); }
1126 
1127  private:
1128   // This is to get the empty base optimization; see the comment in
1129   // sorted_vector_set.
1130   struct EBO : value_compare {
1131     explicit EBO(const value_compare& c, const Allocator& alloc) noexcept(
1132         std::is_nothrow_default_constructible<Container>::value)
1133         : value_compare(c), cont_(alloc) {}
1134     EBO(const EBO& other, const Allocator& alloc)
1135     noexcept(std::is_nothrow_constructible<
1136              Container,
1137              const Container&,
1138              const Allocator&>::value)
1139         : value_compare(static_cast<const value_compare&>(other)),
1140           cont_(other.cont_, alloc) {}
1141     EBO(EBO&& other, const Allocator& alloc)
1142     noexcept(std::is_nothrow_constructible<
1143              Container,
1144              Container&&,
1145              const Allocator&>::value)
1146         : value_compare(static_cast<value_compare&&>(other)),
1147           cont_(std::move(other.cont_), alloc) {}
1148     EBO(const Compare& c, Container&& cont)
1149     noexcept(std::is_nothrow_move_constructible<Container>::value)
1150         : value_compare(c), cont_(std::move(cont)) {}
1151     Container cont_;
1152   } m_;
1153 
1154   template <typename Self>
1155   using self_iterator_t = _t<
1156       std::conditional<std::is_const<Self>::value, const_iterator, iterator>>;
1157 
1158   template <typename Self, typename K>
1159   static self_iterator_t<Self> find_(Self& self, K const& key) {
1160     auto end = self.end();
1161     auto it = self.lower_bound(key);
1162     if (it == end || !self.key_comp()(key, it->first)) {
1163       return it;
1164     }
1165     return end;
1166   }
1167 
1168   template <typename Self, typename K>
1169   static self_iterator_t<Self> lower_bound(Self& self, K const& key) {
1170     auto f = [c = self.key_comp()](value_type const& a, K const& b) {
1171       return c(a.first, b);
1172     };
1173     return std::lower_bound(self.begin(), self.end(), key, f);
1174   }
1175 
1176   template <typename Self, typename K>
1177   static self_iterator_t<Self> upper_bound(Self& self, K const& key) {
1178     auto f = [c = self.key_comp()](K const& a, value_type const& b) {
1179       return c(a, b.first);
1180     };
1181     return std::upper_bound(self.begin(), self.end(), key, f);
1182   }
1183 
1184   template <typename Self, typename K>
1185   static std::pair<self_iterator_t<Self>, self_iterator_t<Self>> equal_range(
1186       Self& self, K const& key) {
1187     // Note: std::equal_range can't be passed a functor that takes
1188     // argument types different from the iterator value_type, so we
1189     // have to do this.
1190     return {lower_bound(self, key), upper_bound(self, key)};
1191   }
1192 };
1193 
1194 // Swap function that can be found using ADL.
1195 template <class K, class V, class C, class A, class G>
1196 inline void swap(
1197     sorted_vector_map<K, V, C, A, G>& a, sorted_vector_map<K, V, C, A, G>& b) {
1198   return a.swap(b);
1199 }
1200 
1201 #if FOLLY_HAS_MEMORY_RESOURCE
1202 
1203 namespace pmr {
1204 
1205 template <
1206     class Key,
1207     class Value,
1208     class Compare = std::less<Key>,
1209     class GrowthPolicy = void,
1210     class Container = std::vector<
1211         std::pair<Key, Value>,
1212         folly::detail::std_pmr::polymorphic_allocator<std::pair<Key, Value>>>>
1213 using sorted_vector_map = folly::sorted_vector_map<
1214     Key,
1215     Value,
1216     Compare,
1217     folly::detail::std_pmr::polymorphic_allocator<std::pair<Key, Value>>,
1218     GrowthPolicy,
1219     Container>;
1220 
1221 } // namespace pmr
1222 
1223 #endif
1224 
1225 //////////////////////////////////////////////////////////////////////
1226 
1227 } // namespace folly
1228