OLD | NEW |
---|---|
(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_ | |
OLD | NEW |