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

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

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

Powered by Google App Engine
This is Rietveld 408576698