Index: base/containers/flat_sorted_container_base.h |
diff --git a/base/containers/flat_sorted_container_base.h b/base/containers/flat_sorted_container_base.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7043242d59c0913bed7b2f153a3e36c824636099 |
--- /dev/null |
+++ b/base/containers/flat_sorted_container_base.h |
@@ -0,0 +1,265 @@ |
+// Copyright (c) 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef BASE_CONTAINTERS_FLAT_SORTED_CONTAINER_BASE_H_ |
+#define BASE_CONTAINTERS_FLAT_SORTED_CONTAINER_BASE_H_ |
+ |
+#include <algorithm> |
+#include <iterator> |
+#include <memory> |
+#include <utility> |
+ |
+namespace base { |
+namespace internal { |
+ |
+template <typename Compare> |
+struct sort_and_unique : private Compare { |
+ template <typename Cont> |
+ void operator()(Cont* rhs) { |
+ using value_type = typename Cont::value_type; |
+ |
+ std::sort(rhs->begin(), rhs->end(), |
+ [this](const value_type& lhs, const value_type& rhs) { |
+ return Compare::operator()(lhs, rhs); |
+ }); |
+ |
+ rhs->erase( |
+ std::unique(rhs->begin(), rhs->end(), |
+ [this](const value_type& lhs, const value_type& rhs) { |
+ return Compare::equal(lhs, rhs); |
+ }), |
+ rhs->end()); |
+ } |
+}; |
+ |
+// Our version of standard library on linux does not have erase with const |
+// iterators. It's a hack around that. |
+template <typename Cont> |
+typename Cont::iterator non_const_iter(Cont* cont, |
+ typename Cont::const_iterator iter) { |
+ return std::next(cont->begin(), std::distance(cont->cbegin(), iter)); |
+} |
+ |
+template <typename Compare, class UnderlyingType> |
+class flat_sorted_container_base { |
+ public: |
+ using compare = Compare; |
+ using key_compare = compare; |
+ using value_compare = compare; |
+ using key_value_compare = compare; |
+ |
+ using underlying_type = UnderlyingType; |
+ using key_type = typename key_compare::key_type; |
+ using value_type = typename key_compare::value_type; |
+ |
+ using size_type = typename underlying_type::size_type; |
+ using difference_type = typename underlying_type::difference_type; |
+ using reference = typename underlying_type::reference; |
+ using const_reference = typename underlying_type::const_reference; |
+ using pointer = typename underlying_type::pointer; |
+ using const_pointer = typename underlying_type::const_pointer; |
+ using iterator = typename underlying_type::iterator; |
+ using const_iterator = typename underlying_type::const_iterator; |
+ using reverse_iterator = typename underlying_type::reverse_iterator; |
+ using const_reverse_iterator = |
+ typename underlying_type::const_reverse_iterator; |
+ |
+ // scoped object to do operations on body, without keeping order |
+ using unsafe_region = |
+ std::unique_ptr<underlying_type, sort_and_unique<compare>>; |
+ |
+ flat_sorted_container_base() {} |
+ |
+ explicit flat_sorted_container_base(underlying_type body) |
+ : body_(std::move(body)) { |
+ unsafe_access(); |
+ } |
+ |
+ template <typename It> |
+ flat_sorted_container_base(It first, It last) : body_(first, last) { |
+ unsafe_access(); |
+ } |
+ |
+ // methods------------------------------------------------------------------- |
+ |
+ // returns scoped object, that gives access to underlying storrage. |
+ // at destruction, sorts and does unification. |
+ // |
+ // if you know, that on exit of the region, storrage is already sorted and |
+ // unified - call unsafe_region::release() |
+ unsafe_region unsafe_access() { return unsafe_region(&body_); } |
+ |
+ // get_allocator() |
+ |
+ iterator begin() { return body_.begin(); } |
+ const_iterator begin() const { return body_.begin(); } |
+ const_iterator cbegin() const { return body_.cbegin(); } |
+ |
+ iterator end() { return body_.end(); } |
+ const_iterator end() const { return body_.end(); } |
+ const_iterator cend() const { return body_.cend(); } |
+ |
+ reverse_iterator rbegin() { return body_.rbegin(); } |
+ const_reverse_iterator rbegin() const { return body_.rbegin(); } |
+ const_reverse_iterator crbegin() const { return body_.crbegin(); } |
+ |
+ reverse_iterator rend() { return body_.rend(); } |
+ const_reverse_iterator rend() const { return body_.rend(); } |
+ const_reverse_iterator crend() const { return body_.crend(); } |
+ |
+ bool empty() const { return body_.empty(); } |
+ size_type size() const { return body_.size(); } |
+ size_type max_size() const { return body_.max_size(); } |
+ |
+ void clear() { body_.clear(); } |
+ |
+ std::pair<iterator, bool> insert(value_type value) { |
+ auto pos = lower_bound(key_value_comp().key_from_value(value)); |
+ if (pos != end() && value_comp().equal(*pos, value)) |
+ return std::make_pair(pos, false); |
+ return std::make_pair(body_.insert(pos, std::move(value)), true); |
+ } |
+ |
+ iterator insert(const_iterator hint, value_type value) { |
+ if (hint == body_.end() || value_comp()(value, *hint)) { |
+ if (hint == body_.begin() || value_comp()(*(hint - 1), value)) |
+ return body_.insert(non_const_iter(&body_, hint), std::move(value)); |
+ } |
+ return insert(std::move(value)).first; |
+ } |
+ |
+ template <class InputIt> |
+ void insert(InputIt first, InputIt last) { |
+ std::copy(first, last, std::inserter(*this, end())); |
+ } |
+ |
+ // void insert( std::initializer_list<value_type> ilist ); |
+ |
+ template <class... Args> |
+ std::pair<iterator, bool> emplace(Args&&... args) { // NOLINT |
+ // todo(dyaroshev) reverse - use emplace for insert |
+ return insert(value_type(std::forward<Args>(args)...)); // NOLINT |
+ } |
+ |
+ template <class... Args> |
+ iterator emplace_hint(const_iterator hint, Args&&... args) { // NOLINT |
+ // todo(dyaroshev) reverse - use emplace for insert |
+ return insert(hint, value_type(std::forward<Args>(args)...)); // NOLINT |
+ } |
+ |
+ iterator erase(const_iterator position) { |
+ return body_.erase(non_const_iter(&body_, position)); |
+ } |
+ void erase(const_iterator first, const_iterator last) { |
+ body_.erase(non_const_iter(&body_, first), non_const_iter(&body_, last)); |
+ } |
+ |
+ size_type erase(const key_type& key) { |
+ auto range = equal_range(key); |
+ auto res = static_cast<size_type>(std::distance(range.first, range.second)); |
+ erase(range.first, range.second); |
+ return res; |
+ } |
+ |
+ void swap(flat_sorted_container_base& other) { body_.swap(other.body_); } |
+ |
+ size_type count(const key_type& key) const { |
+ auto range = equal_range(key); |
+ return static_cast<size_type>(std::distance(range.first, range.second)); |
+ } |
+ |
+ iterator find(const key_type& key) { |
+ auto pos = lower_bound(key); |
+ if (pos == end() || !key_value_comp().equal(*pos, key)) |
+ return end(); |
+ return pos; |
+ } |
+ const_iterator find(const key_type& key) const { |
+ auto pos = lower_bound(key); |
+ if (pos == end() || !key_value_comp().equal(*pos, key)) |
+ return end(); |
+ return pos; |
+ } |
+ |
+ std::pair<iterator, iterator> equal_range(const key_type& key) { |
+ return std::equal_range(body_.begin(), body_.end(), key, key_value_comp()); |
+ } |
+ |
+ std::pair<const_iterator, const_iterator> equal_range( |
+ const key_type& key) const { |
+ return std::equal_range(body_.begin(), body_.end(), key, key_value_comp()); |
+ } |
+ |
+ iterator lower_bound(const key_type& key) { |
+ return std::lower_bound(body_.begin(), body_.end(), key, key_value_comp()); |
+ } |
+ |
+ const_iterator lower_bound(const key_type& key) const { |
+ return std::lower_bound(body_.begin(), body_.end(), key, key_value_comp()); |
+ } |
+ |
+ iterator upper_bound(const key_type& key) { |
+ return std::upper_bound(body_.begin(), body_.end(), key, key_value_comp()); |
+ } |
+ |
+ const_iterator upper_bound(const key_type& key) const { |
+ return std::upper_bound(body_.begin(), body_.end(), key, key_value_comp()); |
+ } |
+ |
+ key_compare key_comp() const { return key_compare(); } |
+ |
+ value_compare value_comp() const { return value_compare(); } |
+ |
+ key_value_compare key_value_comp() const { return key_value_compare(); } |
+ |
+ // regular------------------------------------------------------------------- |
+ // std::map defines it's comparators based on full value compares, |
+ // not provided cmps, so equvalent maps are not removed from sets, for example |
+ |
+ friend void swap(flat_sorted_container_base& lhs, |
+ flat_sorted_container_base& rhs) { |
+ lhs.swap(rhs); |
+ } |
+ |
+ friend bool operator==(const flat_sorted_container_base& lhs, |
+ const flat_sorted_container_base& rhs) { |
+ return lhs.body_ == rhs.body_; |
+ } |
+ |
+ friend bool operator!=(const flat_sorted_container_base& lhs, |
+ const flat_sorted_container_base& rhs) { |
+ return !operator==(lhs, rhs); |
+ } |
+ |
+ // totally-ordered----------------------------------------------------------- |
+ |
+ friend bool operator<(const flat_sorted_container_base& lhs, |
+ const flat_sorted_container_base& rhs) { |
+ return lhs.body_ < rhs.body_; |
+ } |
+ |
+ friend bool operator<=(const flat_sorted_container_base& lhs, |
+ const flat_sorted_container_base& rhs) { |
+ return !(rhs < lhs); |
+ } |
+ |
+ friend bool operator>(const flat_sorted_container_base& lhs, |
+ const flat_sorted_container_base& rhs) { |
+ return rhs < lhs; |
+ } |
+ |
+ friend bool operator>=(const flat_sorted_container_base& lhs, |
+ const flat_sorted_container_base& rhs) { |
+ return !(lhs < rhs); |
+ } |
+ |
+ private: |
+ underlying_type body_; |
+}; |
+ |
+} // namespace internal |
+ |
+} // namespace base |
+ |
+#endif // BASE_CONTAINTERS_FLAT_SORTED_CONTAINER_BASE_H_ |