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

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

Issue 2552343003: First implementation of flat sets (Closed)
Patch Set: Review, round 6. Created 3 years, 11 months 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_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.
danakj 2017/01/26 23:18:07 2017
dyaroshev 2017/01/30 00:07:11 Done.
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 contiguous 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 // Contiguous memory is very beneficial 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:
danakj 2017/01/26 23:18:07 Do you mean Warning?
dyaroshev 2017/01/30 00:07:12 Done.
28 // Current version of flat sets is advised to be used only if you have good
29 // benchmarks and tests for your code: beware of bugs and potential performance
danakj 2017/01/26 23:18:07 I would like to provide some guidance on when this
dyaroshev 2017/01/27 00:46:36 I have an old pc laptop, on weekend I can try to i
dyaroshev 2017/01/30 00:07:12 Writing a good microbenchmark turned out to be har
danakj 2017/01/30 20:24:30 I think that you should give some size limit in th
30 // pitfalls.
danakj 2017/01/26 23:18:07 Can you TODO to crbug.com/682215 here
31 //
32 // Important usability aspects:
33 // * flat_set implements std::set interface from C++11 where possible. It
34 // also has reserve(), capacity() and shrink_to_fit() from std::vector.
35 // * iteration invalidation rules differ:
36 // - all cases of std::vector::iterator invalidation also apply
37 // - we ask (for now) not to rely on the fact that move operations do not
danakj 2017/01/26 23:18:07 this is easier to read if you invert it to not use
38 // invalidate iterators.
39 // TODO(dyaroshev): Research the possibility of using a small buffer
40 // crbug.com/682240.
41 // * allocator support was not tested and we might to decide to use underlying
danakj 2017/01/26 23:18:06 "we might decide". Although I think we should drop
dyaroshev 2017/01/30 00:07:13 Done.
42 // type customization instead.
43 //
44 // TODO(dyaroshev): Add list of benchmarks heavily affected by performance
45 // of flat_sets crbug.com/682215.
46 //
47 // Notes:
48 // Current implementation is based on boost::containers::flat_set,
49 // eastl::vector_set and folly::sorted_vector. All of these implementations do
50 // insert(first, last) as insertion one by one (some implementations with hints
51 // and/or reserve). Boost documentation claims this algorithm to be O(n*log2(n))
52 // but it seems to just be a good quadratic algorithm. We will refer to it is as
53 // O(n^2).
54 // TODO(dyaroshev): research better algorithm for range insertion
55 // crbug.com/682249.
56
57 template <class Key,
58 class Compare = std::less<Key>,
59 class Allocator = std::allocator<Key>>
60 // Meets the requirements of Container, AllocatorAwareContainer,
danakj 2017/01/26 23:18:07 extra space in there.
dyaroshev 2017/01/30 00:07:12 Done.
61 // AssociativeContainer, ReversibleContainer.
62 // Requires:
63 // Key is Movable
64 // Compare defines strict weak ordering on Key
65 class flat_set {
66 private:
67 // Private typedefs have to be declared higher than used.
danakj 2017/01/26 23:18:08 remove this comment. everything needs to be declar
dyaroshev 2017/01/30 00:07:12 Done.
68 using underlying_type = std::vector<Key, Allocator>;
69
70 public:
71 // --------------------------------------------------------------------------
72 // Types.
73 //
74 // Some of these typedefs in the proposal are defined based on allocator but
danakj 2017/01/26 23:18:08 which proposal is this speaking of? it's the first
dyaroshev 2017/01/30 00:07:12 Done.
75 // we define them in terms of underlying_type to avoid any subtleties.
76 using key_type = Key;
danakj 2017/01/26 23:18:07 How many of these typedefs do we need? Things like
dyaroshev 2017/01/27 00:46:36 This has to do with C++ container concept http://e
danakj 2017/01/27 22:10:11 That's a good point you bring up. We should forbid
dyaroshev 2017/01/30 00:07:12 Ok, last attempt after which I give up. a) I thin
danakj 2017/01/30 20:24:31 You have some good arguments for key/value compare
77 using key_compare = Compare;
78 using value_type = Key;
79 using value_compare = Compare;
80 using allocator_type = typename underlying_type::allocator_type;
81
82 using pointer = typename underlying_type::pointer;
83 using const_pointer = typename underlying_type::const_pointer;
84 using reference = typename underlying_type::reference;
85 using const_reference = typename underlying_type::const_reference;
86 using size_type = typename underlying_type::size_type;
87 using difference_type = typename underlying_type::difference_type;
88 using iterator = typename underlying_type::iterator;
89 using const_iterator = typename underlying_type::const_iterator;
90 using reverse_iterator = typename underlying_type::reverse_iterator;
91 using const_reverse_iterator =
92 typename underlying_type::const_reverse_iterator;
93
94 // --------------------------------------------------------------------------
95 // Lifetime.
96 //
97 // Constructors that take range guarantee O(n) complexity if the input range
98 // is sorted, otherwise - O(n^2).
99 //
100 // Assume that move constructors invalidate iterators and references.
101
102 flat_set();
103 explicit flat_set(const Compare& comp, const Allocator& alloc = Allocator());
104 explicit flat_set(const Allocator& alloc);
105
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 flat_set(const flat_set& x);
danakj 2017/01/26 23:18:06 use a name better than "x" please throughout
dyaroshev 2017/01/27 00:46:36 This is stl's original naming convention, used by
danakj 2017/01/27 22:10:11 Give it a name that is meaningful for what it is i
116 flat_set(const flat_set& x, const Allocator& alloc);
117
118 flat_set(flat_set&& x);
119 flat_set(flat_set&& x, const Allocator& alloc);
120
121 flat_set(std::initializer_list<value_type> il,
danakj 2017/01/26 23:18:06 https://google.github.io/styleguide/cppguide.html#
dyaroshev 2017/01/27 00:46:36 C++ standard calls this il: http://www.open-std.or
danakj 2017/01/27 22:10:11 "list" would better follow chromium/google naming
dyaroshev 2017/01/30 00:07:12 I changed to ilist, like on cppreference. I think
122 const Compare& comp = Compare(),
123 const Allocator& alloc = Allocator());
124 flat_set(std::initializer_list<value_type> il, const Allocator& a);
125
126 ~flat_set();
127
128 // --------------------------------------------------------------------------
129 // Assignments.
130 //
131 // Assume that move assignment invalidates iterators and references.
132
133 flat_set& operator=(const flat_set& x);
134 flat_set& operator=(flat_set&& x);
135 flat_set& operator=(std::initializer_list<value_type> il);
136
137 // --------------------------------------------------------------------------
138 // Memory management.
139 //
140 // Generally be cautious about using reserve. There is a potential to do
141 // insert more efficient if we insert into new memory. We do not take
danakj 2017/01/26 23:18:06 I'm not sure what this comment means TBH. When you
dyaroshev 2017/01/27 00:46:36 If we remove insert(first, last) this comment won'
dyaroshev 2017/01/30 00:07:12 Done.
142 // advantage of this possibility in current version but we might in the
143 // future.
144 //
145 // Beware that shrink_to_fit() simply forward to the underlying_type and
danakj 2017/01/26 23:18:08 forwards the request to
dyaroshev 2017/01/30 00:07:12 Done.
146 // according to c++ standard shrink_to_fit() is non-binding.
danakj 2017/01/26 23:18:07 "is non-binding" could be written more clearly as
dyaroshev 2017/01/30 00:07:12 Done.
147 //
148 // reserve() and shrink_to_fit() invalidate iterators and references.
149
150 allocator_type get_allocator() const;
151
152 void reserve(size_type size);
153 size_type capacity() const;
154 void shrink_to_fit();
155
156 // --------------------------------------------------------------------------
157 // Size management.
158 //
159 // clear() leaves the capacity() of the flat_set unchanged.
160
161 void clear();
162
163 size_type size() const;
164 size_type max_size() const;
165 bool empty() const;
166
167 // --------------------------------------------------------------------------
168 // Iterators.
169
170 iterator begin();
171 const_iterator begin() const;
172 const_iterator cbegin() const;
173
174 iterator end();
175 const_iterator end() const;
176 const_iterator cend() const;
177
178 reverse_iterator rbegin();
179 const_reverse_iterator rbegin() const;
180 const_reverse_iterator crbegin() const;
181
182 reverse_iterator rend();
183 const_reverse_iterator rend() const;
184 const_reverse_iterator crend() const;
185
186 // --------------------------------------------------------------------------
187 // Insert operations.
188 //
189 // Assume that every operation invalidates iterators and references.
190 // Insertion of one element can take O(size). See the Notes section in the
191 // class comments for more on range insertion. Capacity of flat_set grows in
192 // an implementation defined manner.
danakj 2017/01/26 23:18:07 implementation-defined
dyaroshev 2017/01/30 00:07:12 Done.
193
194 std::pair<iterator, bool> insert(const value_type& x);
195 std::pair<iterator, bool> insert(value_type&& x);
196
197 iterator insert(const_iterator position, const value_type& x);
198 iterator insert(const_iterator position, value_type&& x);
199
200 template <class InputIterator>
201 void insert(InputIterator first, InputIterator last);
202
203 void insert(std::initializer_list<value_type> il);
204
205 template <class... Args>
206 std::pair<iterator, bool> emplace(Args&&... args);
207
208 template <class... Args>
209 iterator emplace_hint(const_iterator position, Args&&... args);
210
211 // --------------------------------------------------------------------------
212 // Erase operations.
213 //
214 // Assume that every operation invalidates iterators and references. Removal
215 // of one element can take O(size). Prefer the erase(std::remove(), end())
216 // idiom for deleting multiple elements.
217
218 iterator erase(const_iterator position);
219
danakj 2017/01/26 23:18:08 nit: drop whitespace between overloads here
dyaroshev 2017/01/30 00:07:11 Done.
220 iterator erase(const_iterator first, const_iterator last);
221
222 size_type erase(const key_type& x);
danakj 2017/01/26 23:18:07 This is O(size) + O(log(size)) right? Mention that
dyaroshev 2017/01/30 00:07:12 Done.
223
224 // --------------------------------------------------------------------------
225 // Comparators.
226
227 key_compare key_comp() const;
228
229 value_compare value_comp() const;
230
231 // --------------------------------------------------------------------------
232 // Binary search operations.
danakj 2017/01/26 23:18:06 I would say Search operations. And mention that th
dyaroshev 2017/01/30 00:07:11 Done.
233
234 size_type count(const key_type& x) const;
235
236 iterator find(const key_type& x);
237 const_iterator find(const key_type& x) const;
238
239 std::pair<iterator, iterator> equal_range(const key_type& x);
240 std::pair<const_iterator, const_iterator> equal_range(
241 const key_type& x) const;
242
243 iterator lower_bound(const key_type& x);
244 const_iterator lower_bound(const key_type& x) const;
245
246 iterator upper_bound(const key_type& x);
247 const_iterator upper_bound(const key_type& x) const;
248
249 // --------------------------------------------------------------------------
250 // General operations.
251 //
252 // Assume that swap invalidates iterators and references.
253 //
254 // As with std::set, equality and ordering operations for the whole flat_set
255 // are equivalent to using equal() and lexicographical_compare() on the key
256 // types, rather than using element-wise key_comp() as e.g. lower_bound()
257 // does. Implementation note: currently we use operator==() and operator<() on
258 // std::vector, because they have the same contract we need, so we use them
259 // directly for brevity and in case it is more optimal than calling equal()
260 // and lexicograhpical_compare(). If the underlying container type is changed,
261 // this code may need to be modified.
262
263 void swap(flat_set& x);
264
265 friend bool operator==(const flat_set& x, const flat_set& y) {
266 return x.impl_.body_ == y.impl_.body_;
267 }
268
269 friend bool operator!=(const flat_set& x, const flat_set& y) {
270 return !operator==(x, y);
271 }
272
273 friend bool operator<(const flat_set& x, const flat_set& y) {
274 return x.impl_.body_ < y.impl_.body_;
275 }
276
277 friend bool operator>(const flat_set& x, const flat_set& y) { return y < x; }
danakj 2017/01/26 23:18:06 nit: it would be nice if the operator was the same
dyaroshev 2017/01/27 00:46:37 Ok. This is original stl's style again. Here is an
danakj 2017/01/27 22:10:11 That's ok I still prefer the other
dyaroshev 2017/01/30 00:07:12 If I were to implement it in terms of >, I would h
danakj 2017/01/30 20:24:30 Oh, right ya I'm thinking this is implemented on t
278
279 friend bool operator>=(const flat_set& x, const flat_set& y) {
280 return !(x < y);
281 }
282
283 friend bool operator<=(const flat_set& x, const flat_set& y) {
284 return !(y < x);
danakj 2017/01/26 23:18:08 nit: can you write this !(x>y) so its relationship
dyaroshev 2017/01/30 00:07:12 Done.
285 }
286
287 friend void swap(flat_set& x, flat_set& y) { x.swap(y); }
288
289 private:
290 const flat_set& as_const() { return *this; }
291
292 iterator const_cast_it(const_iterator c_it) {
danakj 2017/01/26 23:18:08 Would it work to define this this way for old GCC
danakj 2017/01/27 22:10:11 I see that we're using this in places that aren't
dyaroshev 2017/01/30 00:07:12 Done.
293 auto distance = std::distance(cbegin(), c_it);
294 return std::next(begin(), distance);
295 }
296
297 // To support comparators that may not be possible to default-construct, we
danakj 2017/01/26 23:18:07 Can you mention this is the storage for the underl
dyaroshev 2017/01/30 00:07:11 Done?
298 // have to store an instance of Compare. Using inheritance here lets us take
299 // advantage of the empty base class optimization to avoid extra space in the
300 // common case when Compare has no state.
301 struct Impl : Compare {
302 // forwarding constructor.
danakj 2017/01/26 23:18:06 "Forwarding". Tho, comments should say why, not wh
dyaroshev 2017/01/30 00:07:12 Done.
303 template <class Cmp, class... Body>
304 explicit Impl(Cmp&& compare_arg, Body&&... underlying_type_args)
305 : Compare(std::forward<Cmp>(compare_arg)),
306 body_(std::forward<Body>(underlying_type_args)...) {}
307
308 underlying_type body_;
309 } impl_;
310 };
311
312 // ----------------------------------------------------------------------------
313 // Lifetime.
314
315 template <class Key, class Compare, class Allocator>
316 flat_set<Key, Compare, Allocator>::flat_set() : flat_set(Compare()) {}
317
318 template <class Key, class Compare, class Allocator>
319 flat_set<Key, Compare, Allocator>::flat_set(const Compare& comp,
320 const Allocator& alloc)
321 : impl_(comp, alloc) {}
322
323 template <class Key, class Compare, class Allocator>
324 flat_set<Key, Compare, Allocator>::flat_set(const Allocator& alloc)
325 : flat_set(Compare(), alloc) {}
326
327 template <class Key, class Compare, class Allocator>
328 template <class InputIterator>
329 flat_set<Key, Compare, Allocator>::flat_set(InputIterator first,
330 InputIterator last,
331 const Compare& comp,
332 const Allocator& alloc)
333 : impl_(comp, alloc) {
334 insert(first, last);
335 }
336
337 template <class Key, class Compare, class Allocator>
338 template <class InputIterator>
339 flat_set<Key, Compare, Allocator>::flat_set(InputIterator first,
340 InputIterator last,
341 const Allocator& alloc)
342 : flat_set(first, last, Compare(), alloc) {}
343
344 template <class Key, class Compare, class Allocator>
345 flat_set<Key, Compare, Allocator>::flat_set(const flat_set& x) = default;
346
347 template <class Key, class Compare, class Allocator>
348 flat_set<Key, Compare, Allocator>::flat_set(const flat_set& x,
349 const Allocator& alloc)
350 : impl_(x.key_comp(), x.impl_.body_, alloc) {}
351
352 template <class Key, class Compare, class Allocator>
353 flat_set<Key, Compare, Allocator>::flat_set(flat_set&& x) = default;
354
355 template <class Key, class Compare, class Allocator>
356 flat_set<Key, Compare, Allocator>::flat_set(flat_set&& x,
357 const Allocator& alloc)
358 : impl_(x.key_comp(), std::move(x.impl_.body_), alloc) {}
359
360 template <class Key, class Compare, class Allocator>
361 flat_set<Key, Compare, Allocator>::flat_set(
362 std::initializer_list<value_type> il,
363 const Compare& comp,
364 const Allocator& alloc)
365 : flat_set(std::begin(il), std::end(il), comp, alloc) {}
366
367 template <class Key, class Compare, class Allocator>
368 flat_set<Key, Compare, Allocator>::flat_set(
369 std::initializer_list<value_type> il,
370 const Allocator& a)
371 : flat_set(il, Compare(), a) {}
372
373 template <class Key, class Compare, class Allocator>
374 flat_set<Key, Compare, Allocator>::~flat_set() = default;
375
376 // ----------------------------------------------------------------------------
377 // Assignments.
378
379 template <class Key, class Compare, class Allocator>
380 auto flat_set<Key, Compare, Allocator>::operator=(const flat_set& x)
381 -> flat_set& = default;
382
383 template <class Key, class Compare, class Allocator>
384 auto flat_set<Key, Compare, Allocator>::operator=(flat_set&& x)
385 -> flat_set& = default;
386
387 template <class Key, class Compare, class Allocator>
388 auto flat_set<Key, Compare, Allocator>::operator=(
389 std::initializer_list<value_type> il) -> flat_set& {
390 clear();
391 insert(il);
392 return *this;
393 }
394
395 // ----------------------------------------------------------------------------
396 // Memory management.
397
398 template <class Key, class Compare, class Allocator>
399 auto flat_set<Key, Compare, Allocator>::get_allocator() const
400 -> allocator_type {
401 return impl_.body_.get_allocator();
402 }
403
404 template <class Key, class Compare, class Allocator>
405 void flat_set<Key, Compare, Allocator>::reserve(size_type size) {
406 impl_.body_.reserve(size);
407 }
408
409 template <class Key, class Compare, class Allocator>
410 auto flat_set<Key, Compare, Allocator>::capacity() const -> size_type {
411 return impl_.body_.capacity();
412 }
413
414 template <class Key, class Compare, class Allocator>
415 void flat_set<Key, Compare, Allocator>::shrink_to_fit() {
416 impl_.body_.shrink_to_fit();
417 }
418
419 // ----------------------------------------------------------------------------
420 // Size management.
421
422 template <class Key, class Compare, class Allocator>
423 void flat_set<Key, Compare, Allocator>::clear() {
424 impl_.body_.clear();
425 }
426
427 template <class Key, class Compare, class Allocator>
428 auto flat_set<Key, Compare, Allocator>::size() const -> size_type {
429 return impl_.body_.size();
430 }
431
432 template <class Key, class Compare, class Allocator>
433 auto flat_set<Key, Compare, Allocator>::max_size() const -> size_type {
434 return impl_.body_.max_size();
435 }
436
437 template <class Key, class Compare, class Allocator>
438 bool flat_set<Key, Compare, Allocator>::empty() const {
439 return impl_.body_.empty();
440 }
441
442 // ----------------------------------------------------------------------------
443 // Iterators.
444
445 template <class Key, class Compare, class Allocator>
446 auto flat_set<Key, Compare, Allocator>::begin() -> iterator {
447 return impl_.body_.begin();
448 }
449
450 template <class Key, class Compare, class Allocator>
451 auto flat_set<Key, Compare, Allocator>::begin() const -> const_iterator {
452 return impl_.body_.begin();
453 }
454
455 template <class Key, class Compare, class Allocator>
456 auto flat_set<Key, Compare, Allocator>::cbegin() const -> const_iterator {
457 return impl_.body_.cbegin();
458 }
459
460 template <class Key, class Compare, class Allocator>
461 auto flat_set<Key, Compare, Allocator>::end() -> iterator {
462 return impl_.body_.end();
463 }
464
465 template <class Key, class Compare, class Allocator>
466 auto flat_set<Key, Compare, Allocator>::end() const -> const_iterator {
467 return impl_.body_.end();
468 }
469
470 template <class Key, class Compare, class Allocator>
471 auto flat_set<Key, Compare, Allocator>::cend() const -> const_iterator {
472 return impl_.body_.cend();
473 }
474
475 template <class Key, class Compare, class Allocator>
476 auto flat_set<Key, Compare, Allocator>::rbegin() -> reverse_iterator {
477 return impl_.body_.rbegin();
478 }
479
480 template <class Key, class Compare, class Allocator>
481 auto flat_set<Key, Compare, Allocator>::rbegin() const
482 -> const_reverse_iterator {
483 return impl_.body_.rbegin();
484 }
485
486 template <class Key, class Compare, class Allocator>
487 auto flat_set<Key, Compare, Allocator>::crbegin() const
488 -> const_reverse_iterator {
489 return impl_.body_.crbegin();
490 }
491
492 template <class Key, class Compare, class Allocator>
493 auto flat_set<Key, Compare, Allocator>::rend() -> reverse_iterator {
494 return impl_.body_.rend();
495 }
496
497 template <class Key, class Compare, class Allocator>
498 auto flat_set<Key, Compare, Allocator>::rend() const -> const_reverse_iterator {
499 return impl_.body_.rend();
500 }
501
502 template <class Key, class Compare, class Allocator>
503 auto flat_set<Key, Compare, Allocator>::crend() const
504 -> const_reverse_iterator {
505 return impl_.body_.crend();
506 }
507
508 // ----------------------------------------------------------------------------
509 // Insert operations.
510 //
511 // Currently we use hint the same way as eastl or boost:
danakj 2017/01/26 23:18:07 I'm not sure what "we use hint" here is referring
dyaroshev 2017/01/27 00:46:36 hint refers to insert(position, value_type) - this
danakj 2017/01/27 22:10:11 I would say "we use the position hint" here, and n
dyaroshev 2017/01/30 00:07:12 Done.
512 // https://github.com/electronicarts/EASTL/blob/master/include/EASTL/vector_set. h#L493
513 //
514 // We duplicate code between copy and move version so that we can avoid
515 // creating a temporary value.
516
517 template <class Key, class Compare, class Allocator>
518 auto flat_set<Key, Compare, Allocator>::insert(const value_type& x)
519 -> std::pair<iterator, bool> {
520 auto position = lower_bound(x);
521
522 if (position == end() || value_comp()(x, *position))
523 return {impl_.body_.insert(position, x), true};
524
525 return {position, false};
526 }
527
528 template <class Key, class Compare, class Allocator>
529 auto flat_set<Key, Compare, Allocator>::insert(value_type&& x)
530 -> std::pair<iterator, bool> {
531 auto position = lower_bound(x);
532
533 if (position == end() || value_comp()(x, *position))
534 return {impl_.body_.insert(position, std::move(x)), true};
535
536 return {position, false};
537 }
538
539 template <class Key, class Compare, class Allocator>
540 auto flat_set<Key, Compare, Allocator>::insert(const_iterator position,
541 const value_type& x)
542 -> iterator {
543 if (position == end() || value_comp()(x, *position)) {
544 if (position == begin() || value_comp()(*(position - 1), x))
545 // We have to cast away const because of crbug.com/677044.
546 return impl_.body_.insert(const_cast_it(position), x);
547 }
548 return insert(x).first;
549 }
550
551 template <class Key, class Compare, class Allocator>
552 auto flat_set<Key, Compare, Allocator>::insert(const_iterator position,
553 value_type&& x) -> iterator {
554 if (position == end() || value_comp()(x, *position)) {
555 if (position == begin() || value_comp()(*(position - 1), x))
556 // We have to cast away const because of crbug.com/677044.
557 return impl_.body_.insert(const_cast_it(position), std::move(x));
558 }
559 return insert(std::move(x)).first;
560 }
561
562 template <class Key, class Compare, class Allocator>
563 template <class InputIterator>
564 void flat_set<Key, Compare, Allocator>::insert(InputIterator first,
565 InputIterator last) {
566 std::copy(first, last, std::inserter(*this, end()));
danakj 2017/01/26 23:18:06 This function is O(size * (last-first)). We shoul
dyaroshev 2017/01/30 00:07:11 Done.
567 }
568
569 template <class Key, class Compare, class Allocator>
570 void flat_set<Key, Compare, Allocator>::insert(
571 std::initializer_list<value_type> il) {
572 insert(il.begin(), il.end());
danakj 2017/01/26 23:18:07 Same here.
dyaroshev 2017/01/30 00:07:12 Done.
573 }
574
575 template <class Key, class Compare, class Allocator>
576 template <class... Args>
577 auto flat_set<Key, Compare, Allocator>::emplace(Args&&... args)
578 -> std::pair<iterator, bool> {
579 return insert(value_type(std::forward<Args>(args)...));
danakj 2017/01/26 23:18:06 why does this not use the underlying type's emplac
dyaroshev 2017/01/27 00:46:36 Because I have to do binary search on it. I can't
danakj 2017/01/27 22:10:11 Ah I see that makes sense. I guess this API will b
dyaroshev 2017/01/30 00:07:11 It would still be implemented in the same way - yo
580 }
581
582 template <class Key, class Compare, class Allocator>
583 template <class... Args>
584 auto flat_set<Key, Compare, Allocator>::emplace_hint(const_iterator position,
585 Args&&... args)
586 -> iterator {
587 return insert(position, value_type(std::forward<Args>(args)...));
danakj 2017/01/26 23:18:06 why does this not use the underlying type's emplac
588 }
589
590 // ----------------------------------------------------------------------------
591 // Erase operations.
592
593 template <class Key, class Compare, class Allocator>
594 auto flat_set<Key, Compare, Allocator>::erase(const_iterator position)
595 -> iterator {
596 // We have to cast away const because of crbug.com/677044.
597 return impl_.body_.erase(const_cast_it(position));
598 }
599
600 template <class Key, class Compare, class Allocator>
601 auto flat_set<Key, Compare, Allocator>::erase(const key_type& x) -> size_type {
602 auto eq_range = equal_range(x);
603 auto res = std::distance(eq_range.first, eq_range.second);
604 // We have to cast away const because of crbug.com/677044.
605 erase(const_cast_it(eq_range.first), const_cast_it(eq_range.second));
606 return res;
607 }
608
609 template <class Key, class Compare, class Allocator>
610 auto flat_set<Key, Compare, Allocator>::erase(const_iterator first,
611 const_iterator last) -> iterator {
612 // We have to cast away const because of crbug.com/677044.
613 return impl_.body_.erase(const_cast_it(first), const_cast_it(last));
614 }
615
616 // ----------------------------------------------------------------------------
617 // Comparators.
618
619 template <class Key, class Compare, class Allocator>
620 auto flat_set<Key, Compare, Allocator>::key_comp() const -> key_compare {
621 return key_compare(impl_);
622 }
623
624 template <class Key, class Compare, class Allocator>
625 auto flat_set<Key, Compare, Allocator>::value_comp() const -> value_compare {
626 return value_compare(impl_);
627 }
628
629 // ----------------------------------------------------------------------------
630 // Binary search operations.
danakj 2017/01/26 23:18:07 Search operations. ?
dyaroshev 2017/01/30 00:07:12 Done.
631
632 template <class Key, class Compare, class Allocator>
633 auto flat_set<Key, Compare, Allocator>::count(const key_type& x) const
634 -> size_type {
635 auto eq_range = equal_range(x);
danakj 2017/01/26 23:18:06 Why is this written like this is a multiset? Is th
dyaroshev 2017/01/27 00:46:36 It's a call to our member function equal_range, no
danakj 2017/01/27 22:10:11 Ohh, right thanks. I probably woulda done this thr
dyaroshev 2017/01/30 00:07:12 Done.
636 return std::distance(eq_range.first, eq_range.second);
637 }
638
639 template <class Key, class Compare, class Allocator>
640 auto flat_set<Key, Compare, Allocator>::find(const key_type& x) -> iterator {
641 return const_cast_it(as_const().find(x));
642 }
643
644 template <class Key, class Compare, class Allocator>
645 auto flat_set<Key, Compare, Allocator>::find(const key_type& x) const
646 -> const_iterator {
647 auto eq_range = equal_range(x);
danakj 2017/01/26 23:18:08 Same, is this more efficient than lower_bound and
648 return (eq_range.first == eq_range.second) ? end() : eq_range.first;
649 }
650
651 template <class Key, class Compare, class Allocator>
652 auto flat_set<Key, Compare, Allocator>::equal_range(const key_type& x)
653 -> std::pair<iterator, iterator> {
654 auto res = as_const().equal_range(x);
danakj 2017/01/26 23:18:07 Same, is this more efficient than lower_bound, com
655 return {const_cast_it(res.first), const_cast_it(res.second)};
656 }
657
658 template <class Key, class Compare, class Allocator>
659 auto flat_set<Key, Compare, Allocator>::equal_range(const key_type& x) const
660 -> std::pair<const_iterator, const_iterator> {
661 auto lower = lower_bound(x);
662
663 if (lower == end() || key_comp()(x, *lower))
664 return {lower, lower};
665
666 return {lower, std::next(lower)};
667 }
668
669 template <class Key, class Compare, class Allocator>
670 auto flat_set<Key, Compare, Allocator>::lower_bound(const key_type& x)
671 -> iterator {
672 return const_cast_it(as_const().lower_bound(x));
danakj 2017/01/26 23:18:06 why not just call std::lower_bound here? const_cas
dyaroshev 2017/01/27 00:46:36 Can do that, but it's code duplication. const_cast
danakj 2017/01/27 22:10:11 That tool is very cool. Ok this seems fine then, t
dyaroshev 2017/01/30 00:07:12 It is! If you are interested - an awesome talk fro
673 }
674
675 template <class Key, class Compare, class Allocator>
676 auto flat_set<Key, Compare, Allocator>::lower_bound(const key_type& x) const
677 -> const_iterator {
678 return std::lower_bound(begin(), end(), x, key_comp());
679 }
680
681 template <class Key, class Compare, class Allocator>
682 auto flat_set<Key, Compare, Allocator>::upper_bound(const key_type& x)
683 -> iterator {
684 return const_cast_it(as_const().upper_bound(x));
danakj 2017/01/26 23:18:06 why not just call std::lower_bound here? const_cas
dyaroshev 2017/01/30 00:07:12 Done.
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 // ----------------------------------------------------------------------------
694 // General operations.
695
696 template <class Key, class Compare, class Allocator>
697 void flat_set<Key, Compare, Allocator>::swap(flat_set& rhs) {
698 std::swap(impl_, rhs.impl_);
699 }
700
701 } // namespace base
702
703 #endif // BASE_CONTAINERS_FLAT_SET_H_
OLDNEW
« no previous file with comments | « base/BUILD.gn ('k') | base/containers/flat_set_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698