Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 659 lines (572 sloc) 21.832 kb
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
1 /*
22afce9 Louis Brandy Copyright 2013 -> 2014
lbrandy authored
2 * Copyright 2014 Facebook, Inc.
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
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 * - insert() and erase() are O(N)
54 * - our iterators model RandomAccessIterator
55 * - sorted_vector_map::value_type is pair<K,V>, not pair<const K,V>.
56 * (This is basically because we want to store the value_type in
57 * std::vector<>, which requires it to be Assignable.)
58 */
59
60 #ifndef FOLLY_SORTED_VECTOR_TYPES_H_
61 #define FOLLY_SORTED_VECTOR_TYPES_H_
62
63 #include <algorithm>
1db90a1 Added initializer_list ctors to sorted_vector_{set,map}
Soren Lassen authored
64 #include <initializer_list>
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
65 #include <iterator>
1db90a1 Added initializer_list ctors to sorted_vector_{set,map}
Soren Lassen authored
66 #include <utility>
67 #include <vector>
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
68 #include <boost/operators.hpp>
69 #include <boost/bind.hpp>
70 #include <boost/type_traits/is_same.hpp>
71
72 namespace folly {
73
74 //////////////////////////////////////////////////////////////////////
75
76 namespace detail {
77
78 // This wrapper goes around a GrowthPolicy and provides iterator
79 // preservation semantics, but only if the growth policy is not the
80 // default (i.e. nothing).
81 template<class Policy>
82 struct growth_policy_wrapper : private Policy {
83 template<class Container, class Iterator>
84 Iterator increase_capacity(Container& c, Iterator desired_insertion)
85 {
86 typedef typename Container::difference_type diff_t;
87 diff_t d = desired_insertion - c.begin();
88 Policy::increase_capacity(c);
89 return c.begin() + d;
90 }
91 };
92 template<>
93 struct growth_policy_wrapper<void> {
94 template<class Container, class Iterator>
95 Iterator increase_capacity(Container&, Iterator it) {
96 return it;
97 }
98 };
99
100 /*
101 * This helper returns the distance between two iterators if it is
102 * possible to figure it out without messing up the range
103 * (i.e. unless they are InputIterators). Otherwise this returns
104 * -1.
105 */
106 template<class Iterator>
107 int distance_if_multipass(Iterator first, Iterator last) {
108 typedef typename std::iterator_traits<Iterator>::iterator_category categ;
109 if (boost::is_same<categ,std::input_iterator_tag>::value)
110 return -1;
111 return std::distance(first, last);
112 }
113
114 template<class OurContainer, class Vector, class GrowthPolicy>
c363387 sorted_vector_types does not work with std::inserter
Marc Celani authored
115 typename OurContainer::iterator
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
116 insert_with_hint(OurContainer& sorted,
117 Vector& cont,
118 typename OurContainer::iterator hint,
cc4eb4c sorted_vector_types have move inserts
Marc Celani authored
119 typename OurContainer::value_type&& value,
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
120 GrowthPolicy& po)
121 {
122 const typename OurContainer::value_compare& cmp(sorted.value_comp());
123 if (hint == cont.end() || cmp(value, *hint)) {
124 if (hint == cont.begin()) {
125 po.increase_capacity(cont, cont.begin());
cc4eb4c sorted_vector_types have move inserts
Marc Celani authored
126 return cont.insert(cont.begin(), std::move(value));
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
127 }
128 if (cmp(*(hint - 1), value)) {
129 hint = po.increase_capacity(cont, hint);
cc4eb4c sorted_vector_types have move inserts
Marc Celani authored
130 return cont.insert(hint, std::move(value));
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
131 }
cc4eb4c sorted_vector_types have move inserts
Marc Celani authored
132 return sorted.insert(std::move(value)).first;
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
133 }
134
135 if (cmp(*hint, value)) {
136 if (hint + 1 == cont.end() || cmp(value, *(hint + 1))) {
137 typename OurContainer::iterator it =
138 po.increase_capacity(cont, hint + 1);
cc4eb4c sorted_vector_types have move inserts
Marc Celani authored
139 return cont.insert(it, std::move(value));
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
140 }
141 }
142
143 // Value and *hint did not compare, so they are equal keys.
c363387 sorted_vector_types does not work with std::inserter
Marc Celani authored
144 return hint;
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
145 }
146
147 }
148
149 //////////////////////////////////////////////////////////////////////
150
151 /**
152 * A sorted_vector_set is a container similar to std::set<>, but
153 * implemented as as a sorted array with std::vector<>.
154 *
155 * @param class T Data type to store
156 * @param class Compare Comparison function that imposes a
157 * strict weak ordering over instances of T
158 * @param class Allocator allocation policy
159 * @param class GrowthPolicy policy object to control growth
160 *
161 * @author Aditya Agarwal <aditya@fb.com>
162 * @author Akhil Wable <akhil@fb.com>
163 * @author Jordan DeLong <delong.j@fb.com>
164 */
165 template<class T,
166 class Compare = std::less<T>,
167 class Allocator = std::allocator<T>,
168 class GrowthPolicy = void>
169 class sorted_vector_set
170 : boost::totally_ordered1<
171 sorted_vector_set<T,Compare,Allocator,GrowthPolicy>
172 , detail::growth_policy_wrapper<GrowthPolicy> >
173 {
174 typedef std::vector<T,Allocator> ContainerT;
175
176 detail::growth_policy_wrapper<GrowthPolicy>&
177 get_growth_policy() { return *this; }
178
179 public:
180 typedef T value_type;
181 typedef T key_type;
182 typedef Compare key_compare;
183 typedef Compare value_compare;
184
185 typedef typename ContainerT::pointer pointer;
186 typedef typename ContainerT::reference reference;
187 typedef typename ContainerT::const_reference const_reference;
188 /*
189 * XXX: Our normal iterator ought to also be a constant iterator
190 * (cf. Defect Report 103 for std::set), but this is a bit more of a
191 * pain.
192 */
193 typedef typename ContainerT::iterator iterator;
194 typedef typename ContainerT::const_iterator const_iterator;
195 typedef typename ContainerT::difference_type difference_type;
196 typedef typename ContainerT::size_type size_type;
197 typedef typename ContainerT::reverse_iterator reverse_iterator;
198 typedef typename ContainerT::const_reverse_iterator const_reverse_iterator;
199
200 explicit sorted_vector_set(const Compare& comp = Compare(),
201 const Allocator& alloc = Allocator())
202 : m_(comp, alloc)
203 {}
204
205 template<class InputIterator>
206 explicit sorted_vector_set(
207 InputIterator first,
208 InputIterator last,
209 const Compare& comp = Compare(),
210 const Allocator& alloc = Allocator())
211 : m_(comp, alloc)
212 {
213 // This is linear if [first, last) is already sorted (and if we
214 // can figure out the distance between the two iterators).
215 insert(first, last);
216 }
217
1db90a1 Added initializer_list ctors to sorted_vector_{set,map}
Soren Lassen authored
218 explicit sorted_vector_set(
219 std::initializer_list<value_type> list,
220 const Compare& comp = Compare(),
221 const Allocator& alloc = Allocator())
222 : m_(comp, alloc)
223 {
224 insert(list.begin(), list.end());
225 }
226
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
227 key_compare key_comp() const { return m_; }
228 value_compare value_comp() const { return m_; }
229
230 iterator begin() { return m_.cont_.begin(); }
231 iterator end() { return m_.cont_.end(); }
232 const_iterator begin() const { return m_.cont_.begin(); }
233 const_iterator end() const { return m_.cont_.end(); }
234 reverse_iterator rbegin() { return m_.cont_.rbegin(); }
235 reverse_iterator rend() { return m_.cont_.rend(); }
236 const_reverse_iterator rbegin() const { return m_.cont_.rbegin(); }
237 const_reverse_iterator rend() const { return m_.cont_.rend(); }
238
239 void clear() { return m_.cont_.clear(); }
240 size_type size() const { return m_.cont_.size(); }
241 size_type max_size() const { return m_.cont_.max_size(); }
242 bool empty() const { return m_.cont_.empty(); }
243 void reserve(size_type s) { return m_.cont_.reserve(s); }
7ce3384 sorted_vector containers have a shrink_to_fit() method
Marc Celani authored
244 void shrink_to_fit() { m_.cont_.shrink_to_fit(); }
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
245 size_type capacity() const { return m_.cont_.capacity(); }
246
247 std::pair<iterator,bool> insert(const value_type& value) {
cc4eb4c sorted_vector_types have move inserts
Marc Celani authored
248 return insert(value_type(value));
249 }
250
251 std::pair<iterator,bool> insert(value_type&& value) {
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
252 iterator it = lower_bound(value);
253 if (it == end() || value_comp()(value, *it)) {
254 it = get_growth_policy().increase_capacity(m_.cont_, it);
cc4eb4c sorted_vector_types have move inserts
Marc Celani authored
255 return std::make_pair(m_.cont_.insert(it, std::move(value)), true);
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
256 }
257 return std::make_pair(it, false);
258 }
259
c363387 sorted_vector_types does not work with std::inserter
Marc Celani authored
260 iterator insert(iterator hint, const value_type& value) {
cc4eb4c sorted_vector_types have move inserts
Marc Celani authored
261 return insert(hint, value_type(value));
262 }
263
264 iterator insert(iterator hint, value_type&& value) {
265 return detail::insert_with_hint(*this, m_.cont_, hint, std::move(value),
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
266 get_growth_policy());
267 }
268
269 template<class InputIterator>
270 void insert(InputIterator first, InputIterator last) {
271 int d = detail::distance_if_multipass(first, last);
272 if (d != -1) {
273 m_.cont_.reserve(m_.cont_.size() + d);
274 }
275 for (; first != last; ++first) {
276 insert(end(), *first);
277 }
278 }
279
280 size_type erase(const key_type& key) {
281 iterator it = lower_bound(key);
282 if (it == end()) {
283 return 0;
284 }
285 m_.cont_.erase(it);
286 return 1;
287 }
288
289 void erase(iterator it) {
290 m_.cont_.erase(it);
291 }
292
293 void erase(iterator first, iterator last) {
294 m_.cont_.erase(first, last);
295 }
296
297 iterator find(const key_type& key) {
298 iterator it = lower_bound(key);
299 if (it == end() || !key_comp()(key, *it))
300 return it;
301 return end();
302 }
303
304 const_iterator find(const key_type& key) const {
305 const_iterator it = lower_bound(key);
306 if (it == end() || !key_comp()(key, *it))
307 return it;
308 return end();
309 }
310
311 size_type count(const key_type& key) const {
312 return find(key) == end() ? 0 : 1;
313 }
314
315 iterator lower_bound(const key_type& key) {
316 return std::lower_bound(begin(), end(), key, key_comp());
317 }
318
319 const_iterator lower_bound(const key_type& key) const {
320 return std::lower_bound(begin(), end(), key, key_comp());
321 }
322
323 iterator upper_bound(const key_type& key) {
324 return std::upper_bound(begin(), end(), key, key_comp());
325 }
326
327 const_iterator upper_bound(const key_type& key) const {
328 return std::upper_bound(begin(), end(), key, key_comp());
329 }
330
331 std::pair<iterator,iterator> equal_range(const key_type& key) {
332 return std::equal_range(begin(), end(), key, key_comp());
333 }
334
335 std::pair<const_iterator,const_iterator>
336 equal_range(const key_type& key) const {
337 return std::equal_range(begin(), end(), key, key_comp());
338 }
339
340 // Nothrow as long as swap() on the Compare type is nothrow.
341 void swap(sorted_vector_set& o) {
342 using std::swap; // Allow ADL for swap(); fall back to std::swap().
343 Compare& a = m_;
344 Compare& b = o.m_;
345 swap(a, b);
346 m_.cont_.swap(o.m_.cont_);
347 }
348
349 bool operator==(const sorted_vector_set& other) const {
350 return other.m_.cont_ == m_.cont_;
351 }
352
353 bool operator<(const sorted_vector_set& other) const {
354 return m_.cont_ < other.m_.cont_;
355 }
356
357 private:
358 /*
359 * This structure derives from the comparison object in order to
360 * make use of the empty base class optimization if our comparison
361 * functor is an empty class (usual case).
362 *
363 * Wrapping up this member like this is better than deriving from
364 * the Compare object ourselves (there are some perverse edge cases
365 * involving virtual functions).
366 *
367 * More info: http://www.cantrip.org/emptyopt.html
368 */
369 struct EBO : Compare {
370 explicit EBO(const Compare& c, const Allocator& alloc)
371 : Compare(c)
372 , cont_(alloc)
373 {}
374 ContainerT cont_;
375 } m_;
376 };
377
378 // Swap function that can be found using ADL.
379 template<class T, class C, class A, class G>
380 inline void swap(sorted_vector_set<T,C,A,G>& a,
381 sorted_vector_set<T,C,A,G>& b) {
382 return a.swap(b);
383 }
384
385 //////////////////////////////////////////////////////////////////////
386
387 /**
388 * A sorted_vector_map is similar to a sorted_vector_set but stores
389 * <key,value> pairs instead of single elements.
390 *
391 * @param class Key Key type
392 * @param class Value Value type
393 * @param class Compare Function that can compare key types and impose
394 * a strict weak ordering over them.
395 * @param class Allocator allocation policy
396 * @param class GrowthPolicy policy object to control growth
397 *
398 * @author Aditya Agarwal <aditya@fb.com>
399 * @author Akhil Wable <akhil@fb.com>
400 * @author Jordan DeLong <delong.j@fb.com>
401 */
402 template<class Key,
403 class Value,
404 class Compare = std::less<Key>,
405 class Allocator = std::allocator<std::pair<Key,Value> >,
406 class GrowthPolicy = void>
407 class sorted_vector_map
408 : boost::totally_ordered1<
409 sorted_vector_map<Key,Value,Compare,Allocator,GrowthPolicy>
410 , detail::growth_policy_wrapper<GrowthPolicy> >
411 {
412 typedef std::vector<std::pair<Key,Value>,Allocator> ContainerT;
413
414 detail::growth_policy_wrapper<GrowthPolicy>&
415 get_growth_policy() { return *this; }
416
417 public:
418 typedef Key key_type;
419 typedef Value mapped_type;
420 typedef std::pair<key_type,mapped_type> value_type;
421 typedef Compare key_compare;
422
423 struct value_compare
424 : std::binary_function<value_type,value_type,bool>
425 , private Compare
426 {
427 bool operator()(const value_type& a, const value_type& b) const {
428 return Compare::operator()(a.first, b.first);
429 }
430
431 protected:
432 friend class sorted_vector_map;
433 explicit value_compare(const Compare& c) : Compare(c) {}
434 };
435
436 typedef typename ContainerT::pointer pointer;
437 typedef typename ContainerT::reference reference;
438 typedef typename ContainerT::const_reference const_reference;
439 typedef typename ContainerT::iterator iterator;
440 typedef typename ContainerT::const_iterator const_iterator;
441 typedef typename ContainerT::difference_type difference_type;
442 typedef typename ContainerT::size_type size_type;
443 typedef typename ContainerT::reverse_iterator reverse_iterator;
444 typedef typename ContainerT::const_reverse_iterator const_reverse_iterator;
445
446 explicit sorted_vector_map(const Compare& comp = Compare(),
447 const Allocator& alloc = Allocator())
448 : m_(value_compare(comp), alloc)
449 {}
450
451 template<class InputIterator>
452 explicit sorted_vector_map(
453 InputIterator first,
454 InputIterator last,
455 const Compare& comp = Compare(),
456 const Allocator& alloc = Allocator())
457 : m_(value_compare(comp), alloc)
458 {
459 insert(first, last);
460 }
461
1db90a1 Added initializer_list ctors to sorted_vector_{set,map}
Soren Lassen authored
462 explicit sorted_vector_map(
463 std::initializer_list<value_type> list,
464 const Compare& comp = Compare(),
465 const Allocator& alloc = Allocator())
466 : m_(value_compare(comp), alloc)
467 {
468 insert(list.begin(), list.end());
469 }
470
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
471 key_compare key_comp() const { return m_; }
472 value_compare value_comp() const { return m_; }
473
474 iterator begin() { return m_.cont_.begin(); }
475 iterator end() { return m_.cont_.end(); }
476 const_iterator begin() const { return m_.cont_.begin(); }
477 const_iterator end() const { return m_.cont_.end(); }
478 reverse_iterator rbegin() { return m_.cont_.rbegin(); }
479 reverse_iterator rend() { return m_.cont_.rend(); }
480 const_reverse_iterator rbegin() const { return m_.cont_.rbegin(); }
481 const_reverse_iterator rend() const { return m_.cont_.rend(); }
482
483 void clear() { return m_.cont_.clear(); }
484 size_type size() const { return m_.cont_.size(); }
485 size_type max_size() const { return m_.cont_.max_size(); }
486 bool empty() const { return m_.cont_.empty(); }
487 void reserve(size_type s) { return m_.cont_.reserve(s); }
7ce3384 sorted_vector containers have a shrink_to_fit() method
Marc Celani authored
488 void shrink_to_fit() { m_.cont_.shrink_to_fit(); }
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
489 size_type capacity() const { return m_.cont_.capacity(); }
490
491 std::pair<iterator,bool> insert(const value_type& value) {
cc4eb4c sorted_vector_types have move inserts
Marc Celani authored
492 return insert(value_type(value));
493 }
494
495 std::pair<iterator,bool> insert(value_type&& value) {
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
496 iterator it = lower_bound(value.first);
497 if (it == end() || value_comp()(value, *it)) {
498 it = get_growth_policy().increase_capacity(m_.cont_, it);
cc4eb4c sorted_vector_types have move inserts
Marc Celani authored
499 return std::make_pair(m_.cont_.insert(it, std::move(value)), true);
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
500 }
501 return std::make_pair(it, false);
502 }
503
c363387 sorted_vector_types does not work with std::inserter
Marc Celani authored
504 iterator insert(iterator hint, const value_type& value) {
cc4eb4c sorted_vector_types have move inserts
Marc Celani authored
505 return insert(hint, value_type(value));
506 }
507
508 iterator insert(iterator hint, value_type&& value) {
509 return detail::insert_with_hint(*this, m_.cont_, hint, std::move(value),
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
510 get_growth_policy());
511 }
512
513 template<class InputIterator>
514 void insert(InputIterator first, InputIterator last) {
515 int d = detail::distance_if_multipass(first, last);
516 if (d != -1) {
517 m_.cont_.reserve(m_.cont_.size() + d);
518 }
519 for (; first != last; ++first) {
520 insert(end(), *first);
521 }
522 }
523
524 size_type erase(const key_type& key) {
525 iterator it = find(key);
526 if (it == end()) {
527 return 0;
528 }
529 m_.cont_.erase(it);
530 return 1;
531 }
532
533 void erase(iterator it) {
534 m_.cont_.erase(it);
535 }
536
537 void erase(iterator first, iterator last) {
538 m_.cont_.erase(first, last);
539 }
540
541 iterator find(const key_type& key) {
542 iterator it = lower_bound(key);
543 if (it == end() || !key_comp()(key, it->first))
544 return it;
545 return end();
546 }
547
548 const_iterator find(const key_type& key) const {
549 const_iterator it = lower_bound(key);
550 if (it == end() || !key_comp()(key, it->first))
551 return it;
552 return end();
553 }
554
32654ab Add folly::sorted_vector_map::at()
Louis Kruger authored
555 mapped_type& at(const key_type& key) {
556 iterator it = find(key);
557 if (it != end()) {
558 return it->second;
559 }
560 throw std::out_of_range("sorted_vector_map::at");
561 }
562
563 const mapped_type& at(const key_type& key) const {
564 const_iterator it = find(key);
565 if (it != end()) {
566 return it->second;
567 }
568 throw std::out_of_range("sorted_vector_map::at");
569 }
570
78f3142 const'ing sorted_vector_map::count()
Tom Jackson authored
571 size_type count(const key_type& key) const {
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
572 return find(key) == end() ? 0 : 1;
573 }
574
575 iterator lower_bound(const key_type& key) {
576 return std::lower_bound(begin(), end(), key,
577 boost::bind(key_comp(), boost::bind(&value_type::first, _1), _2));
578 }
579
580 const_iterator lower_bound(const key_type& key) const {
581 return std::lower_bound(begin(), end(), key,
582 boost::bind(key_comp(), boost::bind(&value_type::first, _1), _2));
583 }
584
585 iterator upper_bound(const key_type& key) {
586 return std::upper_bound(begin(), end(), key,
587 boost::bind(key_comp(), _1, boost::bind(&value_type::first, _2)));
588 }
589
590 const_iterator upper_bound(const key_type& key) const {
591 return std::upper_bound(begin(), end(), key,
592 boost::bind(key_comp(), _1, boost::bind(&value_type::first, _2)));
593 }
594
595 std::pair<iterator,iterator> equal_range(const key_type& key) {
596 // Note: std::equal_range can't be passed a functor that takes
597 // argument types different from the iterator value_type, so we
598 // have to do this.
599 iterator low = lower_bound(key);
600 iterator high = std::upper_bound(low, end(), key,
601 boost::bind(key_comp(), _1, boost::bind(&value_type::first, _2)));
602 return std::make_pair(low, high);
603 }
604
605 std::pair<const_iterator,const_iterator>
606 equal_range(const key_type& key) const {
607 return const_cast<sorted_vector_map*>(this)->equal_range(key);
608 }
609
610 // Nothrow as long as swap() on the Compare type is nothrow.
611 void swap(sorted_vector_map& o) {
612 using std::swap; // Allow ADL for swap(); fall back to std::swap().
613 Compare& a = m_;
614 Compare& b = o.m_;
615 swap(a, b);
616 m_.cont_.swap(o.m_.cont_);
617 }
618
619 mapped_type& operator[](const key_type& key) {
620 iterator it = lower_bound(key);
621 if (it == end() || key_comp()(key, it->first)) {
c363387 sorted_vector_types does not work with std::inserter
Marc Celani authored
622 return insert(it, value_type(key, mapped_type()))->second;
27494a2 jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
623 }
624 return it->second;
625 }
626
627 bool operator==(const sorted_vector_map& other) const {
628 return m_.cont_ == other.m_.cont_;
629 }
630
631 bool operator<(const sorted_vector_map& other) const {
632 return m_.cont_ < other.m_.cont_;
633 }
634
635 private:
636 // This is to get the empty base optimization; see the comment in
637 // sorted_vector_set.
638 struct EBO : value_compare {
639 explicit EBO(const value_compare& c, const Allocator& alloc)
640 : value_compare(c)
641 , cont_(alloc)
642 {}
643 ContainerT cont_;
644 } m_;
645 };
646
647 // Swap function that can be found using ADL.
648 template<class K, class V, class C, class A, class G>
649 inline void swap(sorted_vector_map<K,V,C,A,G>& a,
650 sorted_vector_map<K,V,C,A,G>& b) {
651 return a.swap(b);
652 }
653
654 //////////////////////////////////////////////////////////////////////
655
656 }
657
658 #endif
Something went wrong with that request. Please try again.