Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(215)

Side by Side Diff: base/containers/flat_set.h

Issue 2552343003: First implementation of flat sets (Closed)
Patch Set: Initial commit Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/BUILD.gn ('k') | base/containers/flat_set_libcpp_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef BASE_CONTAINERS_FLAT_SET_H_
6 #define BASE_CONTAINERS_FLAT_SET_H_
7
8 #include <algorithm>
9 #include <functional>
10 #include <utility>
11 #include <vector>
12
13 namespace base {
14
15 // Overview:
16 // This file implements flat_set container. It is an alternative to standard
17 // sorted containers that stores it's elements in contigious memory (current
18 // version uses sorted std::vector).
19 // Discussion that preceded introduction of this container can be found here:
20 // https://groups.google.com/a/chromium.org/forum/#!searchin/chromium-dev/vector $20based/chromium-dev/4uQMma9vj9w/HaQ-WvMOAwAJ
21 //
22 // Motivation:
23 // Contigious memory is very benefitial to iteration and copy speed at the cost
24 // of worse algorithmic complexity of insertion/erasure operations. They can
25 // be very fast for set operations and for small number of elements.
26 //
27 // Waring:
28 // Current version of flat sets is advised to be used only if you have good
29 // benchmarks and tests for your code: bevare of bugs and potential performance
30 // pitfalls.
31 //
32 // Important usability aspects:
33 // * flat_set implements std::set interface from C++11 where possible. It
34 // also hase capasity and shrink_to_fit from vector.
35 // * iteration invalidation rules differ:
36 // - all cases of vector::iterator invalidation also apply
37 // - we ask (for now) not to rely on the fact that move operations do not
38 // invalidate iterators - we would like to research a possibility of using
39 // a small buffer.
40 // * allocator support was not tested and we might to deside to use underlying
41 // type customisation instead.
42 //
43 // Tests:
44 // flast_set_libcpp_unittest.cc - partially adapted unittests for std::set from
45 // libcpp.
46 // flat_set_unittest.cc - our extra tests (libcpp's one do not cover
47 // everything).
48 //
49 // Benchmarks:
50 // (Please, if you add a benchmark that is heavily affected by the performance
51 // of flat_sets, list it below.)
52 // (soon) components_perftests.HQPPerfTestOnePopularURL*
53 //
54 // Notes:
55 // Current implementation is not particulary tweaked and based on
56 // boost::containers::flat_set, eastl::vector_set and folly::sorted_vector.
57 // All of these implementations do insert(first, last) as insertion one by one
58 // (some implementations with hints and/or reserve). Boost documentation claims
59 // this algorithm to be O(n*log2(n)) but it seems to just be a good quadratic
60 // algorithm. We will refer to it is as O(n^2).
61 //
62
63 template <class Key,
64 class Compare = std::less<Key>, // instead of std::default_order_t
65 class Allocator = std::allocator<Key>>
66 // Meets the requirements of Container, AllocatorAwareContainer,
67 // AssociativeContainer, ReversibleContainer.
68 // Requires:
69 // Key is Movable
70 // Compare defines strict weak ordering on Key
71 class flat_set {
72 // pritvate types much easier to declaer before everything else in templates.
73 using underlying_type = std::vector<Key, Allocator>;
74
75 public:
76 // types:
77 // Some of these typedefs were using types from allocator but we can refer
78 // them to the underlying_type to avoid any problems that might occur.
79 using key_type = Key;
80 using key_compare = Compare;
81 using value_type = Key;
82 using value_compare = Compare;
83 using allocator_type = typename underlying_type::allocator_type;
84
85 using pointer = typename underlying_type::pointer;
86 using const_pointer = typename underlying_type::const_pointer;
87 using reference = typename underlying_type::reference;
88 using const_reference = typename underlying_type::const_reference;
89 using size_type = typename underlying_type::size_type;
90 using difference_type = typename underlying_type::difference_type;
91 using iterator = typename underlying_type::iterator;
92 using const_iterator = typename underlying_type::const_iterator;
93 using reverse_iterator = typename underlying_type::reverse_iterator;
94 using const_reverse_iterator =
95 typename underlying_type::const_reverse_iterator;
96
97 // Default constructor. Constructs empty container.
98 flat_set();
99 explicit flat_set(const Compare& comp, const Allocator& alloc = Allocator());
100 explicit flat_set(const Allocator& alloc);
101
102 // Range constructor. Constructs the container with the contents of the range
103 // [first, last).
104 // O(n) if first last is sorted
105 // O(n^2) for general case.
106 template <class InputIterator>
107 flat_set(InputIterator first,
108 InputIterator last,
109 const Compare& comp = Compare(),
110 const Allocator& alloc = Allocator());
111
112 template <class InputIterator>
113 flat_set(InputIterator first, InputIterator last, const Allocator& alloc);
114
115 // Copy constructor. Constructs the container with the copy of the contents of
116 // other.
117 flat_set(const flat_set& x) = default;
118 flat_set(const flat_set& x, const Allocator& alloc);
119
120 // Move constructor. Constructs the container with the contents of other using
121 // move semantics.
122 //
123 // Assume that all iterators and references are invalidated.
124 flat_set(flat_set&& x) = default;
125 flat_set(flat_set&& x, const Allocator& alloc);
126
127 // Initializer-list constructor. Constructs the container with the contents of
128 // the initializer list.
129 flat_set(std::initializer_list<value_type> il,
130 const Compare& comp = Compare(),
131 const Allocator& alloc = Allocator());
132 flat_set(std::initializer_list<value_type> il, const Allocator& a);
133
134 // Destructs the container. The destructors of the elements are called and the
135 // used storage is deallocated.
136 ~flat_set() = default;
137
138 // Copy assignment operator. Replaces the contents with a copy of the contents
139 // of other
140 flat_set& operator=(const flat_set& x) = default;
141
142 // Move assignment operator. Replaces the contents with those of other using
143 // move semantics (i.e. the data in other is moved from other into this
144 // container). other is in a valid but unspecified state afterwards.
145 //
146 // Assume that all iterators and references are invalidated.
147 flat_set& operator=(flat_set&& x) = default;
148
149 // Replaces the contents with those identified by initializer list.
150 flat_set& operator=(std::initializer_list<value_type> il);
151
152 // Returns the allocator associated with the container. (* not tested)
153 allocator_type get_allocator() const;
154
155 // Increase the capacity of the container to a value that's greater or equal
156 // to size. If size is greater than the current capacity(), new storage
157 // is allocated, otherwise the method does nothing. If new_cap is greater than
158 // capacity(), all iterators and references, including the past-the-end
159 // iterator, are invalidated. Otherwise, no iterators or references are
160 // invalidated.
161 void reserve(size_type size);
162
163 // Returns the number of elements that the container has currently allocated
164 // space for.
165 size_type capacity() const;
166
167 // Requests the removal of unused capacity. It is a non-binding request to
168 // reduce capacity() to size(). It depends on the implementation if the
169 // request is fulfilled. If reallocation occurs, all iterators, including the
170 // past the end iterator, are invalidated. If no reallocation takes place,
171 // they remain valid.
172 void shrink_to_fit();
173
174 // Removes all elements from the container.
175 // Invalidates any references, pointers, or iterators referring to contained
176 // elements. Any past-the-end iterators are also invalidated. Leaves the
177 // capacity() of the flat_set unchanged
178 void clear();
179
180 // Returns an iterator to the first element of the container.
181 // If the container is empty, the returned iterator will be equal to end()
182 iterator begin();
183 const_iterator begin() const;
184 const_iterator cbegin() const;
185
186 // Returns an iterator to the element following the last element of the
187 // container. This element acts as a placeholder; attempting to access it
188 // results in undefined behavior.
189 iterator end();
190 const_iterator end() const;
191 const_iterator cend() const;
192
193 // Returns a reverse iterator to the first element of the reversed container.
194 // It corresponds to the last element of the non-reversed container.
195 reverse_iterator rbegin();
196 const_reverse_iterator rbegin() const;
197 const_reverse_iterator crbegin() const;
198
199 // Returns a reverse iterator to the element following the last element of the
200 // reversed container. It corresponds to the element preceding the first
201 // element of the non-reversed container. This element acts as a placeholder,
202 // attempting to access it results in undefined behavior
203 reverse_iterator rend();
204 const_reverse_iterator rend() const;
205 const_reverse_iterator crend() const;
206
207 // Checks if the container has no elements, i.e. whether begin() == end().
208 bool empty() const;
209
210 // Returns the number of elements in the container, i.e.
211 // std::distance(begin(), end());
212 size_type size() const;
213
214 // Returns the maximum number of elements the container is able to hold due to
215 // system or library implementation limitations, i.e. std::distance(begin(),
216 // end()) for the largest container.
217 size_type max_size() const;
218
219 // Inserts element(s) into the container, if the container doesn't already
220 // contain an element with an equivalent key.
221
222 // Inserts value. Invalidate iterators, if the value was inserted.
223 std::pair<iterator, bool> insert(const value_type& x);
224 std::pair<iterator, bool> insert(value_type&& x);
225
226 // Inserts value in the position as close as possible (just prior) to hint.
227 // Invalidate iterators, if the value was inserted.
228 iterator insert(const_iterator position, const value_type& x);
229 iterator insert(const_iterator position, value_type&& x);
230
231 // Inserts elements from range [first, last). Invalidate iterators.
232 template <class InputIterator>
233 void insert(InputIterator first, InputIterator last);
234
235 // Inserts elements from initializer list. Invalidate iterators.
236 void insert(std::initializer_list<value_type> il);
237
238 // Inserts a new element into the container constructed in-place with the
239 // given args if there is no element with the key in the container.
240 // Invalidate iterators.
241 template <class... Args>
242 std::pair<iterator, bool> emplace(Args&&... args);
243
244 // Inserts a new element into the container as close as possible to the
245 // position just before hint.
246 // Invalidate iterators.
247 template <class... Args>
248 iterator emplace_hint(const_iterator position, Args&&... args);
249
250 // Removes specified elements from the container. All invalidate iterators.
251
252 // Removes the element at position. Position mast be a valid and
253 // dereferansable iterator. Return an iterator past the element
254 // removed from the position.
255 //
256 // Invalidate iterators.
257 iterator erase(iterator position);
258 iterator erase(const_iterator position);
259
260 // Removes the elements in the range [first; last), which must be a valid
261 // range in (*this). Returns iterator past the last removed element.
262 //
263 // Invalidates iterators.
264 iterator erase(const_iterator first, const_iterator last);
265
266 // Removes the element (if one exists) with the key equivalent to key. Returns
267 // number of elements removed.
268 //
269 // Invalidate iterators if x was removed.
270 size_type erase(const key_type& x);
271
272 // Exchanges the contents of the container with those of other. Assume that
273 // might invoke move or swap operations on individual elements.
274 //
275 // Assume that all iterators and references are invalidated.
276 void swap(flat_set&);
277
278 // Returns the function object that compares the keys, which is a copy of this
279 // container's constructor argument comp. It is the same as value_comp.
280 key_compare key_comp() const;
281
282 // Returns the function object that compares the values. It is the same as
283 // key_comp.
284 value_compare value_comp() const;
285
286 // Returns the number of elements with key that compares equivalent to the
287 // specified argument, which is either 1 or 0 since this container does not
288 // allow duplicates.
289 size_type count(const key_type& x) const;
290
291 // Finds an element with key equivalent to key.
292 iterator find(const key_type& x);
293 const_iterator find(const key_type& x) const;
294
295 // Returns a range containing all elements with the given key in the
296 // container. The range is defined by two iterators, one pointing to the first
297 // element that is not less than key and another pointing to the first element
298 // greater than key.
299 std::pair<iterator, iterator> equal_range(const key_type& x);
300 std::pair<const_iterator, const_iterator> equal_range(
301 const key_type& x) const;
302
303 // Returns an iterator pointing to the first element that is not less than
304 // key.
305 iterator lower_bound(const key_type& x);
306 const_iterator lower_bound(const key_type& x) const;
307
308 // Returns an iterator pointing to the first element that is greater than key.
309 iterator upper_bound(const key_type& x);
310 const_iterator upper_bound(const key_type& x) const;
311
312 // Comparison note: we compare (as std::set does) not using value_compare(),
313 // but using operations provided by types themselves. This allowes, for
314 // example, to keep sets in other sets without anything removing equivalvent
315 // but not equal sets.
316
317 // Checks if the contents of lhs and rhs are equal, that is, whether
318 // lhs.size() == rhs.size() and each element in lhs compares equal with the
319 // element in rhs at the same position.
320 friend bool operator==(const flat_set& lhs, const flat_set& rhs) {
321 return lhs.impl_.body_ == rhs.impl_.body_;
322 }
323
324 friend bool operator!=(const flat_set& lhs, const flat_set& rhs) {
325 return !operator==(lhs, rhs);
326 }
327
328 // Compares the contents of lhs and rhs lexicographically. The comparison is
329 // performed by a function equivalent to std::lexicographical_compare.
330 friend bool operator<(const flat_set& lhs, const flat_set& rhs) {
331 return lhs.impl_.body_ < rhs.impl_.body_;
332 }
333
334 friend bool operator>(const flat_set& lhs, const flat_set& rhs) {
335 return rhs < lhs;
336 }
337
338 friend bool operator>=(const flat_set& lhs, const flat_set& rhs) {
339 return !(lhs < rhs);
340 }
341
342 friend bool operator<=(const flat_set& lhs, const flat_set& rhs) {
343 return !(lhs > rhs);
344 }
345
346 friend void swap(flat_set& lhs, flat_set& rhs) { lhs.swap(rhs); }
347
348 private:
349 const flat_set& as_const() { return *this; }
350
351 iterator const_cast_it(const_iterator c_it) {
352 auto distance = std::distance(cbegin(), c_it);
353 return std::next(begin(), distance);
354 }
355
356 struct Impl : Compare { // empty base class optimisation
357
358 // forwarding constructor.
359 template <class Cmp, class... Body>
360 explicit Impl(Cmp&& compare_arg, Body&&... underlying_type_args)
361 : Compare(std::forward<Cmp>(compare_arg)),
362 body_(std::forward<Body>(underlying_type_args)...) {}
363
364 underlying_type body_;
365 } impl_;
366 };
367
368 template <class Key, class Compare, class Allocator>
369 flat_set<Key, Compare, Allocator>::flat_set() : flat_set(Compare()) {}
370
371 template <class Key, class Compare, class Allocator>
372 flat_set<Key, Compare, Allocator>::flat_set(const Compare& comp,
373 const Allocator& alloc)
374 : impl_(comp, alloc) {}
375
376 template <class Key, class Compare, class Allocator>
377 template <class InputIterator>
378 flat_set<Key, Compare, Allocator>::flat_set(InputIterator first,
379 InputIterator last,
380 const Compare& comp,
381 const Allocator& alloc)
382 : impl_(comp, alloc) {
383 insert(first, last);
384 }
385
386 template <class Key, class Compare, class Allocator>
387 flat_set<Key, Compare, Allocator>::flat_set(const Allocator& alloc)
388 : flat_set(Compare(), alloc) {}
389
390 template <class Key, class Compare, class Allocator>
391 flat_set<Key, Compare, Allocator>::flat_set(const flat_set& rhs,
392 const Allocator& alloc)
393 : impl_(rhs.key_comp(), rhs.impl_.body_, alloc) {}
394
395 template <class Key, class Compare, class Allocator>
396 flat_set<Key, Compare, Allocator>::flat_set(flat_set&& rhs,
397 const Allocator& alloc)
398 : impl_(rhs.key_comp(), std::move(rhs.impl_.body_), alloc) {}
399
400 template <class Key, class Compare, class Allocator>
401 flat_set<Key, Compare, Allocator>::flat_set(
402 std::initializer_list<value_type> il,
403 const Compare& comp,
404 const Allocator& alloc)
405 : flat_set(std::begin(il), std::end(il), comp, alloc) {}
406
407 template <class Key, class Compare, class Allocator>
408 template <class InputIterator>
409 flat_set<Key, Compare, Allocator>::flat_set(InputIterator first,
410 InputIterator last,
411 const Allocator& alloc)
412 : flat_set(first, last, Compare(), alloc) {}
413
414 template <class Key, class Compare, class Allocator>
415 flat_set<Key, Compare, Allocator>::flat_set(
416 std::initializer_list<value_type> il,
417 const Allocator& a)
418 : flat_set(il, Compare(), a) {}
419
420 template <class Key, class Compare, class Allocator>
421 auto flat_set<Key, Compare, Allocator>::operator=(
422 std::initializer_list<value_type> il) -> flat_set& {
423 clear();
424 insert(il);
425 return *this;
426 }
427
428 template <class Key, class Compare, class Allocator>
429 auto flat_set<Key, Compare, Allocator>::get_allocator() const
430 -> allocator_type {
431 return impl_.body_.get_allocator();
432 }
433
434 template <class Key, class Compare, class Allocator>
435 void flat_set<Key, Compare, Allocator>::reserve(size_type size) {
436 impl_.body_.reserve(size);
437 }
438
439 template <class Key, class Compare, class Allocator>
440 auto flat_set<Key, Compare, Allocator>::capacity() const -> size_type {
441 return impl_.body_.capacity();
442 }
443
444 template <class Key, class Compare, class Allocator>
445 void flat_set<Key, Compare, Allocator>::shrink_to_fit() {
446 impl_.body_.shrink_to_fit();
447 }
448
449 template <class Key, class Compare, class Allocator>
450 auto flat_set<Key, Compare, Allocator>::begin() -> iterator {
451 return impl_.body_.begin();
452 }
453
454 template <class Key, class Compare, class Allocator>
455 auto flat_set<Key, Compare, Allocator>::begin() const -> const_iterator {
456 return impl_.body_.begin();
457 }
458
459 template <class Key, class Compare, class Allocator>
460 auto flat_set<Key, Compare, Allocator>::end() -> iterator {
461 return impl_.body_.end();
462 }
463
464 template <class Key, class Compare, class Allocator>
465 auto flat_set<Key, Compare, Allocator>::end() const -> const_iterator {
466 return impl_.body_.end();
467 }
468
469 template <class Key, class Compare, class Allocator>
470 auto flat_set<Key, Compare, Allocator>::rbegin() -> reverse_iterator {
471 return impl_.body_.rbegin();
472 }
473
474 template <class Key, class Compare, class Allocator>
475 auto flat_set<Key, Compare, Allocator>::rbegin() const
476 -> const_reverse_iterator {
477 return impl_.body_.rbegin();
478 }
479
480 template <class Key, class Compare, class Allocator>
481 auto flat_set<Key, Compare, Allocator>::rend() -> reverse_iterator {
482 return impl_.body_.rend();
483 }
484
485 template <class Key, class Compare, class Allocator>
486 auto flat_set<Key, Compare, Allocator>::rend() const -> const_reverse_iterator {
487 return impl_.body_.rend();
488 }
489
490 template <class Key, class Compare, class Allocator>
491 auto flat_set<Key, Compare, Allocator>::cbegin() const -> const_iterator {
492 return impl_.body_.cbegin();
493 }
494
495 template <class Key, class Compare, class Allocator>
496 auto flat_set<Key, Compare, Allocator>::cend() const -> const_iterator {
497 return impl_.body_.cend();
498 }
499
500 template <class Key, class Compare, class Allocator>
501 auto flat_set<Key, Compare, Allocator>::crbegin() const
502 -> const_reverse_iterator {
503 return impl_.body_.crbegin();
504 }
505
506 template <class Key, class Compare, class Allocator>
507 auto flat_set<Key, Compare, Allocator>::crend() const
508 -> const_reverse_iterator {
509 return impl_.body_.crend();
510 }
511
512 template <class Key, class Compare, class Allocator>
513 bool flat_set<Key, Compare, Allocator>::empty() const {
514 return impl_.body_.empty();
515 }
516
517 template <class Key, class Compare, class Allocator>
518 auto flat_set<Key, Compare, Allocator>::size() const -> size_type {
519 return impl_.body_.size();
520 }
521
522 template <class Key, class Compare, class Allocator>
523 auto flat_set<Key, Compare, Allocator>::max_size() const -> size_type {
524 return impl_.body_.max_size();
525 }
526
527 template <class Key, class Compare, class Allocator>
528 template <class... Args>
529 auto flat_set<Key, Compare, Allocator>::emplace(Args&&... args)
530 -> std::pair<iterator, bool> {
531 return insert(value_type(std::forward<Args>(args)...));
532 }
533
534 template <class Key, class Compare, class Allocator>
535 template <class... Args>
536 auto flat_set<Key, Compare, Allocator>::emplace_hint(const_iterator position,
537 Args&&... args)
538 -> iterator {
539 return insert(position, value_type(std::forward<Args>(args)...));
540 }
541
542 // Current optimised version of using a hint is taken from eastl:
543 // https://github.com/electronicarts/EASTL/blob/master/include/EASTL/vector_set. h#L493
544 //
545 // We duplicate code between copy and move version so that we can avoid
546 // creating a temporary value.
547 template <class Key, class Compare, class Allocator>
548 auto flat_set<Key, Compare, Allocator>::insert(const value_type& x)
549 -> std::pair<iterator, bool> {
550 auto position = lower_bound(x);
551
552 if (position != end() && !value_comp()(x, *position))
Peter Kasting 2016/12/12 20:34:30 This condition is basically the negation of the on
dyaroshev 2016/12/15 14:28:00 Done.
553 return {position, false};
554
555 return {impl_.body_.insert(position, x), true};
556 }
557
558 template <class Key, class Compare, class Allocator>
559 auto flat_set<Key, Compare, Allocator>::insert(value_type&& x)
560 -> std::pair<iterator, bool> {
561 auto position = lower_bound(x);
562
563 if (position != end() && !value_comp()(x, *position))
564 return {position, false};
565
566 return {impl_.body_.insert(position, std::move(x)), true};
567 }
568
569 template <class Key, class Compare, class Allocator>
570 auto flat_set<Key, Compare, Allocator>::insert(const_iterator position,
571 const value_type& x)
572 -> iterator {
573 if (position == end() || value_comp()(x, *position))
574 if (position == begin() || value_comp()(*(position - 1), x))
Peter Kasting 2016/12/12 20:34:30 Nit: Either add braces to outer conditional (body
dyaroshev 2016/12/15 14:28:00 Done.
575 return impl_.body_.insert(position, x);
576 return insert(x).first;
577 }
578
579 template <class Key, class Compare, class Allocator>
580 auto flat_set<Key, Compare, Allocator>::insert(const_iterator position,
581 value_type&& x) -> iterator {
582 if (position == end() || value_comp()(x, *position))
583 if (position == begin() || value_comp()(*(position - 1), x))
584 return impl_.body_.insert(position, std::move(x));
585 return insert(std::move(x)).first;
586 }
587
588 template <class Key, class Compare, class Allocator>
589 template <class InputIterator>
590 void flat_set<Key, Compare, Allocator>::insert(InputIterator first,
591 InputIterator last) {
592 std::copy(first, last, std::inserter(*this, end()));
593 }
594
595 template <class Key, class Compare, class Allocator>
596 void flat_set<Key, Compare, Allocator>::insert(
597 std::initializer_list<value_type> il) {
598 insert(il.begin(), il.end());
599 }
600
601 template <class Key, class Compare, class Allocator>
602 auto flat_set<Key, Compare, Allocator>::erase(iterator position) -> iterator {
603 return impl_.body_.erase(position);
604 }
605
606 template <class Key, class Compare, class Allocator>
607 auto flat_set<Key, Compare, Allocator>::erase(const_iterator position)
608 -> iterator {
609 return impl_.body_.erase(position);
610 }
611
612 template <class Key, class Compare, class Allocator>
613 auto flat_set<Key, Compare, Allocator>::erase(const key_type& x) -> size_type {
614 auto eq_range = equal_range(x);
615 auto res = std::distance(eq_range.first, eq_range.second);
616 erase(eq_range.first, eq_range.second);
617 return res;
618 }
619
620 template <class Key, class Compare, class Allocator>
621 auto flat_set<Key, Compare, Allocator>::erase(const_iterator first,
622 const_iterator last) -> iterator {
623 return impl_.body_.erase(first, last);
624 }
625
626 template <class Key, class Compare, class Allocator>
627 void flat_set<Key, Compare, Allocator>::swap(flat_set& rhs) {
628 std::swap(impl_, rhs.impl_);
629 }
630
631 template <class Key, class Compare, class Allocator>
632 void flat_set<Key, Compare, Allocator>::clear() {
633 impl_.body_.clear();
634 }
635
636 template <class Key, class Compare, class Allocator>
637 auto flat_set<Key, Compare, Allocator>::key_comp() const -> key_compare {
638 return impl_;
639 }
640
641 template <class Key, class Compare, class Allocator>
642 auto flat_set<Key, Compare, Allocator>::value_comp() const -> value_compare {
643 return impl_;
644 }
645
646 template <class Key, class Compare, class Allocator>
647 auto flat_set<Key, Compare, Allocator>::find(const key_type& x) -> iterator {
648 return const_cast_it(as_const().find(x));
649 }
650
651 template <class Key, class Compare, class Allocator>
652 auto flat_set<Key, Compare, Allocator>::find(const key_type& x) const
653 -> const_iterator {
654 auto eq_range = equal_range(x);
655 if (eq_range.first == eq_range.second)
656 return end();
657 return eq_range.first;
658 }
659
660 template <class Key, class Compare, class Allocator>
661 auto flat_set<Key, Compare, Allocator>::count(const key_type& x) const
662 -> size_type {
663 auto eq_range = equal_range(x);
664 return std::distance(eq_range.first, eq_range.second);
665 }
666
667 template <class Key, class Compare, class Allocator>
668 auto flat_set<Key, Compare, Allocator>::lower_bound(const key_type& x)
669 -> iterator {
670 auto res = as_const().lower_bound(x);
Peter Kasting 2016/12/12 20:34:30 Nit: Inline into next statement?
dyaroshev 2016/12/15 14:28:00 Done.
671 return const_cast_it(res);
672 }
673
674 template <class Key, class Compare, class Allocator>
675 auto flat_set<Key, Compare, Allocator>::lower_bound(const key_type& x) const
676 -> const_iterator {
677 return std::lower_bound(begin(), end(), x, key_comp());
678 }
679
680 template <class Key, class Compare, class Allocator>
681 auto flat_set<Key, Compare, Allocator>::upper_bound(const key_type& x)
682 -> iterator {
683 auto res = as_const().upper_bound(x);
Peter Kasting 2016/12/12 20:34:30 Nit: Inline into next statement?
dyaroshev 2016/12/15 14:28:00 Done.
684 return const_cast_it(res);
685 }
686
687 template <class Key, class Compare, class Allocator>
688 auto flat_set<Key, Compare, Allocator>::upper_bound(const key_type& x) const
689 -> const_iterator {
690 return std::upper_bound(begin(), end(), x, key_comp());
691 }
692
693 template <class Key, class Compare, class Allocator>
694 auto flat_set<Key, Compare, Allocator>::equal_range(const key_type& x)
695 -> std::pair<iterator, iterator> {
696 auto res = as_const().equal_range(x);
697 return {const_cast_it(res.first), const_cast_it(res.second)};
698 }
699
700 template <class Key, class Compare, class Allocator>
701 auto flat_set<Key, Compare, Allocator>::equal_range(const key_type& x) const
702 -> std::pair<const_iterator, const_iterator> {
703 auto lower = lower_bound(x);
704
705 if (lower == end() || key_comp()(x, *lower)) {
Peter Kasting 2016/12/12 20:34:30 Nit: No {} (you generally don't use them for one-l
dyaroshev 2016/12/15 14:28:00 Done.
706 return {lower, lower};
707 }
708
709 return {lower, std::next(lower)};
710 }
711
712 } // namespace base
713
714 #endif // BASE_CONTAINERS_FLAT_SET_H_
OLDNEW
« no previous file with comments | « base/BUILD.gn ('k') | base/containers/flat_set_libcpp_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698