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