X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2Fsorted_vector_types.h;h=432b9411094a58dec138ea3ea132bd952a2229c0;hp=255b451834f8afa8ee18a5651500dc7dc0363432;hb=9b471821c6bf11a45e3ad9cb20ad6e5616efe089;hpb=b90498bc90c4b327fa9877d6a395c0483f4dd686 diff --git a/folly/sorted_vector_types.h b/folly/sorted_vector_types.h index 255b4518..432b9411 100644 --- a/folly/sorted_vector_types.h +++ b/folly/sorted_vector_types.h @@ -34,7 +34,7 @@ * example growth policy that grows one element at a time: * * struct OneAtATimePolicy { - * template + * template * void increase_capacity(Container& c) { * if (c.size() == c.capacity()) { * c.reserve(c.size() + 1); @@ -68,6 +68,8 @@ #include #include + +#include #include namespace folly { @@ -76,104 +78,122 @@ namespace folly { namespace detail { - // This wrapper goes around a GrowthPolicy and provides iterator - // preservation semantics, but only if the growth policy is not the - // default (i.e. nothing). - template - struct growth_policy_wrapper : private Policy { - template - Iterator increase_capacity(Container& c, Iterator desired_insertion) - { - typedef typename Container::difference_type diff_t; - diff_t d = desired_insertion - c.begin(); - Policy::increase_capacity(c); - return c.begin() + d; - } - }; - template<> - struct growth_policy_wrapper { - template - Iterator increase_capacity(Container&, Iterator it) { - return it; - } - }; +template +struct sorted_vector_enable_if_is_transparent {}; - /* - * This helper returns the distance between two iterators if it is - * possible to figure it out without messing up the range - * (i.e. unless they are InputIterators). Otherwise this returns - * -1. - */ - template - int distance_if_multipass(Iterator first, Iterator last) { - typedef typename std::iterator_traits::iterator_category categ; - if (std::is_same::value) - return -1; - return std::distance(first, last); - } - - template - typename OurContainer::iterator - insert_with_hint(OurContainer& sorted, - Vector& cont, - typename OurContainer::iterator hint, - typename OurContainer::value_type&& value, - GrowthPolicy& po) - { - const typename OurContainer::value_compare& cmp(sorted.value_comp()); - if (hint == cont.end() || cmp(value, *hint)) { - if (hint == cont.begin()) { - po.increase_capacity(cont, cont.begin()); - return cont.insert(cont.begin(), std::move(value)); - } - if (cmp(*(hint - 1), value)) { - hint = po.increase_capacity(cont, hint); - return cont.insert(hint, std::move(value)); - } - return sorted.insert(std::move(value)).first; - } +template +struct sorted_vector_enable_if_is_transparent< + void_t, + Compare, + Key, + T> { + using type = T; +}; - if (cmp(*hint, value)) { - if (hint + 1 == cont.end() || cmp(value, *(hint + 1))) { - typename OurContainer::iterator it = - po.increase_capacity(cont, hint + 1); - return cont.insert(it, std::move(value)); - } - } +// This wrapper goes around a GrowthPolicy and provides iterator +// preservation semantics, but only if the growth policy is not the +// default (i.e. nothing). +template +struct growth_policy_wrapper : private Policy { + template + Iterator increase_capacity(Container& c, Iterator desired_insertion) { + typedef typename Container::difference_type diff_t; + diff_t d = desired_insertion - c.begin(); + Policy::increase_capacity(c); + return c.begin() + d; + } +}; +template <> +struct growth_policy_wrapper { + template + Iterator increase_capacity(Container&, Iterator it) { + return it; + } +}; - // Value and *hint did not compare, so they are equal keys. - return hint; +/* + * This helper returns the distance between two iterators if it is + * possible to figure it out without messing up the range + * (i.e. unless they are InputIterators). Otherwise this returns + * -1. + */ +template +int distance_if_multipass(Iterator first, Iterator last) { + typedef typename std::iterator_traits::iterator_category categ; + if (std::is_same::value) { + return -1; } + return std::distance(first, last); +} - template - void bulk_insert( - OurContainer& sorted, - Vector& cont, - InputIterator first, - InputIterator last) { - // prevent deref of middle where middle == cont.end() - if (first == last) { - return; +template +typename OurContainer::iterator insert_with_hint( + OurContainer& sorted, + Vector& cont, + typename OurContainer::iterator hint, + typename OurContainer::value_type&& value, + GrowthPolicy& po) { + const typename OurContainer::value_compare& cmp(sorted.value_comp()); + if (hint == cont.end() || cmp(value, *hint)) { + if (hint == cont.begin() || cmp(*(hint - 1), value)) { + hint = po.increase_capacity(cont, hint); + return cont.insert(hint, std::move(value)); + } else { + return sorted.insert(std::move(value)).first; } + } - auto const& cmp(sorted.value_comp()); - - int const d = distance_if_multipass(first, last); - if (d != -1) { - cont.reserve(cont.size() + d); + if (cmp(*hint, value)) { + if (hint + 1 == cont.end() || cmp(value, *(hint + 1))) { + hint = po.increase_capacity(cont, hint + 1); + return cont.insert(hint, std::move(value)); + } else { + return sorted.insert(std::move(value)).first; } - auto const prev_size = cont.size(); + } - std::copy(first, last, std::back_inserter(cont)); - auto const middle = cont.begin() + prev_size; - if (!std::is_sorted(middle, cont.end(), cmp)) { - std::sort(middle, cont.end(), cmp); - } - if (middle != cont.begin() && cmp(*middle, *(middle - 1))) { - std::inplace_merge(cont.begin(), middle, cont.end(), cmp); - } + // Value and *hint did not compare, so they are equal keys. + return hint; +} + +template +void bulk_insert( + OurContainer& sorted, + Vector& cont, + InputIterator first, + InputIterator last) { + // prevent deref of middle where middle == cont.end() + if (first == last) { + return; + } + + auto const& cmp(sorted.value_comp()); + + int const d = distance_if_multipass(first, last); + if (d != -1) { + cont.reserve(cont.size() + d); + } + auto const prev_size = cont.size(); + + std::copy(first, last, std::back_inserter(cont)); + auto const middle = cont.begin() + prev_size; + if (!std::is_sorted(middle, cont.end(), cmp)) { + std::sort(middle, cont.end(), cmp); + } + if (middle != cont.begin() && !cmp(*(middle - 1), *middle)) { + std::inplace_merge(cont.begin(), middle, cont.end(), cmp); + cont.erase( + std::unique( + cont.begin(), + cont.end(), + [&](typename OurContainer::value_type const& a, + typename OurContainer::value_type const& b) { + return !cmp(a, b) && !cmp(b, a); + }), + cont.end()); } } +} // namespace detail ////////////////////////////////////////////////////////////////////// @@ -191,47 +211,50 @@ namespace detail { * @author Akhil Wable * @author Jordan DeLong */ -template, - class Allocator = std::allocator, - class GrowthPolicy = void> +template < + class T, + class Compare = std::less, + class Allocator = std::allocator, + class GrowthPolicy = void, + class Container = std::vector> class sorted_vector_set - : boost::totally_ordered1< - sorted_vector_set - , detail::growth_policy_wrapper > -{ - typedef std::vector ContainerT; - + : boost::totally_ordered1< + sorted_vector_set, + detail::growth_policy_wrapper> { detail::growth_policy_wrapper& get_growth_policy() { return *this; } -public: + template + using if_is_transparent = + _t>; + + public: typedef T value_type; typedef T key_type; typedef Compare key_compare; typedef Compare value_compare; - typedef typename ContainerT::pointer pointer; - typedef typename ContainerT::reference reference; - typedef typename ContainerT::const_reference const_reference; + typedef typename Container::pointer pointer; + typedef typename Container::reference reference; + typedef typename Container::const_reference const_reference; /* * XXX: Our normal iterator ought to also be a constant iterator * (cf. Defect Report 103 for std::set), but this is a bit more of a * pain. */ - typedef typename ContainerT::iterator iterator; - typedef typename ContainerT::const_iterator const_iterator; - typedef typename ContainerT::difference_type difference_type; - typedef typename ContainerT::size_type size_type; - typedef typename ContainerT::reverse_iterator reverse_iterator; - typedef typename ContainerT::const_reverse_iterator const_reverse_iterator; + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + typedef typename Container::difference_type difference_type; + typedef typename Container::size_type size_type; + typedef typename Container::reverse_iterator reverse_iterator; + typedef typename Container::const_reverse_iterator const_reverse_iterator; explicit sorted_vector_set(const Compare& comp = Compare(), const Allocator& alloc = Allocator()) : m_(comp, alloc) {} - template + template explicit sorted_vector_set( InputIterator first, InputIterator last, @@ -259,10 +282,10 @@ public: // those performed by the caller. (The iterator range constructor performs at // least one allocation). // - // Note that `sorted_vector_set(const ContainerT& container)` is not provided, + // Note that `sorted_vector_set(const Container& container)` is not provided, // since the purpose of this constructor is to avoid an unnecessary copy. explicit sorted_vector_set( - ContainerT&& container, + Container&& container, const Compare& comp = Compare()) : m_(comp, container.get_allocator()) { std::sort(container.begin(), container.end(), value_comp()); @@ -313,7 +336,7 @@ public: get_growth_policy()); } - template + template void insert(InputIterator first, InputIterator last) { detail::bulk_insert(*this, m_.cont_, first, last); } @@ -336,23 +359,32 @@ public: } iterator find(const key_type& key) { - iterator it = lower_bound(key); - if (it == end() || !key_comp()(key, *it)) - return it; - return end(); + return find(*this, key); } const_iterator find(const key_type& key) const { - const_iterator it = lower_bound(key); - if (it == end() || !key_comp()(key, *it)) - return it; - return end(); + return find(*this, key); + } + + template + if_is_transparent find(const K& key) { + return find(*this, key); + } + + template + if_is_transparent find(const K& key) const { + return find(*this, key); } size_type count(const key_type& key) const { return find(key) == end() ? 0 : 1; } + template + if_is_transparent count(const K& key) const { + return find(key) == end() ? 0 : 1; + } + iterator lower_bound(const key_type& key) { return std::lower_bound(begin(), end(), key, key_comp()); } @@ -361,6 +393,16 @@ public: return std::lower_bound(begin(), end(), key, key_comp()); } + template + if_is_transparent lower_bound(const K& key) { + return std::lower_bound(begin(), end(), key, key_comp()); + } + + template + if_is_transparent lower_bound(const K& key) const { + return std::lower_bound(begin(), end(), key, key_comp()); + } + iterator upper_bound(const key_type& key) { return std::upper_bound(begin(), end(), key, key_comp()); } @@ -369,12 +411,34 @@ public: return std::upper_bound(begin(), end(), key, key_comp()); } - std::pair equal_range(const key_type& key) { + template + if_is_transparent upper_bound(const K& key) { + return std::upper_bound(begin(), end(), key, key_comp()); + } + + template + if_is_transparent upper_bound(const K& key) const { + return std::upper_bound(begin(), end(), key, key_comp()); + } + + std::pair equal_range(const key_type& key) { return std::equal_range(begin(), end(), key, key_comp()); } - std::pair - equal_range(const key_type& key) const { + std::pair equal_range( + const key_type& key) const { + return std::equal_range(begin(), end(), key, key_comp()); + } + + template + if_is_transparent> equal_range( + const K& key) { + return std::equal_range(begin(), end(), key, key_comp()); + } + + template + if_is_transparent> equal_range( + const K& key) const { return std::equal_range(begin(), end(), key, key_comp()); } @@ -395,7 +459,7 @@ public: return m_.cont_ < other.m_.cont_; } -private: + private: /* * This structure derives from the comparison object in order to * make use of the empty base class optimization if our comparison @@ -412,12 +476,26 @@ private: : Compare(c) , cont_(alloc) {} - ContainerT cont_; + Container cont_; } m_; + + template + using self_iterator_t = _t< + std::conditional::value, const_iterator, iterator>>; + + template + static self_iterator_t find(Self& self, K const& key) { + auto end = self.end(); + auto it = self.lower_bound(key); + if (it == end || !self.key_comp()(key, *it)) { + return it; + } + return end; + } }; // Swap function that can be found using ADL. -template +template inline void swap(sorted_vector_set& a, sorted_vector_set& b) { return a.swap(b); @@ -440,22 +518,25 @@ inline void swap(sorted_vector_set& a, * @author Akhil Wable * @author Jordan DeLong */ -template, - class Allocator = std::allocator >, - class GrowthPolicy = void> +template < + class Key, + class Value, + class Compare = std::less, + class Allocator = std::allocator>, + class GrowthPolicy = void, + class Container = std::vector, Allocator>> class sorted_vector_map - : boost::totally_ordered1< - sorted_vector_map - , detail::growth_policy_wrapper > -{ - typedef std::vector,Allocator> ContainerT; - + : boost::totally_ordered1< + sorted_vector_map, + detail::growth_policy_wrapper> { detail::growth_policy_wrapper& get_growth_policy() { return *this; } -public: + template + using if_is_transparent = + _t>; + + public: typedef Key key_type; typedef Value mapped_type; typedef std::pair value_type; @@ -466,27 +547,27 @@ public: return Compare::operator()(a.first, b.first); } - protected: + protected: friend class sorted_vector_map; explicit value_compare(const Compare& c) : Compare(c) {} }; - typedef typename ContainerT::pointer pointer; - typedef typename ContainerT::reference reference; - typedef typename ContainerT::const_reference const_reference; - typedef typename ContainerT::iterator iterator; - typedef typename ContainerT::const_iterator const_iterator; - typedef typename ContainerT::difference_type difference_type; - typedef typename ContainerT::size_type size_type; - typedef typename ContainerT::reverse_iterator reverse_iterator; - typedef typename ContainerT::const_reverse_iterator const_reverse_iterator; + typedef typename Container::pointer pointer; + typedef typename Container::reference reference; + typedef typename Container::const_reference const_reference; + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + typedef typename Container::difference_type difference_type; + typedef typename Container::size_type size_type; + typedef typename Container::reverse_iterator reverse_iterator; + typedef typename Container::const_reverse_iterator const_reverse_iterator; explicit sorted_vector_map(const Compare& comp = Compare(), const Allocator& alloc = Allocator()) : m_(value_compare(comp), alloc) {} - template + template explicit sorted_vector_map( InputIterator first, InputIterator last, @@ -512,10 +593,10 @@ public: // those performed by the caller. (The iterator range constructor performs at // least one allocation). // - // Note that `sorted_vector_map(const ContainerT& container)` is not provided, + // Note that `sorted_vector_map(const Container& container)` is not provided, // since the purpose of this constructor is to avoid an unnecessary copy. explicit sorted_vector_map( - ContainerT&& container, + Container&& container, const Compare& comp = Compare()) : m_(value_compare(comp), container.get_allocator()) { std::sort(container.begin(), container.end(), value_comp()); @@ -566,7 +647,7 @@ public: get_growth_policy()); } - template + template void insert(InputIterator first, InputIterator last) { detail::bulk_insert(*this, m_.cont_, first, last); } @@ -589,17 +670,21 @@ public: } iterator find(const key_type& key) { - iterator it = lower_bound(key); - if (it == end() || !key_comp()(key, it->first)) - return it; - return end(); + return find(*this, key); } const_iterator find(const key_type& key) const { - const_iterator it = lower_bound(key); - if (it == end() || !key_comp()(key, it->first)) - return it; - return end(); + return find(*this, key); + } + + template + if_is_transparent find(const K& key) { + return find(*this, key); + } + + template + if_is_transparent find(const K& key) const { + return find(*this, key); } mapped_type& at(const key_type& key) { @@ -622,54 +707,66 @@ public: return find(key) == end() ? 0 : 1; } + template + if_is_transparent count(const K& key) const { + return find(key) == end() ? 0 : 1; + } + iterator lower_bound(const key_type& key) { - auto c = key_comp(); - auto f = [&](const value_type& a, const key_type& b) { - return c(a.first, b); - }; - return std::lower_bound(begin(), end(), key, f); + return lower_bound(*this, key); } const_iterator lower_bound(const key_type& key) const { - auto c = key_comp(); - auto f = [&](const value_type& a, const key_type& b) { - return c(a.first, b); - }; - return std::lower_bound(begin(), end(), key, f); + return lower_bound(*this, key); + } + + template + if_is_transparent lower_bound(const K& key) { + return lower_bound(*this, key); + } + + template + if_is_transparent lower_bound(const K& key) const { + return lower_bound(*this, key); } iterator upper_bound(const key_type& key) { - auto c = key_comp(); - auto f = [&](const key_type& a, const value_type& b) { - return c(a, b.first); - }; - return std::upper_bound(begin(), end(), key, f); + return upper_bound(*this, key); } const_iterator upper_bound(const key_type& key) const { - auto c = key_comp(); - auto f = [&](const key_type& a, const value_type& b) { - return c(a, b.first); - }; - return std::upper_bound(begin(), end(), key, f); + return upper_bound(*this, key); } - std::pair equal_range(const key_type& key) { - // Note: std::equal_range can't be passed a functor that takes - // argument types different from the iterator value_type, so we - // have to do this. - iterator low = lower_bound(key); - auto c = key_comp(); - auto f = [&](const key_type& a, const value_type& b) { - return c(a, b.first); - }; - iterator high = std::upper_bound(low, end(), key, f); - return std::make_pair(low, high); + template + if_is_transparent upper_bound(const K& key) { + return upper_bound(*this, key); + } + + template + if_is_transparent upper_bound(const K& key) const { + return upper_bound(*this, key); + } + + std::pair equal_range(const key_type& key) { + return equal_range(*this, key); } - std::pair - equal_range(const key_type& key) const { - return const_cast(this)->equal_range(key); + std::pair equal_range( + const key_type& key) const { + return equal_range(*this, key); + } + + template + if_is_transparent> equal_range( + const K& key) { + return equal_range(*this, key); + } + + template + if_is_transparent> equal_range( + const K& key) const { + return equal_range(*this, key); } // Nothrow as long as swap() on the Compare type is nothrow. @@ -697,7 +794,7 @@ public: return m_.cont_ < other.m_.cont_; } -private: + private: // This is to get the empty base optimization; see the comment in // sorted_vector_set. struct EBO : value_compare { @@ -705,12 +802,52 @@ private: : value_compare(c) , cont_(alloc) {} - ContainerT cont_; + Container cont_; } m_; + + template + using self_iterator_t = _t< + std::conditional::value, const_iterator, iterator>>; + + template + static self_iterator_t find(Self& self, K const& key) { + auto end = self.end(); + auto it = self.lower_bound(key); + if (it == end || !self.key_comp()(key, it->first)) { + return it; + } + return end; + } + + template + static self_iterator_t lower_bound(Self& self, K const& key) { + auto f = [c = self.key_comp()](value_type const& a, K const& b) { + return c(a.first, b); + }; + return std::lower_bound(self.begin(), self.end(), key, f); + } + + template + static self_iterator_t upper_bound(Self& self, K const& key) { + auto f = [c = self.key_comp()](K const& a, value_type const& b) { + return c(a, b.first); + }; + return std::upper_bound(self.begin(), self.end(), key, f); + } + + template + static std::pair, self_iterator_t> equal_range( + Self& self, + K const& key) { + // Note: std::equal_range can't be passed a functor that takes + // argument types different from the iterator value_type, so we + // have to do this. + return {lower_bound(self, key), upper_bound(self, key)}; + } }; // Swap function that can be found using ADL. -template +template inline void swap(sorted_vector_map& a, sorted_vector_map& b) { return a.swap(b); @@ -718,4 +855,4 @@ inline void swap(sorted_vector_map& a, ////////////////////////////////////////////////////////////////////// -} +} // namespace folly