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