Compare commits

..

13 Commits

Author SHA1 Message Date
joaquintides d689613172 protected visitation against spurious insertion sentinels 2023-12-27 12:32:31 +01:00
joaquintides 8365ccb78a fixed is_reserved 2023-12-26 18:11:22 +01:00
joaquintides 0a6da6979f protected for_all_elements(_while) against transient slot reserves 2023-12-26 09:53:29 +01:00
joaquintides 31c33faf57 added almost-latch-free insertion for regular-layout group_type 2023-12-25 20:25:34 +01:00
Braden Ganetsky 0d2751c5e1 Extract at()'s throw_exception calls into noinline function (#223)
* Create function `detail::throw_out_of_range()` to make `at()` more inlineable

* Replace `boost::throw_exception()` with `detail::throw_out_of_range()`
2023-12-19 17:08:08 +01:00
joaquintides f493603f5c [skip ci] editorial 2023-12-01 12:22:48 +01:00
Peter Dimov 74ca1b0e74 Update test/CMakeLists.txt 2023-11-30 17:54:53 +02:00
Peter Dimov 7b16324869 Regenerate CMakeLists.txt 2023-11-30 17:40:41 +02:00
joaquintides 6680e86b38 [skip ci] typo 2023-11-25 09:49:24 +01:00
joaquintides 3e76b1cf68 [skip ci] beautified some badges 2023-11-19 18:45:21 +01:00
joaquintides 22f29718e4 changed drone badges 2023-11-19 09:48:38 +01:00
joaquintides f7c7f8fdd2 [skip ci] added Drone badges 2023-11-18 11:30:47 +01:00
joaquintides 7fd94b9df7 Fix/bucket iterator indirection operator (#220 rewrite) (#221)
* Add tests for member of pointer operator for bucket iterators

* Fix erroneous conversion from node* to value_type* in bucket iterators

Originally caughy by vslashg  from PR https://github.com/boostorg/unordered/pull/220

* Update change log

* Update GHA config to use containers in C++20 builds for clang-14 as it's incompatible with libstdc++-13

* fixed Python installation problem

* tried variation of former fix

* tried another variation of former fix

* tried yet another variation

* editorial

---------

Co-authored-by: Christian Mazakas <christian.mazakas@gmail.com>
2023-11-17 08:51:40 +01:00
15 changed files with 266 additions and 66 deletions
+4 -4
View File
@@ -95,12 +95,12 @@ jobs:
- { name: "clang-14 w/ sanitizers (17)", sanitize: yes,
compiler: clang-14, cxxstd: '17', os: 'ubuntu-22.04', ccache_key: "san2" }
- { name: "clang-14 w/ sanitizers (20)", sanitize: yes,
compiler: clang-14, cxxstd: '20', os: 'ubuntu-22.04', ccache_key: "san2" }
compiler: clang-14, cxxstd: '20', container: 'ubuntu:22.04', os: 'ubuntu-latest', ccache_key: "san2" }
- { name: "clang-14 w/ sanitizers (2b)", sanitize: yes,
compiler: clang-14, cxxstd: '2b', os: 'ubuntu-22.04', ccache_key: "san2" }
compiler: clang-14, cxxstd: '2b', container: 'ubuntu:22.04', os: 'ubuntu-latest', ccache_key: "san2" }
- { name: "cfoa tsan (clang-14)", cxxstd: '11,14,17,20,2b', os: 'ubuntu-22.04', compiler: clang-14,
targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes,
targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes,
stdlib: libc++, install: 'clang-14 libc++-14-dev libc++abi-14-dev', ccache_key: "tsan" }
- { compiler: 'clang-15', cxxstd: '11,14', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-15 libc++-15-dev libc++abi-15-dev' }
@@ -134,7 +134,7 @@ jobs:
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys E1DD270288B4E6030699E45FA1715D88E1DF1F24
for i in {1..${NET_RETRY_COUNT:-3}}; do sudo -E add-apt-repository -y ppa:git-core/ppa && break || sleep 10; done
apt-get -o Acquire::Retries=$NET_RETRY_COUNT update
apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y g++ python libpython-dev git
apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y g++ python-is-python3 git
fi
# For jobs not compatible with ccache, use "ccache: no" in the matrix
if [[ "${{ matrix.ccache }}" == "no" ]]; then
+3 -6
View File
@@ -3,7 +3,7 @@
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
cmake_minimum_required(VERSION 3.5...3.20)
cmake_minimum_required(VERSION 3.8...3.20)
project(boost_unordered VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
@@ -18,16 +18,13 @@ target_link_libraries(boost_unordered
Boost::config
Boost::container_hash
Boost::core
Boost::move
Boost::mp11
Boost::predef
Boost::preprocessor
Boost::static_assert
Boost::throw_exception
Boost::tuple
Boost::type_traits
)
target_compile_features(boost_unordered INTERFACE cxx_std_11)
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
add_subdirectory(test)
+2 -2
View File
@@ -1,7 +1,7 @@
# Boost.Unordered
[![Branch](https://img.shields.io/badge/branch-master-brightgreen.svg)](https://github.com/boostorg/unordered/tree/master) [![CI](https://github.com/boostorg/unordered/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/unordered/actions/workflows/ci.yml) [![Build status](https://ci.appveyor.com/api/projects/status/github/boostorg/unordered?branch=master&svg=true)](https://ci.appveyor.com/project/cppalliance/unordered/branch/master) [![codecov](https://codecov.io/gh/boostorg/unordered/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/unordered/branch/master) [![Deps](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/unordered.html) [![Documentation](https://img.shields.io/badge/docs-master-brightgreen.svg)](https://www.boost.org/doc/libs/master/libs/unordered/doc/html/unordered.html) [![Enter the Matrix](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/unordered.html)<br/>
[![Branch](https://img.shields.io/badge/branch-develop-brightgreen.svg)](https://github.com/boostorg/unordered/tree/develop) [![CI](https://github.com/boostorg/unordered/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/unordered/actions/workflows/ci.yml) [![Build status](https://ci.appveyor.com/api/projects/status/github/boostorg/unordered?branch=develop&svg=true)](https://ci.appveyor.com/project/cppalliance/unordered/branch/develop) [![codecov](https://codecov.io/gh/boostorg/unordered/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/unordered/branch/develop) [![Deps](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/unordered.html) [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](https://www.boost.org/doc/libs/develop/libs/unordered/doc/html/unordered.html) [![Enter the Matrix](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/unordered.html)<br/>
[![Branch](https://img.shields.io/badge/branch-master-brightgreen.svg)](https://github.com/boostorg/unordered/tree/master) [![CI](https://github.com/boostorg/unordered/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/unordered/actions/workflows/ci.yml) [![Drone status](https://img.shields.io/drone/build/boostorg/unordered/master?server=https%3A%2F%2Fdrone.cpp.al&logo=drone&logoColor=%23CCCCCC&label=CI)](https://drone.cpp.al/boostorg/unordered) [![Build status](https://img.shields.io/appveyor/build/cppalliance/unordered/master?logo=appveyor&label=CI)](https://ci.appveyor.com/project/cppalliance/unordered/branch/master) [![codecov](https://codecov.io/gh/boostorg/unordered/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/unordered/branch/master) [![Deps](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/unordered.html) [![Documentation](https://img.shields.io/badge/docs-master-brightgreen.svg)](https://www.boost.org/doc/libs/master/libs/unordered/doc/html/unordered.html) [![Enter the Matrix](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/unordered.html)<br/>
[![Branch](https://img.shields.io/badge/branch-develop-brightgreen.svg)](https://github.com/boostorg/unordered/tree/develop) [![CI](https://github.com/boostorg/unordered/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/unordered/actions/workflows/ci.yml) [![Drone status](https://img.shields.io/drone/build/boostorg/unordered/develop?server=https%3A%2F%2Fdrone.cpp.al&logo=drone&logoColor=%23CCCCCC&label=CI)](https://drone.cpp.al/boostorg/unordered) [![Build status](https://img.shields.io/appveyor/build/cppalliance/unordered/master?logo=appveyor&label=CI)](https://ci.appveyor.com/project/cppalliance/unordered/branch/develop) [![codecov](https://codecov.io/gh/boostorg/unordered/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/unordered/branch/develop) [![Deps](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/unordered.html) [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](https://www.boost.org/doc/libs/develop/libs/unordered/doc/html/unordered.html) [![Enter the Matrix](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/unordered.html)<br/>
[![BSL 1.0](https://img.shields.io/badge/license-BSL_1.0-blue.svg)](https://www.boost.org/users/license.html) <img alt="C++11 required" src="https://img.shields.io/badge/standard-C%2b%2b11-blue.svg"> <img alt="Header-only library" src="https://img.shields.io/badge/build-header--only-blue.svg">
Boost.Unordered offers a catalog of hash containers with different standards compliance levels, performances and intented usage scenarios:
+7 -4
View File
@@ -19,6 +19,9 @@ a concurrent container from user code.
* Added Boost.Serialization support to all containers and their (non-local) iterator types.
* Added support for fancy pointers to open-addressing and concurrent containers.
This enables scenarios like the use of Boost.Interprocess allocators to construct containers in shared memory.
* Fixed bug in member of pointer operator for local iterators of closed-addressing
containers ({github-pr-url}/221[PR#221^], credit goes to GitHub user vslashg for finding
and fixing this issue).
* Starting with this release, `boost::unordered_[multi]set` and `boost::unordered_[multi]map`
only work with C++11 onwards.
@@ -39,7 +42,7 @@ when the returned proxy is not used.
`boost::unordered_node_map` and `boost::unordered_node_set`.
* Extended heterogeneous lookup to more member functions as specified in
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2363r5.html[P2363].
* Replaced the previous post-mixing process for open-addressing containers with
* Replaced the previous post-mixing process for open-addressing containers with
a new algorithm based on extended multiplication by a constant.
* Fixed bug in internal emplace() impl where stack-local types were not properly
constructed using the Allocator of the container which breaks uses-allocator
@@ -56,20 +59,20 @@ when the returned proxy is not used.
* Refactor internal implementation to be dramatically faster
* Allow `final` Hasher and KeyEqual objects
* Update documentation, adding benchmark graphs and notes on the new internal
* Update documentation, adding benchmark graphs and notes on the new internal
data structures
== Release 1.79.0
* Improved {cpp}20 support:
** All containers have been updated to support
** All containers have been updated to support
heterogeneous `count`, `equal_range` and `find`.
** All containers now implement the member function `contains`.
** `erase_if` has been implemented for all containers.
* Improved {cpp}23 support:
** All containers have been updated to support
heterogeneous `erase` and `extract`.
* Changed behavior of `reserve` to eagerly
* Changed behavior of `reserve` to eagerly
allocate ({github-pr-url}/59[PR#59^]).
* Various warning fixes in the test suite.
* Update code to internally use `boost::allocator_traits`.
+1 -1
View File
@@ -38,7 +38,7 @@ Users can then declare a hash function `Hash` as avalanching either by embedding
into the definition of `Hash`, or directly by specializing `hash_is_avalanching<Hash>` to a class with
an embedded compile-time constant `value` set to `true`.
xref:unordered_flat_set[`boost::unordered_flat_set`] and xref:unordered_flat_map[`boost::unordered_flat_map`]
Open-addressing and concurrent containers
use the provided hash function `Hash` as-is if `hash_is_avalanching<Hash>::value` is `true`; otherwise, they
implement a bit-mixing post-processing stage to increase the quality of hashing at the expense of
extra computational cost.
+1 -1
View File
@@ -152,7 +152,7 @@ performing container-wide operations such as swapping or assignment.
By using atomic operations to access the group metadata, lookup is (group-level)
lock-free up to the point where an actual comparison needs to be done with an element
that has been previously SIMD-matched: only then it's the group's spinlock used.
that has been previously SIMD-matched: only then is the group's spinlock used.
Insertion uses the following _optimistic algorithm_:
+8 -2
View File
@@ -318,7 +318,10 @@ namespace boost {
reference operator*() const noexcept { return dereference(); }
pointer operator->() const noexcept { return boost::to_address(p); }
pointer operator->() const noexcept
{
return std::addressof(dereference());
}
grouped_local_bucket_iterator& operator++() noexcept
{
@@ -386,7 +389,10 @@ namespace boost {
reference operator*() const noexcept { return dereference(); }
pointer operator->() const noexcept { return boost::to_address(p); }
pointer operator->() const noexcept
{
return std::addressof(dereference());
}
const_grouped_local_bucket_iterator& operator++() noexcept
{
@@ -198,13 +198,13 @@ private:
template<typename Integral>
struct atomic_integral
{
operator Integral()const{return n.load(std::memory_order_relaxed);}
void operator=(Integral m){n.store(m,std::memory_order_relaxed);}
void operator|=(Integral m){n.fetch_or(m,std::memory_order_relaxed);}
void operator&=(Integral m){n.fetch_and(m,std::memory_order_relaxed);}
operator Integral()const{return n.load(std::memory_order_acquire);}
void operator=(Integral m){n.store(m,std::memory_order_release);}
void operator|=(Integral m){n.fetch_or(m);}
void operator&=(Integral m){n.fetch_and(m);}
atomic_integral& operator=(atomic_integral const& rhs) {
n.store(rhs.n.load(std::memory_order_relaxed),std::memory_order_relaxed);
n.store(rhs.n.load());
return *this;
}
@@ -1177,7 +1177,7 @@ private:
do{
auto n=unchecked_countr_zero(mask);
if(BOOST_LIKELY(
pg->is_occupied(n)&&bool(this->pred()(x,this->key_from(p[n]))))){
is_occupied(pg,n)&&bool(this->pred()(x,this->key_from(p[n]))))){
f(pg,n,p+n);
return 1;
}
@@ -1236,7 +1236,7 @@ private:
do{
auto n=unchecked_countr_zero(mask);
if(BOOST_LIKELY(
pg->is_occupied(n)&&
is_occupied(pg,n)&&
bool(this->pred()(*it,this->key_from(p[n]))))){
f(cast_for(access_mode,type_policy::value_from(p[n])));
++res;
@@ -1436,10 +1436,103 @@ private:
bool commit_=false;
};
struct latch_free_reserve_slot
{
latch_free_reserve_slot(group_type* pg_,std::size_t pos_):pg{pg_},pos{pos_}
{
unsigned char expected=0;
succeeded_=reinterpret_cast<std::atomic<unsigned char>*>(pg)[pos].
compare_exchange_weak(expected,1);
}
~latch_free_reserve_slot()
{
if(succeeded_&&!commit_)pg->reset(pos);
}
bool succeeded()const{return succeeded_;}
void commit(){commit_=true;}
group_type *pg;
std::size_t pos;
bool succeeded_;
bool commit_=false;
};
struct assign_insert_counter_on_exit
{
~assign_insert_counter_on_exit(){counter=x;}
group_insert_counter_type &counter;
boost::uint32_t x;
};
template<typename GroupAccessMode,typename F,typename... Args>
BOOST_FORCEINLINE int
unprotected_norehash_emplace_or_visit(
GroupAccessMode access_mode,F&& f,Args&&... args)
{
return unprotected_norehash_emplace_or_visit_with_layout(
std::integral_constant<bool,group_type::regular_layout>{},
access_mode,std::forward<F>(f),std::forward<Args>(args)...);
}
template<typename GroupAccessMode,typename F,typename... Args>
BOOST_FORCEINLINE int
unprotected_norehash_emplace_or_visit_with_layout(
std::true_type, /* regular layout, almost-latch-free */
GroupAccessMode access_mode,F&& f,Args&&... args)
{
const auto &k=this->key_from(std::forward<Args>(args)...);
auto hash=this->hash_for(k);
auto pos0=this->position_for(hash);
for(;;){
startover:
boost::uint32_t counter=0;
while(BOOST_UNLIKELY((counter=insert_counter(pos0))%2==1)){}
if(unprotected_visit(
access_mode,k,pos0,hash,std::forward<F>(f)))return 0;
reserve_size rsize(*this);
if(BOOST_LIKELY(rsize.succeeded())){
for(prober pb(pos0);;pb.next(this->arrays.groups_size_mask)){
auto pos=pb.get();
auto pg=this->arrays.groups()+pos;
auto mask=pg->match_available();
if(BOOST_LIKELY(mask!=0)){
auto n=unchecked_countr_zero(mask);
latch_free_reserve_slot rslot{pg,n};
if(BOOST_UNLIKELY(!rslot.succeeded())){
/* slot wasn't empty */
goto startover;
}
if(BOOST_UNLIKELY(
!insert_counter(pos0).compare_exchange_weak(counter,counter+1))){
/* other thread inserted from pos0, need to start over */
goto startover;
}
assign_insert_counter_on_exit a{insert_counter(pos0),counter+2};
auto p=this->arrays.elements()+pos*N+n;
this->construct_element(p,std::forward<Args>(args)...);
pg->set(n,hash);
rslot.commit();
rsize.commit();
return 1;
}
pg->mark_overflow(hash);
}
}
else return -1;
}
}
template<typename GroupAccessMode,typename F,typename... Args>
BOOST_FORCEINLINE int
unprotected_norehash_emplace_or_visit_with_layout(
std::false_type, /* non-regular layout, latched */
GroupAccessMode access_mode,F&& f,Args&&... args)
{
const auto &k=this->key_from(std::forward<Args>(args)...);
auto hash=this->hash_for(k);
@@ -1486,6 +1579,46 @@ private:
}
}
/* check occupation with previous unsynced match */
static bool is_occupied(group_type* pg,std::size_t pos)
{
return is_occupied(
std::integral_constant<bool,group_type::regular_layout>{},pg,pos);
}
static bool is_occupied(std::true_type,group_type* pg,std::size_t pos)
{
/* regular layout, almost-latch-free insertion -> possible reserved slot */
return reinterpret_cast<std::atomic<unsigned char>*>(pg)[pos]>1;
}
static bool is_occupied(std::false_type,group_type* pg,std::size_t pos)
{
/* non-regular layout, latched insertion -> no reserved slots */
return pg->is_occupied(pos);
}
/* check occupation with previous synced match */
static bool is_really_occupied(group_type* pg,std::size_t pos)
{
return is_really_occupied(
std::integral_constant<bool,group_type::regular_layout>{},pg,pos);
}
static bool is_really_occupied(std::true_type,group_type* pg,std::size_t pos)
{
/* regular layout, almost-latch-free insertion -> possible reserved slot */
return reinterpret_cast<std::atomic<unsigned char>*>(pg)[pos]>1;
}
static bool is_really_occupied(std::false_type,group_type*,std::size_t)
{
/* non-regular layout, latched insertion -> no false positives */
return true;
}
template<typename GroupAccessMode,typename F>
auto for_all_elements(GroupAccessMode access_mode,F f)const
->decltype(f(nullptr),void())
@@ -1523,7 +1656,7 @@ private:
auto mask=this->match_really_occupied(pg,last);
while(mask){
auto n=unchecked_countr_zero(mask);
if(!f(pg,n,p+n))return false;
if(BOOST_LIKELY(is_really_occupied(pg,n))&&!f(pg,n,p+n))return false;
mask&=mask-1;
}
}
@@ -1558,7 +1691,7 @@ private:
auto mask=this->match_really_occupied(&g,last);
while(mask){
auto n=unchecked_countr_zero(mask);
f(&g,n,p+n);
if(BOOST_LIKELY(is_really_occupied(&g,n)))f(&g,n,p+n);
mask&=mask-1;
}
}
@@ -1580,7 +1713,7 @@ private:
auto mask=this->match_really_occupied(&g,last);
while(mask){
auto n=unchecked_countr_zero(mask);
if(!f(p+n))return false;
if(BOOST_LIKELY(is_really_occupied(&g,n))&&!f(p+n))return false;
mask&=mask-1;
}
return true;
@@ -0,0 +1,30 @@
// Copyright (C) 2023 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_UNORDERED_DETAIL_THROW_EXCEPTION_HPP
#define BOOST_UNORDERED_DETAIL_THROW_EXCEPTION_HPP
#include <boost/config.hpp>
#if defined(BOOST_HAS_PRAGMA_ONCE)
#pragma once
#endif
#include <boost/throw_exception.hpp>
#include <stdexcept>
namespace boost {
namespace unordered {
namespace detail {
BOOST_NOINLINE BOOST_NORETURN inline void throw_out_of_range(
char const* message)
{
boost::throw_exception(std::out_of_range(message));
}
} // namespace detail
} // namespace unordered
} // namespace boost
#endif // BOOST_UNORDERED_DETAIL_THROW_EXCEPTION_HPP
@@ -14,12 +14,12 @@
#include <boost/unordered/detail/foa/flat_map_types.hpp>
#include <boost/unordered/detail/foa/table.hpp>
#include <boost/unordered/detail/serialize_container.hpp>
#include <boost/unordered/detail/throw_exception.hpp>
#include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_flat_map_fwd.hpp>
#include <boost/core/allocator_access.hpp>
#include <boost/container_hash/hash.hpp>
#include <boost/throw_exception.hpp>
#include <initializer_list>
#include <iterator>
@@ -459,8 +459,8 @@ namespace boost {
// TODO: someday refactor this to conditionally serialize the key and
// include it in the error message
//
boost::throw_exception(
std::out_of_range("key was not found in unordered_flat_map"));
boost::unordered::detail::throw_out_of_range(
"key was not found in unordered_flat_map");
}
mapped_type const& at(key_type const& key) const
@@ -469,8 +469,8 @@ namespace boost {
if (pos != table_.end()) {
return pos->second;
}
boost::throw_exception(
std::out_of_range("key was not found in unordered_flat_map"));
boost::unordered::detail::throw_out_of_range(
"key was not found in unordered_flat_map");
}
template <class K>
@@ -483,8 +483,8 @@ namespace boost {
if (pos != table_.end()) {
return pos->second;
}
boost::throw_exception(
std::out_of_range("key was not found in unordered_flat_map"));
boost::unordered::detail::throw_out_of_range(
"key was not found in unordered_flat_map");
}
template <class K>
@@ -497,8 +497,8 @@ namespace boost {
if (pos != table_.end()) {
return pos->second;
}
boost::throw_exception(
std::out_of_range("key was not found in unordered_flat_map"));
boost::unordered::detail::throw_out_of_range(
"key was not found in unordered_flat_map");
}
BOOST_FORCEINLINE mapped_type& operator[](key_type const& key)
+9 -8
View File
@@ -16,6 +16,7 @@
#include <boost/unordered/detail/map.hpp>
#include <boost/unordered/detail/serialize_fca_container.hpp>
#include <boost/unordered/detail/throw_exception.hpp>
#include <boost/unordered/detail/type_traits.hpp>
#include <boost/container_hash/hash.hpp>
@@ -1586,8 +1587,8 @@ namespace boost {
return p->value().second;
}
boost::throw_exception(
std::out_of_range("Unable to find key in unordered_map."));
boost::unordered::detail::throw_out_of_range(
"Unable to find key in unordered_map.");
}
template <class K, class T, class H, class P, class A>
@@ -1602,8 +1603,8 @@ namespace boost {
return p->value().second;
}
boost::throw_exception(
std::out_of_range("Unable to find key in unordered_map."));
boost::unordered::detail::throw_out_of_range(
"Unable to find key in unordered_map.");
}
template <class K, class T, class H, class P, class A>
@@ -1620,8 +1621,8 @@ namespace boost {
return p->value().second;
}
boost::throw_exception(
std::out_of_range("Unable to find key in unordered_map."));
boost::unordered::detail::throw_out_of_range(
"Unable to find key in unordered_map.");
}
template <class K, class T, class H, class P, class A>
@@ -1638,8 +1639,8 @@ namespace boost {
return p->value().second;
}
boost::throw_exception(
std::out_of_range("Unable to find key in unordered_map."));
boost::unordered::detail::throw_out_of_range(
"Unable to find key in unordered_map.");
}
template <class K, class T, class H, class P, class A>
@@ -15,12 +15,12 @@
#include <boost/unordered/detail/foa/node_map_types.hpp>
#include <boost/unordered/detail/foa/table.hpp>
#include <boost/unordered/detail/serialize_container.hpp>
#include <boost/unordered/detail/throw_exception.hpp>
#include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_node_map_fwd.hpp>
#include <boost/core/allocator_access.hpp>
#include <boost/container_hash/hash.hpp>
#include <boost/throw_exception.hpp>
#include <initializer_list>
#include <iterator>
@@ -554,8 +554,8 @@ namespace boost {
// TODO: someday refactor this to conditionally serialize the key and
// include it in the error message
//
boost::throw_exception(
std::out_of_range("key was not found in unordered_node_map"));
boost::unordered::detail::throw_out_of_range(
"key was not found in unordered_node_map");
}
mapped_type const& at(key_type const& key) const
@@ -564,8 +564,8 @@ namespace boost {
if (pos != table_.end()) {
return pos->second;
}
boost::throw_exception(
std::out_of_range("key was not found in unordered_node_map"));
boost::unordered::detail::throw_out_of_range(
"key was not found in unordered_node_map");
}
template <class K>
@@ -578,8 +578,8 @@ namespace boost {
if (pos != table_.end()) {
return pos->second;
}
boost::throw_exception(
std::out_of_range("key was not found in unordered_node_map"));
boost::unordered::detail::throw_out_of_range(
"key was not found in unordered_node_map");
}
template <class K>
@@ -592,8 +592,8 @@ namespace boost {
if (pos != table_.end()) {
return pos->second;
}
boost::throw_exception(
std::out_of_range("key was not found in unordered_node_map"));
boost::unordered::detail::throw_out_of_range(
"key was not found in unordered_node_map");
}
BOOST_FORCEINLINE mapped_type& operator[](key_type const& key)
+1 -1
View File
@@ -9,7 +9,7 @@ if(HAVE_BOOST_TEST)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
set(BOOST_TEST_LINK_LIBRARIES Boost::unordered Boost::core Boost::concept_check)
set(BOOST_TEST_LINK_LIBRARIES Boost::unordered Boost::core Boost::concept_check Boost::tuple)
function(fca_tests)
boost_test(PREFIX boost_unordered ${ARGN})
+1
View File
@@ -7,6 +7,7 @@
#define BOOST_UNORDERED_TEST_TEST_HEADER
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/stringize.hpp>
+38 -9
View File
@@ -15,6 +15,7 @@
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/helpers.hpp"
#include "../helpers/metafunctions.hpp"
#if BOOST_WORKAROUND(BOOST_MSVC, < 1400)
#pragma warning(disable : 4267) // conversion from 'size_t' to 'unsigned int',
@@ -31,6 +32,7 @@ namespace bucket_tests {
typedef typename X::size_type size_type;
typedef typename X::const_local_iterator const_local_iterator;
typedef typename X::value_type value_type;
test::random_values<X> v(1000, generator);
X x(v.begin(), v.end());
@@ -58,15 +60,42 @@ namespace bucket_tests {
}
for (size_type i = 0; i < x.bucket_count(); ++i) {
BOOST_TEST(x.bucket_size(i) ==
static_cast<size_type>(std::distance(x.begin(i), x.end(i))));
BOOST_TEST(x.bucket_size(i) ==
static_cast<size_type>(std::distance(x.cbegin(i), x.cend(i))));
X const& x_ref = x;
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(std::distance(
x_ref.begin(i), x_ref.end(i))));
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(std::distance(
x_ref.cbegin(i), x_ref.cend(i))));
{
auto begin = x.begin(i);
auto end = x.end(i);
BOOST_TEST(x.bucket_size(i) ==
static_cast<size_type>(std::distance(begin, end)));
for (auto pos = begin; pos != end; ++pos) {
using pointer_type = typename std::conditional<test::is_set<X>::value,
value_type const*, value_type*>::type;
pointer_type p = pos.operator->();
BOOST_TEST_EQ(p, std::addressof(*pos));
}
auto cbegin = x.cbegin(i);
auto cend = x.cend(i);
BOOST_TEST(x.bucket_size(i) ==
static_cast<size_type>(std::distance(cbegin, cend)));
for (auto pos = cbegin; pos != cend; ++pos) {
value_type const* p = pos.operator->();
BOOST_TEST_EQ(p, std::addressof(*pos));
}
}
{
X const& x_ref = x;
BOOST_TEST_TRAIT_SAME(
decltype(x_ref.begin()), decltype(x_ref.cbegin()));
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(std::distance(
x_ref.begin(i), x_ref.end(i))));
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(std::distance(
x_ref.cbegin(i), x_ref.cend(i))));
}
}
}