mirror of
https://github.com/boostorg/container.git
synced 2025-08-04 15:04:29 +02:00
Implemented unique associative containers' equal_range using lower_bound_range which is more efficient with heavy comparison functions.
Updated benchmark to avoid measuring redundant operations in searches.
This commit is contained in:
@@ -229,6 +229,27 @@ cpu_times insert_time(vector<typename C::value_type> &unique_range, vector<typen
|
|||||||
return total_time.elapsed();
|
return total_time.elapsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Iterator>
|
||||||
|
bool check_not_end(vector<Iterator> &iterators, Iterator itend, std::size_t number_of_ends = 0)
|
||||||
|
{
|
||||||
|
std::size_t end_count = 0;
|
||||||
|
for(std::size_t i = 0, max = iterators.size(); i != max; ++i){
|
||||||
|
if(iterators[i] == itend && (++end_count > number_of_ends) )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Iterator>
|
||||||
|
bool check_all_not_empty(vector< std::pair<Iterator, Iterator > > &iterator_pairs)
|
||||||
|
{
|
||||||
|
for(std::size_t i = 0, max = iterator_pairs.size(); i != max; ++i){
|
||||||
|
if(iterator_pairs[i].first == iterator_pairs[i].second)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename C>
|
template<typename C>
|
||||||
cpu_times search_time(vector<typename C::value_type> &unique_range, const char *RangeType)
|
cpu_times search_time(vector<typename C::value_type> &unique_range, const char *RangeType)
|
||||||
{
|
{
|
||||||
@@ -239,72 +260,68 @@ cpu_times search_time(vector<typename C::value_type> &unique_range, const char *
|
|||||||
cpu_timer total_time;
|
cpu_timer total_time;
|
||||||
total_time.resume();
|
total_time.resume();
|
||||||
|
|
||||||
|
vector<typename C::iterator> v_it(N);
|
||||||
|
vector< std::pair<typename C::iterator, typename C::iterator> > v_itp(N);
|
||||||
|
|
||||||
for(std::size_t i = 0; i != N; ++i){
|
for(std::size_t i = 0; i != N; ++i){
|
||||||
//Find
|
//Find
|
||||||
{
|
{
|
||||||
std::size_t found = 0;
|
|
||||||
find_timer.resume();
|
find_timer.resume();
|
||||||
for(std::size_t rep = 0; rep != 2; ++rep)
|
for(std::size_t rep = 0; rep != 2; ++rep)
|
||||||
for(std::size_t i = 0, max = unique_range.size(); i != max; ++i){
|
for(std::size_t i = 0, max = unique_range.size(); i != max; ++i){
|
||||||
found += static_cast<std::size_t>(c.end() != c.find(unique_range[i]));
|
v_it[i] = c.find(unique_range[i]);
|
||||||
}
|
}
|
||||||
find_timer.stop();
|
find_timer.stop();
|
||||||
if(found/2 != c.size()){
|
if(!check_not_end(v_it, c.end())){
|
||||||
std::cout << "ERROR! find all elements not found" << std::endl;
|
std::cout << "ERROR! find all elements not found" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Lower
|
//Lower
|
||||||
{
|
{
|
||||||
std::size_t found = 0;
|
|
||||||
lower_timer.resume();
|
lower_timer.resume();
|
||||||
for(std::size_t rep = 0; rep != 2; ++rep)
|
for(std::size_t rep = 0; rep != 2; ++rep)
|
||||||
for(std::size_t i = 0, max = unique_range.size(); i != max; ++i){
|
for(std::size_t i = 0, max = unique_range.size(); i != max; ++i){
|
||||||
found += static_cast<std::size_t>(c.end() != c.lower_bound(unique_range[i]));
|
v_it[i] = c.lower_bound(unique_range[i]);
|
||||||
}
|
}
|
||||||
lower_timer.stop();
|
lower_timer.stop();
|
||||||
if(found/2 != c.size()){
|
if(!check_not_end(v_it, c.end())){
|
||||||
std::cout << "ERROR! lower_bound all elements not found" << std::endl;
|
std::cout << "ERROR! lower_bound all elements not found" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Upper
|
//Upper
|
||||||
{
|
{
|
||||||
std::size_t found = 0;
|
|
||||||
upper_timer.resume();
|
upper_timer.resume();
|
||||||
for(std::size_t rep = 0; rep != 2; ++rep)
|
for(std::size_t rep = 0; rep != 2; ++rep)
|
||||||
for(std::size_t i = 0, max = unique_range.size(); i != max; ++i){
|
for(std::size_t i = 0, max = unique_range.size(); i != max; ++i){
|
||||||
found += static_cast<std::size_t>(c.end() != c.upper_bound(unique_range[i]));
|
v_it[i] = c.upper_bound(unique_range[i]);
|
||||||
}
|
}
|
||||||
upper_timer.stop();
|
upper_timer.stop();
|
||||||
if(found/2 != (c.size()-1)){
|
if(!check_not_end(v_it, c.end(), 1u)){
|
||||||
std::cout << "ERROR! upper_bound all elements not found" << std::endl;
|
std::cout << "ERROR! upper_bound all elements not found" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Equal
|
//Equal
|
||||||
{
|
{
|
||||||
std::size_t found = 0;
|
|
||||||
std::pair<typename C::iterator,typename C::iterator> ret;
|
|
||||||
equal_range_timer.resume();
|
equal_range_timer.resume();
|
||||||
for(std::size_t rep = 0; rep != 2; ++rep)
|
for(std::size_t rep = 0; rep != 2; ++rep)
|
||||||
for(std::size_t i = 0, max = unique_range.size(); i != max; ++i){
|
for(std::size_t i = 0, max = unique_range.size(); i != max; ++i){
|
||||||
ret = c.equal_range(unique_range[i]);
|
v_itp[i] = c.equal_range(unique_range[i]);
|
||||||
found += static_cast<std::size_t>(ret.first != ret.second);
|
|
||||||
}
|
}
|
||||||
equal_range_timer.stop();
|
equal_range_timer.stop();
|
||||||
if(found/2 != c.size()){
|
if(!check_all_not_empty(v_itp)){
|
||||||
std::cout << "ERROR! equal_range all elements not found" << std::endl;
|
std::cout << "ERROR! equal_range all elements not found" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Count
|
//Count
|
||||||
{
|
{
|
||||||
std::size_t found = 0;
|
std::size_t count = 0;
|
||||||
std::pair<typename C::iterator,typename C::iterator> ret;
|
|
||||||
count_timer.resume();
|
count_timer.resume();
|
||||||
for(std::size_t rep = 0; rep != 2; ++rep)
|
for(std::size_t rep = 0; rep != 2; ++rep)
|
||||||
for(std::size_t i = 0, max = unique_range.size(); i != max; ++i){
|
for(std::size_t i = 0, max = unique_range.size(); i != max; ++i){
|
||||||
found += static_cast<std::size_t>(c.count(unique_range[i]));
|
count += c.count(unique_range[i]);
|
||||||
}
|
}
|
||||||
count_timer.stop();
|
count_timer.stop();
|
||||||
if(found/2 != c.size()){
|
if(count/2 != c.size()){
|
||||||
std::cout << "ERROR! count all elements not found" << std::endl;
|
std::cout << "ERROR! count all elements not found" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -743,6 +743,12 @@ class flat_tree
|
|||||||
std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const
|
std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const
|
||||||
{ return this->priv_equal_range(this->cbegin(), this->cend(), k); }
|
{ return this->priv_equal_range(this->cbegin(), this->cend(), k); }
|
||||||
|
|
||||||
|
std::pair<iterator, iterator> lower_bound_range(const key_type& k)
|
||||||
|
{ return this->priv_lower_bound_range(this->begin(), this->end(), k); }
|
||||||
|
|
||||||
|
std::pair<const_iterator, const_iterator> lower_bound_range(const key_type& k) const
|
||||||
|
{ return this->priv_lower_bound_range(this->cbegin(), this->cend(), k); }
|
||||||
|
|
||||||
size_type capacity() const
|
size_type capacity() const
|
||||||
{ return this->m_data.m_vect.capacity(); }
|
{ return this->m_data.m_vect.capacity(); }
|
||||||
|
|
||||||
@@ -958,6 +964,18 @@ class flat_tree
|
|||||||
return std::pair<RanIt, RanIt>(first, first);
|
return std::pair<RanIt, RanIt>(first, first);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class RanIt>
|
||||||
|
std::pair<RanIt, RanIt> priv_lower_bound_range(RanIt first, RanIt last, const key_type& k) const
|
||||||
|
{
|
||||||
|
const Compare &key_cmp = this->m_data.get_comp();
|
||||||
|
KeyOfValue key_extract;
|
||||||
|
RanIt lb(this->priv_lower_bound(first, last, k)), ub(lb);
|
||||||
|
if(lb != last && static_cast<difference_type>(!key_cmp(k, key_extract(*lb)))){
|
||||||
|
++ub;
|
||||||
|
}
|
||||||
|
return std::pair<RanIt, RanIt>(lb, ub);
|
||||||
|
}
|
||||||
|
|
||||||
template<class InIt>
|
template<class InIt>
|
||||||
void priv_insert_equal_loop(InIt first, InIt last)
|
void priv_insert_equal_loop(InIt first, InIt last)
|
||||||
{
|
{
|
||||||
|
@@ -1071,7 +1071,8 @@ class tree
|
|||||||
void clear()
|
void clear()
|
||||||
{ AllocHolder::clear(alloc_version()); }
|
{ AllocHolder::clear(alloc_version()); }
|
||||||
|
|
||||||
// set operations:
|
// search operations. Const and non-const overloads even if no iterator is returned
|
||||||
|
// so splay implementations can to their rebalancing when searching in non-const versions
|
||||||
iterator find(const key_type& k)
|
iterator find(const key_type& k)
|
||||||
{ return iterator(this->icont().find(k, KeyNodeCompare(value_comp()))); }
|
{ return iterator(this->icont().find(k, KeyNodeCompare(value_comp()))); }
|
||||||
|
|
||||||
@@ -1108,6 +1109,21 @@ class tree
|
|||||||
(const_iterator(ret.first), const_iterator(ret.second));
|
(const_iterator(ret.first), const_iterator(ret.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<iterator,iterator> lower_bound_range(const key_type& k)
|
||||||
|
{
|
||||||
|
std::pair<iiterator, iiterator> ret =
|
||||||
|
this->icont().lower_bound_range(k, KeyNodeCompare(value_comp()));
|
||||||
|
return std::pair<iterator,iterator>(iterator(ret.first), iterator(ret.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<const_iterator, const_iterator> lower_bound_range(const key_type& k) const
|
||||||
|
{
|
||||||
|
std::pair<iiterator, iiterator> ret =
|
||||||
|
this->non_const_icont().lower_bound_range(k, KeyNodeCompare(value_comp()));
|
||||||
|
return std::pair<const_iterator,const_iterator>
|
||||||
|
(const_iterator(ret.first), const_iterator(ret.second));
|
||||||
|
}
|
||||||
|
|
||||||
void rebalance()
|
void rebalance()
|
||||||
{ intrusive_tree_proxy_t::rebalance(this->icont()); }
|
{ intrusive_tree_proxy_t::rebalance(this->icont()); }
|
||||||
|
|
||||||
|
@@ -857,13 +857,13 @@ class flat_map
|
|||||||
//!
|
//!
|
||||||
//! <b>Complexity</b>: Logarithmic
|
//! <b>Complexity</b>: Logarithmic
|
||||||
std::pair<iterator,iterator> equal_range(const key_type& x)
|
std::pair<iterator,iterator> equal_range(const key_type& x)
|
||||||
{ return container_detail::force_copy<std::pair<iterator,iterator> >(m_flat_tree.equal_range(x)); }
|
{ return container_detail::force_copy<std::pair<iterator,iterator> >(m_flat_tree.lower_bound_range(x)); }
|
||||||
|
|
||||||
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
|
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
|
||||||
//!
|
//!
|
||||||
//! <b>Complexity</b>: Logarithmic
|
//! <b>Complexity</b>: Logarithmic
|
||||||
std::pair<const_iterator,const_iterator> equal_range(const key_type& x) const
|
std::pair<const_iterator,const_iterator> equal_range(const key_type& x) const
|
||||||
{ return container_detail::force_copy<std::pair<const_iterator,const_iterator> >(m_flat_tree.equal_range(x)); }
|
{ return container_detail::force_copy<std::pair<const_iterator,const_iterator> >(m_flat_tree.lower_bound_range(x)); }
|
||||||
|
|
||||||
//! <b>Effects</b>: Returns true if x and y are equal
|
//! <b>Effects</b>: Returns true if x and y are equal
|
||||||
//!
|
//!
|
||||||
|
@@ -604,30 +604,17 @@ class flat_set
|
|||||||
|
|
||||||
#endif // #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
|
#endif // #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
|
||||||
|
|
||||||
|
|
||||||
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
|
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
|
||||||
//!
|
//!
|
||||||
//! <b>Complexity</b>: Logarithmic
|
//! <b>Complexity</b>: Logarithmic
|
||||||
std::pair<const_iterator, const_iterator> equal_range(const key_type& x) const
|
std::pair<const_iterator, const_iterator> equal_range(const key_type& x) const
|
||||||
{
|
{ return this->base_t::lower_bound_range(x); }
|
||||||
const_iterator lb = this->lower_bound(x), ub(lb);
|
|
||||||
if(lb != this->cend() && static_cast<difference_type>(!this->key_comp()(x, *lb))){
|
|
||||||
++ub;
|
|
||||||
}
|
|
||||||
return std::pair<const_iterator, const_iterator>(lb, ub);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
|
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
|
||||||
//!
|
//!
|
||||||
//! <b>Complexity</b>: Logarithmic
|
//! <b>Complexity</b>: Logarithmic
|
||||||
std::pair<iterator,iterator> equal_range(const key_type& x)
|
std::pair<iterator,iterator> equal_range(const key_type& x)
|
||||||
{
|
{ return this->base_t::lower_bound_range(x); }
|
||||||
iterator lb = this->lower_bound(x), ub(lb);
|
|
||||||
if(lb != this->end() && static_cast<difference_type>(!this->key_comp()(x, *lb))){
|
|
||||||
++ub;
|
|
||||||
}
|
|
||||||
return std::pair<iterator, iterator>(lb, ub);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
|
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
|
||||||
|
|
||||||
|
@@ -540,6 +540,22 @@ class set
|
|||||||
//! <b>Complexity</b>: Logarithmic
|
//! <b>Complexity</b>: Logarithmic
|
||||||
const_iterator upper_bound(const key_type& x) const;
|
const_iterator upper_bound(const key_type& x) const;
|
||||||
|
|
||||||
|
#endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
|
||||||
|
|
||||||
|
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
|
||||||
|
//!
|
||||||
|
//! <b>Complexity</b>: Logarithmic
|
||||||
|
std::pair<iterator,iterator> equal_range(const key_type& x)
|
||||||
|
{ return this->base_t::lower_bound_range(x); }
|
||||||
|
|
||||||
|
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
|
||||||
|
//!
|
||||||
|
//! <b>Complexity</b>: Logarithmic
|
||||||
|
std::pair<const_iterator, const_iterator> equal_range(const key_type& x) const
|
||||||
|
{ return this->base_t::lower_bound_range(x); }
|
||||||
|
|
||||||
|
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
|
||||||
|
|
||||||
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
|
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
|
||||||
//!
|
//!
|
||||||
//! <b>Complexity</b>: Logarithmic
|
//! <b>Complexity</b>: Logarithmic
|
||||||
|
Reference in New Issue
Block a user