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

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

Issue 2333253002: flat containers prototype (Closed)
Patch Set: Fixing performance bug in insert(It, It) 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
OLDNEW
(Empty)
1 // Copyright (c) 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_CONTAINTERS_FLAT_SORTED_CONTAINER_BASE_H_
6 #define BASE_CONTAINTERS_FLAT_SORTED_CONTAINER_BASE_H_
7
8 #include <algorithm>
9 #include <iterator>
10 #include <memory>
11 #include <utility>
12
13 namespace base {
14 namespace internal {
15
16 template <typename Compare>
17 struct sort_and_unique : private Compare {
18 template <typename Cont>
19 void operator()(Cont* rhs) {
20 using value_type = typename Cont::value_type;
21
22 std::sort(rhs->begin(), rhs->end(),
23 [this](const value_type& lhs, const value_type& rhs) {
24 return Compare::operator()(lhs, rhs);
25 });
26
27 rhs->erase(
28 std::unique(rhs->begin(), rhs->end(),
29 [this](const value_type& lhs, const value_type& rhs) {
30 return Compare::equal(lhs, rhs);
31 }),
32 rhs->end());
33 }
34 };
35
36 // Our version of standard library on linux does not have erase with const
37 // iterators. It's a hack around that.
38 template <typename Cont>
39 typename Cont::iterator non_const_iter(Cont* cont,
40 typename Cont::const_iterator iter) {
41 return std::next(cont->begin(), std::distance(cont->cbegin(), iter));
42 }
43
44 template <typename Compare, class UnderlyingType>
45 class flat_sorted_container_base {
46 public:
47 using compare = Compare;
48 using key_compare = compare;
49 using value_compare = compare;
50 using key_value_compare = compare;
51
52 using underlying_type = UnderlyingType;
53 using key_type = typename key_compare::key_type;
54 using value_type = typename key_compare::value_type;
55
56 using size_type = typename underlying_type::size_type;
57 using difference_type = typename underlying_type::difference_type;
58 using reference = typename underlying_type::reference;
59 using const_reference = typename underlying_type::const_reference;
60 using pointer = typename underlying_type::pointer;
61 using const_pointer = typename underlying_type::const_pointer;
62 using iterator = typename underlying_type::iterator;
63 using const_iterator = typename underlying_type::const_iterator;
64 using reverse_iterator = typename underlying_type::reverse_iterator;
65 using const_reverse_iterator =
66 typename underlying_type::const_reverse_iterator;
67
68 // scoped object to do operations on body, without keeping order
69 using unsafe_region =
70 std::unique_ptr<underlying_type, sort_and_unique<compare>>;
71
72 flat_sorted_container_base() {}
73
74 explicit flat_sorted_container_base(underlying_type body)
75 : body_(std::move(body)) {
76 unsafe_access();
77 }
78
79 template <typename It>
80 flat_sorted_container_base(It first, It last) : body_(first, last) {
81 unsafe_access();
82 }
83
84 // methods-------------------------------------------------------------------
85
86 // returns scoped object, that gives access to underlying storrage.
87 // at destruction, sorts and does unification.
88 //
89 // if you know, that on exit of the region, storrage is already sorted and
90 // unified - call unsafe_region::release()
91 unsafe_region unsafe_access() { return unsafe_region(&body_); }
92
93 // get_allocator()
94
95 iterator begin() { return body_.begin(); }
96 const_iterator begin() const { return body_.begin(); }
97 const_iterator cbegin() const { return body_.cbegin(); }
98
99 iterator end() { return body_.end(); }
100 const_iterator end() const { return body_.end(); }
101 const_iterator cend() const { return body_.cend(); }
102
103 reverse_iterator rbegin() { return body_.rbegin(); }
104 const_reverse_iterator rbegin() const { return body_.rbegin(); }
105 const_reverse_iterator crbegin() const { return body_.crbegin(); }
106
107 reverse_iterator rend() { return body_.rend(); }
108 const_reverse_iterator rend() const { return body_.rend(); }
109 const_reverse_iterator crend() const { return body_.crend(); }
110
111 bool empty() const { return body_.empty(); }
112 size_type size() const { return body_.size(); }
113 size_type max_size() const { return body_.max_size(); }
114
115 void clear() { body_.clear(); }
116
117 std::pair<iterator, bool> insert(value_type value) {
118 auto pos = lower_bound(key_value_comp().key_from_value(value));
119 if (pos != end() && value_comp().equal(*pos, value))
120 return std::make_pair(pos, false);
121 return std::make_pair(body_.insert(pos, std::move(value)), true);
122 }
123
124 iterator insert(const_iterator hint, value_type value) {
125 if (hint == body_.end() || value_comp()(value, *hint)) {
126 if (hint == body_.begin() || value_comp()(*(hint - 1), value))
127 return body_.insert(non_const_iter(&body_, hint), std::move(value));
128 }
129 return insert(std::move(value)).first;
130 }
131
132 template <class InputIt>
133 void insert(InputIt first, InputIt last) {
134 std::copy(first, last, std::inserter(*this, end()));
135 }
136
137 // void insert( std::initializer_list<value_type> ilist );
138
139 template <class... Args>
140 std::pair<iterator, bool> emplace(Args&&... args) { // NOLINT
141 // todo(dyaroshev) reverse - use emplace for insert
142 return insert(value_type(std::forward<Args>(args)...)); // NOLINT
143 }
144
145 template <class... Args>
146 iterator emplace_hint(const_iterator hint, Args&&... args) { // NOLINT
147 // todo(dyaroshev) reverse - use emplace for insert
148 return insert(hint, value_type(std::forward<Args>(args)...)); // NOLINT
149 }
150
151 iterator erase(const_iterator position) {
152 return body_.erase(non_const_iter(&body_, position));
153 }
154 void erase(const_iterator first, const_iterator last) {
155 body_.erase(non_const_iter(&body_, first), non_const_iter(&body_, last));
156 }
157
158 size_type erase(const key_type& key) {
159 auto range = equal_range(key);
160 auto res = static_cast<size_type>(std::distance(range.first, range.second));
161 erase(range.first, range.second);
162 return res;
163 }
164
165 void swap(flat_sorted_container_base& other) { body_.swap(other.body_); }
166
167 size_type count(const key_type& key) const {
168 auto range = equal_range(key);
169 return static_cast<size_type>(std::distance(range.first, range.second));
170 }
171
172 iterator find(const key_type& key) {
173 auto pos = lower_bound(key);
174 if (pos == end() || !key_value_comp().equal(*pos, key))
175 return end();
176 return pos;
177 }
178 const_iterator find(const key_type& key) const {
179 auto pos = lower_bound(key);
180 if (pos == end() || !key_value_comp().equal(*pos, key))
181 return end();
182 return pos;
183 }
184
185 std::pair<iterator, iterator> equal_range(const key_type& key) {
186 return std::equal_range(body_.begin(), body_.end(), key, key_value_comp());
187 }
188
189 std::pair<const_iterator, const_iterator> equal_range(
190 const key_type& key) const {
191 return std::equal_range(body_.begin(), body_.end(), key, key_value_comp());
192 }
193
194 iterator lower_bound(const key_type& key) {
195 return std::lower_bound(body_.begin(), body_.end(), key, key_value_comp());
196 }
197
198 const_iterator lower_bound(const key_type& key) const {
199 return std::lower_bound(body_.begin(), body_.end(), key, key_value_comp());
200 }
201
202 iterator upper_bound(const key_type& key) {
203 return std::upper_bound(body_.begin(), body_.end(), key, key_value_comp());
204 }
205
206 const_iterator upper_bound(const key_type& key) const {
207 return std::upper_bound(body_.begin(), body_.end(), key, key_value_comp());
208 }
209
210 key_compare key_comp() const { return key_compare(); }
211
212 value_compare value_comp() const { return value_compare(); }
213
214 key_value_compare key_value_comp() const { return key_value_compare(); }
215
216 // regular-------------------------------------------------------------------
217 // std::map defines it's comparators based on full value compares,
218 // not provided cmps, so equvalent maps are not removed from sets, for example
219
220 friend void swap(flat_sorted_container_base& lhs,
221 flat_sorted_container_base& rhs) {
222 lhs.swap(rhs);
223 }
224
225 friend bool operator==(const flat_sorted_container_base& lhs,
226 const flat_sorted_container_base& rhs) {
227 return lhs.body_ == rhs.body_;
228 }
229
230 friend bool operator!=(const flat_sorted_container_base& lhs,
231 const flat_sorted_container_base& rhs) {
232 return !operator==(lhs, rhs);
233 }
234
235 // totally-ordered-----------------------------------------------------------
236
237 friend bool operator<(const flat_sorted_container_base& lhs,
238 const flat_sorted_container_base& rhs) {
239 return lhs.body_ < rhs.body_;
240 }
241
242 friend bool operator<=(const flat_sorted_container_base& lhs,
243 const flat_sorted_container_base& rhs) {
244 return !(rhs < lhs);
245 }
246
247 friend bool operator>(const flat_sorted_container_base& lhs,
248 const flat_sorted_container_base& rhs) {
249 return rhs < lhs;
250 }
251
252 friend bool operator>=(const flat_sorted_container_base& lhs,
253 const flat_sorted_container_base& rhs) {
254 return !(lhs < rhs);
255 }
256
257 private:
258 underlying_type body_;
259 };
260
261 } // namespace internal
262
263 } // namespace base
264
265 #endif // BASE_CONTAINTERS_FLAT_SORTED_CONTAINER_BASE_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698