Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e8cd7da67a | |||
| d2797abcb7 | |||
| ffb34fdcde | |||
| 38eca0efc0 | |||
| 4f8a037957 | |||
| 61d92b5847 | |||
| 33f4b04f69 | |||
| 8b024986da | |||
| 4948a3a12e | |||
| 35c265f313 | |||
| 15b63cc169 | |||
| 3de21a474c | |||
| 6a6a3084da | |||
| abd69e859e | |||
| ff20d71676 | |||
| 9a7d1d336a | |||
| 3fc18d56ac | |||
| 6bcf457b46 | |||
| 01b2369700 | |||
| fcb3f0e82a | |||
| 1e4deb10a1 |
@@ -31,14 +31,28 @@ environment:
|
||||
B2_VARIANT: debug,release
|
||||
|
||||
matrix:
|
||||
- FLAVOR: Visual Studio 2008, 2010, 2012
|
||||
- FLAVOR: Visual Studio 2008
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
B2_TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0
|
||||
B2_TOOLSET: msvc-9.0
|
||||
B2_ADDRESS_MODEL: 32 # No 64bit support
|
||||
|
||||
- FLAVOR: Visual Studio 2013, 2015
|
||||
- FLAVOR: Visual Studio 2010
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
B2_TOOLSET: msvc-12.0,msvc-14.0
|
||||
B2_TOOLSET: msvc-10.0
|
||||
B2_ADDRESS_MODEL: 32 # No 64bit support
|
||||
|
||||
- FLAVOR: Visual Studio 2012
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
B2_TOOLSET: msvc-11.0
|
||||
B2_ADDRESS_MODEL: 32 # No 64bit support
|
||||
|
||||
- FLAVOR: Visual Studio 2013
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
B2_TOOLSET: msvc-12.0
|
||||
|
||||
- FLAVOR: Visual Studio 2015
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
B2_TOOLSET: msvc-14.0
|
||||
|
||||
- FLAVOR: Visual Studio 2017, C++14
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
@@ -55,32 +69,32 @@ environment:
|
||||
B2_CXXSTD: latest
|
||||
B2_TOOLSET: msvc-14.1
|
||||
|
||||
- FLAVOR: cygwin (32-bit, C++03,11)
|
||||
- FLAVOR: cygwin (32-bit, C++03)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
ADDPATH: C:\cygwin\bin;
|
||||
B2_ADDRESS_MODEL: 32
|
||||
B2_CXXSTD: 03,11
|
||||
B2_CXXSTD: 03
|
||||
B2_TOOLSET: gcc
|
||||
|
||||
- FLAVOR: cygwin (32-bit, C++14,1z)
|
||||
- FLAVOR: cygwin (32-bit, C++11)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
ADDPATH: C:\cygwin\bin;
|
||||
B2_ADDRESS_MODEL: 32
|
||||
B2_CXXSTD: 14,1z
|
||||
B2_CXXSTD: 11
|
||||
B2_TOOLSET: gcc
|
||||
|
||||
- FLAVOR: cygwin (64-bit, C++03,11)
|
||||
- FLAVOR: cygwin (32-bit, C++14)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
B2_ADDRESS_MODEL: 64
|
||||
B2_CXXSTD: 03,11
|
||||
ADDPATH: C:\cygwin\bin;
|
||||
B2_ADDRESS_MODEL: 32
|
||||
B2_CXXSTD: 14
|
||||
B2_TOOLSET: gcc
|
||||
|
||||
- FLAVOR: cygwin (64-bit, C++14,1z)
|
||||
- FLAVOR: cygwin (32-bit, C++1z)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
B2_ADDRESS_MODEL: 64
|
||||
B2_CXXSTD: 14,1z
|
||||
ADDPATH: C:\cygwin\bin;
|
||||
B2_ADDRESS_MODEL: 32
|
||||
B2_CXXSTD: 1z
|
||||
B2_TOOLSET: gcc
|
||||
|
||||
- FLAVOR: cygwin (64-bit, latest, C++03)
|
||||
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
# Linux, gcc
|
||||
- { compiler: gcc-7, cxxstd: '03,11,14,17', os: ubuntu-20.04, install: 'g++-7' }
|
||||
- { compiler: gcc-8, cxxstd: '03,11,14,17', os: ubuntu-20.04, install: 'g++-8' }
|
||||
- { compiler: gcc-9, cxxstd: '03,11,14,17', os: ubuntu-20.04, install: 'g++-9' }
|
||||
- { compiler: gcc-9, cxxstd: '03,11,14,17', os: ubuntu-22.04, install: 'g++-9' }
|
||||
- { compiler: gcc-10, cxxstd: '03,11,14,17,20', os: ubuntu-22.04, install: 'g++-10' }
|
||||
- { compiler: gcc-11, cxxstd: '03,11,14,17,20', os: ubuntu-22.04, install: 'g++-11' }
|
||||
- { name: "gcc-12 w/ sanitizers (03,11,14)", sanitize: yes,
|
||||
@@ -54,8 +54,8 @@ jobs:
|
||||
- { name: Collect coverage, coverage: yes,
|
||||
compiler: gcc-12, cxxstd: '03,20', os: ubuntu-22.04, install: 'g++-12-multilib', address-model: '32,64', ccache_key: "cov" }
|
||||
|
||||
- { name: "cfoa tsan (gcc)", cxxstd: '11,14,17,20,2b', os: ubuntu-22.04, compiler: gcc-12,
|
||||
targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes }
|
||||
- { name: "cfoa tsan (gcc-12)", cxxstd: '11,14,17,20,2b', os: ubuntu-22.04, compiler: gcc-12,
|
||||
targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes, ccache_key: "tsan" }
|
||||
|
||||
# Linux, clang, libc++
|
||||
- { compiler: clang-7, cxxstd: '03,11,14,17', os: ubuntu-20.04, stdlib: libc++, install: 'clang-7 libc++-7-dev libc++abi-7-dev' }
|
||||
@@ -67,7 +67,6 @@ jobs:
|
||||
- { name: "clang-12 w/ sanitizers (17,20,2b)", sanitize: yes,
|
||||
compiler: clang-12, cxxstd: '17,20,2b', os: ubuntu-20.04, stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san2" }
|
||||
- { compiler: clang-13, cxxstd: '03,11,14,17,20,2b', os: ubuntu-22.04, stdlib: libc++, install: 'clang-13 libc++-13-dev libc++abi-13-dev' }
|
||||
- { compiler: clang-14, cxxstd: '03,11,14,17,20,2b', os: ubuntu-22.04, stdlib: libc++, install: 'clang-14 libc++-14-dev libc++abi-14-dev' }
|
||||
|
||||
# not using libc++ because of https://github.com/llvm/llvm-project/issues/52771
|
||||
- { name: "clang-14 w/ sanitizers (03,11,14)", sanitize: yes,
|
||||
@@ -75,16 +74,19 @@ jobs:
|
||||
- { name: "clang-14 w/ sanitizers (17,20,2b)", sanitize: yes,
|
||||
compiler: clang-14, cxxstd: '17,20,2b', os: ubuntu-22.04, ccache_key: "san2" }
|
||||
|
||||
- { name: "cfoa tsan (clang)", cxxstd: '11,14,17,20,2b', os: ubuntu-22.04, compiler: clang-14,
|
||||
- { 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,
|
||||
stdlib: libc++, install: 'clang-14 libc++-14-dev libc++abi-14-dev' }
|
||||
stdlib: libc++, install: 'clang-14 libc++-14-dev libc++abi-14-dev', ccache_key: "tsan" }
|
||||
|
||||
- { compiler: clang-15, cxxstd: '03,11,14,17,20,2b', os: ubuntu-22.04, stdlib: libc++, install: 'clang-15 libc++-15-dev libc++abi-15-dev' }
|
||||
|
||||
# OSX, clang
|
||||
- { compiler: clang, cxxstd: '03,11,14,17,2a', os: macos-11, }
|
||||
- { compiler: clang, cxxstd: '03,11,14,17,2a', os: macos-12, sanitize: yes }
|
||||
- { compiler: clang, cxxstd: '11,14,17,2a', os: macos-12, thread-sanitize: yes, targets: 'libs/unordered/test//cfoa_tests' }
|
||||
- { compiler: clang, cxxstd: '03,11,14,17,2a', os: macos-11 }
|
||||
- { compiler: clang, cxxstd: '03,11,14,17,2a', os: macos-12, sanitize: yes, ccache_key: "san1" }
|
||||
- { compiler: clang, cxxstd: '11,14,17,2a', os: macos-12, thread-sanitize: yes, targets: 'libs/unordered/test//cfoa_tests', ccache_key: "tsan" }
|
||||
- { compiler: clang, cxxstd: '03,11,14,17,20,2b', os: macos-13 }
|
||||
|
||||
timeout-minutes: 180
|
||||
timeout-minutes: 210
|
||||
runs-on: ${{matrix.os}}
|
||||
container: ${{matrix.container}}
|
||||
env: {B2_USE_CCACHE: 1}
|
||||
|
||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 23 KiB |
@@ -17,10 +17,13 @@
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/list.hpp>
|
||||
#include <boost/mp11/tuple.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/unordered/detail/foa/core.hpp>
|
||||
#include <boost/unordered/detail/foa/rw_spinlock.hpp>
|
||||
#include <boost/unordered/detail/foa/takes_arg_as_const_reference.hpp>
|
||||
#include <boost/unordered/detail/foa/tuple_rotate_right.hpp>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
@@ -485,7 +488,7 @@ public:
|
||||
template<typename Key,typename F>
|
||||
BOOST_FORCEINLINE std::size_t visit(const Key& x,F&& f)
|
||||
{
|
||||
return visit_impl(group_exclusive{},x,std::forward<F>(f));
|
||||
return visit_impl(group_access_for<F>{},x,std::forward<F>(f));
|
||||
}
|
||||
|
||||
template<typename Key,typename F>
|
||||
@@ -502,7 +505,7 @@ public:
|
||||
|
||||
template<typename F> std::size_t visit_all(F&& f)
|
||||
{
|
||||
return visit_all_impl(group_exclusive{},std::forward<F>(f));
|
||||
return visit_all_impl(group_access_for<F>{},std::forward<F>(f));
|
||||
}
|
||||
|
||||
template<typename F> std::size_t visit_all(F&& f)const
|
||||
@@ -520,7 +523,7 @@ public:
|
||||
void visit_all(ExecutionPolicy&& policy,F&& f)
|
||||
{
|
||||
visit_all_impl(
|
||||
group_exclusive{},
|
||||
group_access_for<F>{},
|
||||
std::forward<ExecutionPolicy>(policy),std::forward<F>(f));
|
||||
}
|
||||
|
||||
@@ -582,7 +585,7 @@ public:
|
||||
BOOST_FORCEINLINE bool try_emplace_or_visit(Key&& x,Args&&... args)
|
||||
{
|
||||
return emplace_or_visit_flast(
|
||||
group_exclusive{},
|
||||
group_access_for_last_of<Args...>{},
|
||||
try_emplace_args_t{},std::forward<Key>(x),std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
@@ -598,7 +601,7 @@ public:
|
||||
BOOST_FORCEINLINE bool emplace_or_visit(Args&&... args)
|
||||
{
|
||||
return construct_and_emplace_or_visit_flast(
|
||||
group_exclusive{},std::forward<Args>(args)...);
|
||||
group_access_for_last_of<Args...>{},std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
@@ -611,7 +614,7 @@ public:
|
||||
template<typename F>
|
||||
BOOST_FORCEINLINE bool insert_or_visit(const init_type& x,F&& f)
|
||||
{
|
||||
return emplace_or_visit_impl(group_exclusive{},std::forward<F>(f),x);
|
||||
return emplace_or_visit_impl(group_access_for<F>{},std::forward<F>(f),x);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
@@ -624,7 +627,7 @@ public:
|
||||
BOOST_FORCEINLINE bool insert_or_visit(init_type&& x,F&& f)
|
||||
{
|
||||
return emplace_or_visit_impl(
|
||||
group_exclusive{},std::forward<F>(f),std::move(x));
|
||||
group_access_for<F>{},std::forward<F>(f),std::move(x));
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
@@ -640,7 +643,7 @@ public:
|
||||
BOOST_FORCEINLINE auto insert_or_visit(const Value& x,F&& f)
|
||||
->enable_if_is_value_type<Value,bool>
|
||||
{
|
||||
return emplace_or_visit_impl(group_exclusive{},std::forward<F>(f),x);
|
||||
return emplace_or_visit_impl(group_access_for<F>{},std::forward<F>(f),x);
|
||||
}
|
||||
|
||||
template<typename Value,typename F>
|
||||
@@ -655,7 +658,7 @@ public:
|
||||
->enable_if_is_value_type<Value,bool>
|
||||
{
|
||||
return emplace_or_visit_impl(
|
||||
group_exclusive{},std::forward<F>(f),std::move(x));
|
||||
group_access_for<F>{},std::forward<F>(f),std::move(x));
|
||||
}
|
||||
|
||||
template<typename Value,typename F>
|
||||
@@ -683,7 +686,7 @@ public:
|
||||
group_exclusive{},x,this->position_for(hash),hash,
|
||||
[&,this](group_type* pg,unsigned int n,element_type* p)
|
||||
{
|
||||
if(f(cast_for(group_exclusive{},type_policy::value_from(*p)))){
|
||||
if(f(cast_for(group_access_for<F>{},type_policy::value_from(*p)))){
|
||||
super::erase(pg,n,p);
|
||||
res=1;
|
||||
}
|
||||
@@ -699,7 +702,7 @@ public:
|
||||
for_all_elements(
|
||||
group_exclusive{},
|
||||
[&,this](group_type* pg,unsigned int n,element_type* p){
|
||||
if(f(cast_for(group_exclusive{},type_policy::value_from(*p)))){
|
||||
if(f(cast_for(group_access_for<F>{},type_policy::value_from(*p)))){
|
||||
super::erase(pg,n,p);
|
||||
++res;
|
||||
}
|
||||
@@ -716,7 +719,7 @@ public:
|
||||
for_all_elements(
|
||||
group_exclusive{},std::forward<ExecutionPolicy>(policy),
|
||||
[&,this](group_type* pg,unsigned int n,element_type* p){
|
||||
if(f(cast_for(group_exclusive{},type_policy::value_from(*p)))){
|
||||
if(f(cast_for(group_access_for<F>{},type_policy::value_from(*p)))){
|
||||
super::erase(pg,n,p);
|
||||
}
|
||||
});
|
||||
@@ -886,6 +889,17 @@ private:
|
||||
using group_shared=std::false_type;
|
||||
using group_exclusive=std::true_type;
|
||||
|
||||
template<typename F>
|
||||
using group_access_for=typename std::conditional<
|
||||
takes_arg_as_const_reference<F,value_type>::value,
|
||||
group_shared,
|
||||
group_exclusive
|
||||
>::type;
|
||||
|
||||
template<typename... Args>
|
||||
using group_access_for_last_of=
|
||||
group_access_for<mp11::mp_back<mp11::mp_list<Args...>>>;
|
||||
|
||||
inline group_shared_lock_guard access(group_shared,std::size_t pos)const
|
||||
{
|
||||
return this->arrays.group_accesses[pos].shared_access();
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/* Copyright 2023 Joaquin M Lopez Munoz.
|
||||
* 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)
|
||||
*
|
||||
* See https://www.boost.org/libs/unordered for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_FOA_TAKES_ARG_AS_CONST_REFERENCE_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_FOA_TAKES_ARG_AS_CONST_REFERENCE_HPP
|
||||
|
||||
#include <boost/type_traits/make_void.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
namespace unordered{
|
||||
namespace detail{
|
||||
namespace foa{
|
||||
|
||||
template<typename Arg,typename R,typename... Args>
|
||||
void check_function_1st_arg(R(*)(Arg,Args...));
|
||||
|
||||
template<typename Arg,typename R,typename... Args>
|
||||
void check_function_1st_arg(R(*)(Arg,Args...,...));
|
||||
|
||||
#define BOOST_UNORDERED_CHECK_MEMFUN_1ST_ARG(qualifier) \
|
||||
template<typename Arg,typename R,typename C,typename... Args> \
|
||||
void check_memfun_1st_arg(R(C::*)(Arg,Args...)qualifier); \
|
||||
\
|
||||
template<typename Arg,typename R,typename C,typename... Args> \
|
||||
void check_memfun_1st_arg(R(C::*)(Arg,Args...,...)qualifier);
|
||||
|
||||
/* VS warns when a pp function is directly called with an empty arg */
|
||||
#define BOOST_UNORDERED_EMPTY_PP_ARG()
|
||||
|
||||
BOOST_UNORDERED_CHECK_MEMFUN_1ST_ARG(BOOST_UNORDERED_EMPTY_PP_ARG())
|
||||
BOOST_UNORDERED_CHECK_MEMFUN_1ST_ARG(const)
|
||||
BOOST_UNORDERED_CHECK_MEMFUN_1ST_ARG(volatile)
|
||||
BOOST_UNORDERED_CHECK_MEMFUN_1ST_ARG(const volatile)
|
||||
BOOST_UNORDERED_CHECK_MEMFUN_1ST_ARG(&)
|
||||
BOOST_UNORDERED_CHECK_MEMFUN_1ST_ARG(const&)
|
||||
BOOST_UNORDERED_CHECK_MEMFUN_1ST_ARG(volatile&)
|
||||
BOOST_UNORDERED_CHECK_MEMFUN_1ST_ARG(const volatile&)
|
||||
BOOST_UNORDERED_CHECK_MEMFUN_1ST_ARG(&&)
|
||||
BOOST_UNORDERED_CHECK_MEMFUN_1ST_ARG(const&&)
|
||||
BOOST_UNORDERED_CHECK_MEMFUN_1ST_ARG(volatile&&)
|
||||
BOOST_UNORDERED_CHECK_MEMFUN_1ST_ARG(const volatile&&)
|
||||
|
||||
#undef BOOST_UNORDERED_EMPTY_PP_ARG
|
||||
#undef BOOST_UNORDERED_CHECK_MEMFUN_1ST_ARG
|
||||
|
||||
/* Detects if f(x) takes x as a const reference. From an implementation
|
||||
* technique by Kenneth Gorking.
|
||||
* Requires: F is invocable with an Arg&.
|
||||
*/
|
||||
|
||||
template<typename F,typename Arg,typename=void>
|
||||
struct takes_arg_as_const_reference0:std::false_type{};
|
||||
|
||||
template<typename F,typename Arg>
|
||||
struct takes_arg_as_const_reference0<
|
||||
F,Arg,
|
||||
decltype(check_function_1st_arg<const Arg&>(std::declval<F>()))
|
||||
>:std::true_type{};
|
||||
|
||||
template<typename F,typename Arg>
|
||||
struct takes_arg_as_const_reference0<
|
||||
F,Arg,
|
||||
boost::void_t<
|
||||
decltype(std::declval<F>().operator()(std::declval<Arg&>()))
|
||||
>
|
||||
>:std::true_type{};
|
||||
|
||||
template<typename F,typename Arg,typename=void>
|
||||
struct takes_arg_as_const_reference:takes_arg_as_const_reference0<F,Arg>{};
|
||||
|
||||
template<
|
||||
typename F,typename Arg,
|
||||
typename R=decltype(std::declval<F>()(std::declval<Arg&>())),
|
||||
typename RawF=
|
||||
typename std::remove_cv<typename std::remove_reference<F>::type>::type
|
||||
>
|
||||
decltype(check_memfun_1st_arg<Arg&,R,RawF>(&RawF::operator()))
|
||||
check_operator_call_takes_arg_as_reference();
|
||||
|
||||
template<typename F,typename Arg>
|
||||
struct takes_arg_as_const_reference<
|
||||
F,Arg,
|
||||
decltype(check_operator_call_takes_arg_as_reference<F,Arg>())
|
||||
>:std::false_type{};
|
||||
|
||||
} /* namespace foa */
|
||||
} /* namespace detail */
|
||||
} /* namespace unordered */
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -20,7 +20,7 @@ function(foa_tests)
|
||||
endfunction()
|
||||
|
||||
function(cfoa_tests)
|
||||
boost_test(PREFIX boost_unordered_cfoa LINK_LIBRARIES Threads::Threads ${ARGN})
|
||||
boost_test(PREFIX boost_unordered_cfoa LINK_LIBRARIES Boost::compat Threads::Threads ${ARGN})
|
||||
endfunction()
|
||||
|
||||
# FCA tests
|
||||
@@ -140,7 +140,6 @@ foa_tests(SOURCES exception/merge_exception_tests.cpp)
|
||||
|
||||
# CFOA tests
|
||||
|
||||
cfoa_tests(SOURCES cfoa/latch_tests.cpp)
|
||||
cfoa_tests(SOURCES cfoa/insert_tests.cpp)
|
||||
cfoa_tests(SOURCES cfoa/erase_tests.cpp)
|
||||
cfoa_tests(SOURCES cfoa/try_emplace_tests.cpp)
|
||||
@@ -159,5 +158,13 @@ cfoa_tests(SOURCES cfoa/exception_erase_tests.cpp)
|
||||
cfoa_tests(SOURCES cfoa/exception_constructor_tests.cpp)
|
||||
cfoa_tests(SOURCES cfoa/exception_assign_tests.cpp)
|
||||
cfoa_tests(SOURCES cfoa/exception_merge_tests.cpp)
|
||||
cfoa_tests(SOURCES cfoa/rw_spinlock_test.cpp)
|
||||
cfoa_tests(SOURCES cfoa/rw_spinlock_test2.cpp)
|
||||
cfoa_tests(SOURCES cfoa/rw_spinlock_test3.cpp)
|
||||
cfoa_tests(SOURCES cfoa/rw_spinlock_test4.cpp)
|
||||
cfoa_tests(SOURCES cfoa/rw_spinlock_test5.cpp)
|
||||
cfoa_tests(SOURCES cfoa/rw_spinlock_test6.cpp)
|
||||
cfoa_tests(SOURCES cfoa/rw_spinlock_test7.cpp)
|
||||
cfoa_tests(SOURCES cfoa/rw_spinlock_test8.cpp)
|
||||
|
||||
endif()
|
||||
|
||||
@@ -176,7 +176,6 @@ alias foa_tests :
|
||||
;
|
||||
|
||||
local CFOA_TESTS =
|
||||
latch_tests
|
||||
insert_tests
|
||||
erase_tests
|
||||
try_emplace_tests
|
||||
@@ -195,6 +194,15 @@ local CFOA_TESTS =
|
||||
exception_constructor_tests
|
||||
exception_assign_tests
|
||||
exception_merge_tests
|
||||
rw_spinlock_test
|
||||
rw_spinlock_test2
|
||||
rw_spinlock_test3
|
||||
rw_spinlock_test4
|
||||
rw_spinlock_test5
|
||||
rw_spinlock_test6
|
||||
rw_spinlock_test7
|
||||
rw_spinlock_test8
|
||||
takes_arg_as_cref_tests
|
||||
;
|
||||
|
||||
for local test in $(CFOA_TESTS)
|
||||
|
||||
@@ -787,7 +787,7 @@ namespace {
|
||||
|
||||
std::thread t1, t2, t3;
|
||||
|
||||
boost::latch start_latch(2), end_latch(2);
|
||||
boost::compat::latch start_latch(2), end_latch(2);
|
||||
|
||||
auto v1 = make_random_values(1024 * 16, [&] { return gen(rg); });
|
||||
auto v2 = v1;
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
// 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)
|
||||
|
||||
#include "latch.hpp"
|
||||
|
||||
#include "../helpers/generators.hpp"
|
||||
#include "../helpers/test.hpp"
|
||||
|
||||
#include <boost/compat/latch.hpp>
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/core/span.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
@@ -370,7 +369,7 @@ std::vector<boost::span<T> > split(
|
||||
|
||||
template <class T, class F> void thread_runner(std::vector<T>& values, F f)
|
||||
{
|
||||
boost::latch latch(static_cast<std::ptrdiff_t>(num_threads));
|
||||
boost::compat::latch latch(static_cast<std::ptrdiff_t>(num_threads));
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
auto subslices = split<T>(values, num_threads);
|
||||
|
||||
@@ -5,11 +5,10 @@
|
||||
#ifndef BOOST_UNORDERED_TEST_CFOA_HELPERS_HPP
|
||||
#define BOOST_UNORDERED_TEST_CFOA_HELPERS_HPP
|
||||
|
||||
#include "latch.hpp"
|
||||
|
||||
#include "../helpers/generators.hpp"
|
||||
#include "../helpers/test.hpp"
|
||||
|
||||
#include <boost/compat/latch.hpp>
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/core/span.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
@@ -339,7 +338,7 @@ std::vector<boost::span<T> > split(
|
||||
|
||||
template <class T, class F> void thread_runner(std::vector<T>& values, F f)
|
||||
{
|
||||
boost::latch latch(static_cast<std::ptrdiff_t>(num_threads));
|
||||
boost::compat::latch latch(static_cast<std::ptrdiff_t>(num_threads));
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
auto subslices = split<T>(values, num_threads);
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
// Copyright (C) 2023 Christian Mazakas
|
||||
// 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_TEST_CFOA_LATCH_HPP
|
||||
#define BOOST_UNORDERED_TEST_CFOA_LATCH_HPP
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <climits>
|
||||
#include <condition_variable>
|
||||
#include <cstddef>
|
||||
#include <mutex>
|
||||
|
||||
namespace boost {
|
||||
class latch
|
||||
{
|
||||
private:
|
||||
std::ptrdiff_t n_;
|
||||
mutable std::mutex m_;
|
||||
mutable std::condition_variable cv_;
|
||||
|
||||
public:
|
||||
explicit latch(std::ptrdiff_t expected) : n_{expected}, m_{}, cv_{}
|
||||
{
|
||||
BOOST_ASSERT(n_ >= 0);
|
||||
BOOST_ASSERT(n_ <= max());
|
||||
}
|
||||
|
||||
latch(latch const&) = delete;
|
||||
latch& operator=(latch const&) = delete;
|
||||
|
||||
~latch() = default;
|
||||
|
||||
void count_down(std::ptrdiff_t n = 1)
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_);
|
||||
count_down_and_notify(lk, n);
|
||||
}
|
||||
|
||||
bool try_wait() const noexcept
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_);
|
||||
return is_ready();
|
||||
}
|
||||
|
||||
void wait() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_);
|
||||
wait_impl(lk);
|
||||
}
|
||||
|
||||
void arrive_and_wait(std::ptrdiff_t n = 1)
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_);
|
||||
bool should_wait = count_down_and_notify(lk, n);
|
||||
if (should_wait) {
|
||||
wait_impl(lk);
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr std::ptrdiff_t max() noexcept { return INT_MAX; }
|
||||
|
||||
private:
|
||||
bool is_ready() const { return n_ == 0; }
|
||||
|
||||
bool count_down_and_notify(
|
||||
std::unique_lock<std::mutex>& lk, std::ptrdiff_t n)
|
||||
{
|
||||
n_ -= n;
|
||||
if (n_ == 0) {
|
||||
lk.unlock();
|
||||
cv_.notify_all();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wait_impl(std::unique_lock<std::mutex>& lk) const
|
||||
{
|
||||
cv_.wait(lk, [this] { return this->is_ready(); });
|
||||
}
|
||||
};
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_UNORDERED_TEST_CFOA_LATCH_HPP
|
||||
@@ -1,155 +0,0 @@
|
||||
// Copyright (C) 2023 Christian Mazakas
|
||||
// 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)
|
||||
|
||||
#define BOOST_ENABLE_ASSERT_HANDLER
|
||||
|
||||
#include "latch.hpp"
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
struct exception
|
||||
{
|
||||
};
|
||||
|
||||
namespace boost {
|
||||
void assertion_failed(
|
||||
char const* expr, char const* function, char const* file, long line)
|
||||
{
|
||||
(void)expr;
|
||||
(void)function;
|
||||
(void)file;
|
||||
(void)line;
|
||||
throw exception{};
|
||||
}
|
||||
} // namespace boost
|
||||
|
||||
namespace {
|
||||
void test_max() { BOOST_TEST_EQ(boost::latch::max(), INT_MAX); }
|
||||
|
||||
void test_constructor()
|
||||
{
|
||||
{
|
||||
auto const f = [] {
|
||||
boost::latch l(-1);
|
||||
(void)l;
|
||||
};
|
||||
BOOST_TEST_THROWS(f(), exception);
|
||||
}
|
||||
|
||||
{
|
||||
std::ptrdiff_t n = 0;
|
||||
|
||||
boost::latch l(n);
|
||||
BOOST_TEST(l.try_wait());
|
||||
}
|
||||
|
||||
{
|
||||
std::ptrdiff_t n = 16;
|
||||
|
||||
boost::latch l(n);
|
||||
BOOST_TEST_NOT(l.try_wait());
|
||||
|
||||
l.count_down(16);
|
||||
BOOST_TEST(l.try_wait());
|
||||
}
|
||||
|
||||
#if PTRDIFF_MAX > INT_MAX
|
||||
{
|
||||
auto const f = [] {
|
||||
std::ptrdiff_t n = INT_MAX;
|
||||
n += 10;
|
||||
boost::latch l(n);
|
||||
(void)l;
|
||||
};
|
||||
BOOST_TEST_THROWS(f(), exception);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_count_down_and_wait()
|
||||
{
|
||||
constexpr std::ptrdiff_t n = 1024;
|
||||
|
||||
boost::latch l(2 * n);
|
||||
|
||||
bool bs[] = {false, false};
|
||||
|
||||
std::thread t1([&] {
|
||||
l.wait();
|
||||
BOOST_TEST(bs[0]);
|
||||
BOOST_TEST(bs[1]);
|
||||
});
|
||||
|
||||
std::thread t2([&] {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (i == (n - 1)) {
|
||||
bs[0] = true;
|
||||
} else {
|
||||
BOOST_TEST_NOT(l.try_wait());
|
||||
}
|
||||
|
||||
l.count_down(1);
|
||||
}
|
||||
});
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (i == (n - 1)) {
|
||||
bs[1] = true;
|
||||
} else {
|
||||
BOOST_TEST_NOT(l.try_wait());
|
||||
}
|
||||
|
||||
l.count_down(1);
|
||||
}
|
||||
|
||||
t1.join();
|
||||
t2.join();
|
||||
|
||||
BOOST_TEST(l.try_wait());
|
||||
}
|
||||
|
||||
void test_arrive_and_wait()
|
||||
{
|
||||
std::ptrdiff_t const n = 16;
|
||||
|
||||
boost::latch l(2 * n);
|
||||
|
||||
int xs[n] = {0};
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
threads.emplace_back([&l, &xs, i, n] {
|
||||
(void)n;
|
||||
for (int j = 0; j < n; ++j) {
|
||||
BOOST_TEST_EQ(xs[j], 0);
|
||||
}
|
||||
|
||||
l.arrive_and_wait(2);
|
||||
|
||||
xs[i] = 1;
|
||||
});
|
||||
}
|
||||
|
||||
for (auto& t : threads) {
|
||||
t.join();
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
BOOST_TEST_EQ(xs[i], 1);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int main()
|
||||
{
|
||||
test_max();
|
||||
test_constructor();
|
||||
test_count_down_and_wait();
|
||||
test_arrive_and_wait();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -103,7 +103,7 @@ namespace {
|
||||
map2_type x2(2 * vals1.size(), allocator_type(3));
|
||||
|
||||
std::thread t1, t2, t3;
|
||||
boost::latch l(2);
|
||||
boost::compat::latch l(2);
|
||||
|
||||
std::mutex m;
|
||||
std::condition_variable cv;
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace {
|
||||
map_type x(0, hasher(1), key_equal(2), allocator_type(3));
|
||||
|
||||
std::thread t1, t2, t3;
|
||||
boost::latch l(2);
|
||||
boost::compat::latch l(2);
|
||||
|
||||
std::mutex m;
|
||||
std::condition_variable cv;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2023 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/unordered/detail/foa/rw_spinlock.hpp>
|
||||
#include <mutex>
|
||||
|
||||
using boost::unordered::detail::foa::rw_spinlock;
|
||||
|
||||
// Sanity check only
|
||||
|
||||
static rw_spinlock sp;
|
||||
static rw_spinlock sp2;
|
||||
|
||||
int main()
|
||||
{
|
||||
sp.lock();
|
||||
sp2.lock();
|
||||
sp.unlock();
|
||||
sp2.unlock();
|
||||
|
||||
{
|
||||
std::lock_guard<rw_spinlock> lock( sp );
|
||||
std::lock_guard<rw_spinlock> lock2( sp2 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright 2023 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/unordered/detail/foa/rw_spinlock.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <mutex>
|
||||
|
||||
using boost::unordered::detail::foa::rw_spinlock;
|
||||
|
||||
static rw_spinlock sp;
|
||||
static rw_spinlock sp2;
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_TEST( sp.try_lock() );
|
||||
BOOST_TEST( !sp.try_lock() );
|
||||
BOOST_TEST( sp2.try_lock() );
|
||||
BOOST_TEST( !sp.try_lock() );
|
||||
BOOST_TEST( !sp2.try_lock() );
|
||||
sp.unlock();
|
||||
sp2.unlock();
|
||||
|
||||
sp.lock();
|
||||
BOOST_TEST( !sp.try_lock() );
|
||||
sp2.lock();
|
||||
BOOST_TEST( !sp.try_lock() );
|
||||
BOOST_TEST( !sp2.try_lock() );
|
||||
sp.unlock();
|
||||
sp2.unlock();
|
||||
|
||||
{
|
||||
std::lock_guard<rw_spinlock> lock( sp );
|
||||
BOOST_TEST( !sp.try_lock() );
|
||||
std::lock_guard<rw_spinlock> lock2( sp2 );
|
||||
BOOST_TEST( !sp.try_lock() );
|
||||
BOOST_TEST( !sp2.try_lock() );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2023 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/unordered/detail/foa/rw_spinlock.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <cstdio>
|
||||
|
||||
using boost::unordered::detail::foa::rw_spinlock;
|
||||
|
||||
static int count = 0;
|
||||
static rw_spinlock sp;
|
||||
|
||||
void f( int k, int n )
|
||||
{
|
||||
std::printf( "Thread %d started.\n", k );
|
||||
|
||||
for( int i = 0; i < n; ++i )
|
||||
{
|
||||
std::lock_guard<rw_spinlock> lock( sp );
|
||||
++count;
|
||||
}
|
||||
|
||||
std::printf( "Thread %d finished.\n", k );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int const N = 1000000; // iterations
|
||||
int const M = 8; // threads
|
||||
|
||||
std::thread th[ M ];
|
||||
|
||||
for( int i = 0; i < M; ++i )
|
||||
{
|
||||
th[ i ] = std::thread( f, i, N );
|
||||
}
|
||||
|
||||
for( int i = 0; i < M; ++i )
|
||||
{
|
||||
th[ i ].join();
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ( count, N * M );
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2023 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/unordered/detail/foa/rw_spinlock.hpp>
|
||||
#include <boost/compat/shared_lock.hpp>
|
||||
#include <mutex>
|
||||
|
||||
using boost::unordered::detail::foa::rw_spinlock;
|
||||
|
||||
static rw_spinlock sp;
|
||||
static rw_spinlock sp2;
|
||||
|
||||
int main()
|
||||
{
|
||||
sp.lock();
|
||||
sp2.lock_shared();
|
||||
sp2.lock_shared();
|
||||
|
||||
sp.unlock();
|
||||
sp2.unlock_shared();
|
||||
sp2.unlock_shared();
|
||||
|
||||
{
|
||||
std::lock_guard<rw_spinlock> lock( sp );
|
||||
boost::compat::shared_lock<rw_spinlock> lock2( sp2 );
|
||||
boost::compat::shared_lock<rw_spinlock> lock3( sp2 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright 2023 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/unordered/detail/foa/rw_spinlock.hpp>
|
||||
#include <boost/compat/shared_lock.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <mutex>
|
||||
|
||||
using boost::unordered::detail::foa::rw_spinlock;
|
||||
|
||||
static rw_spinlock sp;
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
BOOST_TEST( sp.try_lock_shared() );
|
||||
BOOST_TEST( sp.try_lock_shared() );
|
||||
sp.unlock_shared();
|
||||
sp.unlock_shared();
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_TEST( sp.try_lock() );
|
||||
BOOST_TEST( !sp.try_lock_shared() );
|
||||
sp.unlock();
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<rw_spinlock> lock( sp );
|
||||
BOOST_TEST( !sp.try_lock_shared() );
|
||||
}
|
||||
|
||||
{
|
||||
boost::compat::shared_lock<rw_spinlock> lock( sp );
|
||||
BOOST_TEST( !sp.try_lock() );
|
||||
BOOST_TEST( sp.try_lock_shared() );
|
||||
sp.unlock_shared();
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright 2023 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/unordered/detail/foa/rw_spinlock.hpp>
|
||||
#include <boost/compat/shared_lock.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <cstdio>
|
||||
|
||||
using boost::unordered::detail::foa::rw_spinlock;
|
||||
|
||||
static int count = 0;
|
||||
static rw_spinlock sp;
|
||||
|
||||
void f( int k, int n )
|
||||
{
|
||||
std::printf( "Thread %d started.\n", k );
|
||||
|
||||
int i = 0;
|
||||
|
||||
for( ;; ++i )
|
||||
{
|
||||
{
|
||||
boost::compat::shared_lock<rw_spinlock> lock( sp );
|
||||
if( count >= n ) break;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<rw_spinlock> lock( sp );
|
||||
if( count >= n ) break;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
std::printf( "Thread %d finished (%i iterations).\n", k, i );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int const N = 1000000; // total iterations
|
||||
int const M = 8; // threads
|
||||
|
||||
std::thread th[ M ];
|
||||
|
||||
for( int i = 0; i < M; ++i )
|
||||
{
|
||||
th[ i ] = std::thread( f, i, N );
|
||||
}
|
||||
|
||||
for( int i = 0; i < M; ++i )
|
||||
{
|
||||
th[ i ].join();
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ( count, N );
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2023 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/unordered/detail/foa/rw_spinlock.hpp>
|
||||
#include <boost/compat/shared_lock.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <cstdio>
|
||||
|
||||
using boost::unordered::detail::foa::rw_spinlock;
|
||||
|
||||
static int count = 0;
|
||||
static rw_spinlock sp;
|
||||
|
||||
void f( int k, int n )
|
||||
{
|
||||
std::printf( "Thread %d started.\n", k );
|
||||
|
||||
int i = 0;
|
||||
|
||||
for( ;; ++i )
|
||||
{
|
||||
int oldc;
|
||||
|
||||
{
|
||||
boost::compat::shared_lock<rw_spinlock> lock( sp );
|
||||
if( count >= n ) break;
|
||||
oldc = count;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<rw_spinlock> lock( sp );
|
||||
if( count == oldc ) ++count;
|
||||
}
|
||||
}
|
||||
|
||||
std::printf( "Thread %d finished (%i iterations).\n", k, i );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int const N = 1000000; // total iterations
|
||||
int const M = 8; // threads
|
||||
|
||||
std::thread th[ M ];
|
||||
|
||||
for( int i = 0; i < M; ++i )
|
||||
{
|
||||
th[ i ] = std::thread( f, i, N );
|
||||
}
|
||||
|
||||
for( int i = 0; i < M; ++i )
|
||||
{
|
||||
th[ i ].join();
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ( count, N );
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright 2023 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/unordered/detail/foa/rw_spinlock.hpp>
|
||||
#include <boost/compat/shared_lock.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <cstdio>
|
||||
|
||||
using boost::unordered::detail::foa::rw_spinlock;
|
||||
|
||||
static int count = 0;
|
||||
static rw_spinlock sp;
|
||||
|
||||
void f( int k, int m, int n )
|
||||
{
|
||||
std::printf( "Thread %d of %d started.\n", k, m );
|
||||
|
||||
for( int i = 0; i < n; ++i )
|
||||
{
|
||||
int oldc;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
{
|
||||
boost::compat::shared_lock<rw_spinlock> lock( sp );
|
||||
oldc = count;
|
||||
}
|
||||
|
||||
if( oldc % m == k ) break;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<rw_spinlock> lock( sp );
|
||||
if( count == oldc ) ++count;
|
||||
}
|
||||
}
|
||||
|
||||
std::printf( "Thread %d of %d finished.\n", k, m );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int const N = 100; // total iterations
|
||||
int const M = 4; // threads
|
||||
|
||||
std::thread th[ M ];
|
||||
|
||||
for( int i = 0; i < M; ++i )
|
||||
{
|
||||
th[ i ] = std::thread( f, i, M, N );
|
||||
}
|
||||
|
||||
for( int i = 0; i < M; ++i )
|
||||
{
|
||||
th[ i ].join();
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ( count, N * M );
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -190,7 +190,7 @@ namespace {
|
||||
map_type x2(vals2.size(), hasher(2), key_equal(1), allocator_type(3));
|
||||
|
||||
std::thread t1, t2, t3;
|
||||
boost::latch l(2);
|
||||
boost::compat::latch l(2);
|
||||
|
||||
std::mutex m;
|
||||
std::condition_variable cv;
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
// Copyright 2023 Joaquin M Lopez Munoz
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/unordered/detail/foa/takes_arg_as_const_reference.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
using boost::unordered::detail::foa::takes_arg_as_const_reference;
|
||||
|
||||
using f1 = void ( const int& );
|
||||
void function2( const int& ) noexcept;
|
||||
using f2 = decltype(function2);
|
||||
using f3 = void ( const int&, char* );
|
||||
using f4 = void ( const int&, ... );
|
||||
using f5 = void ( int& );
|
||||
void function6( int& ) noexcept;
|
||||
using f6 = decltype(function6);
|
||||
using f7 = void ( int&, char* );
|
||||
using f8 = void ( int&, ... );
|
||||
struct f9 { void operator()( const int& ); };
|
||||
struct f10 { void operator()( const int& ) const; };
|
||||
struct f11 { void operator()( const int& ) volatile; };
|
||||
struct f12 { void operator()( const int& ) const volatile; };
|
||||
struct f13 { void operator()( const int& )&; };
|
||||
struct f14 { void operator()( const int& ) const&; };
|
||||
struct f15 { void operator()( const int& ) volatile&; };
|
||||
struct f16 { void operator()( const int& ) const volatile&; };
|
||||
struct f17 { void operator()( const int& )&&; };
|
||||
struct f18 { void operator()( const int& ) const&&; };
|
||||
struct f19 { void operator()( const int& ) volatile&&; };
|
||||
struct f20 { void operator()( const int& ) const volatile&&; };
|
||||
struct f21 { void operator()( const int& ) noexcept; };
|
||||
struct f22 { void operator()( const int& ) const noexcept; };
|
||||
struct f23 { void operator()( const int&, int=0 ); };
|
||||
struct f24 { void operator()( const int&, ... ) noexcept; };
|
||||
struct f25 { void operator()( int& ); };
|
||||
struct f26 { void operator()( int& ) const; };
|
||||
struct f27 { void operator()( int& ) volatile; };
|
||||
struct f28 { void operator()( int& ) const volatile; };
|
||||
struct f29 { void operator()( int& )&; };
|
||||
struct f30 { void operator()( int& ) const&; };
|
||||
struct f31 { void operator()( int& ) volatile&; };
|
||||
struct f32 { void operator()( int& ) const volatile&; };
|
||||
struct f33 { void operator()( int& )&&; };
|
||||
struct f34 { void operator()( int& ) const&&; };
|
||||
struct f35 { void operator()( int& ) volatile&&; };
|
||||
struct f36 { void operator()( int& ) const volatile&&; };
|
||||
struct f37 { void operator()( int& ) noexcept; };
|
||||
struct f38 { void operator()( int& ) const noexcept; };
|
||||
struct f39 { void operator()( int&, int=0 ); };
|
||||
struct f40 { void operator()( int&, ... ) noexcept; };
|
||||
struct f41 { template<typename Arg> void operator()( const Arg& ); };
|
||||
struct f42 { template<typename Arg> void operator()( const Arg& ) const; };
|
||||
struct f43 { template<typename Arg> void operator()( const Arg& ) const noexcept; };
|
||||
struct f44 { template<typename Arg> void operator()( Arg& ); };
|
||||
struct f45 { template<typename Arg> void operator()( Arg& ) const; };
|
||||
struct f46 { template<typename Arg> void operator()( Arg& ) const noexcept; };
|
||||
struct f47 { template<typename Arg> void operator()( Arg ); };
|
||||
struct f48 { template<typename Arg> void operator()( Arg ) const; };
|
||||
struct f49 { template<typename Arg> void operator()( Arg ) const noexcept; };
|
||||
struct f50
|
||||
{
|
||||
void operator()( const int& );
|
||||
void operator()( char* );
|
||||
};
|
||||
struct f51 // expected false negative
|
||||
{
|
||||
void operator()( const int& );
|
||||
template<typename Arg> void operator()( Arg& );
|
||||
};
|
||||
using f52=int; // detection doesn't crash even if requirements violated
|
||||
|
||||
int main()
|
||||
{
|
||||
auto lambda53 = []( const int& ){};
|
||||
using f53=decltype(lambda53);
|
||||
int retrieved=0;
|
||||
auto lambda54 = [&]( const int& x ) mutable { retrieved = x; };
|
||||
using f54=decltype(lambda54);
|
||||
auto lambda55 = []( int& x ){ x = 0; };
|
||||
using f55=decltype(lambda55);
|
||||
auto lambda56 = [&]( int& x ) mutable { retrieved = x; x = 0; };
|
||||
using f56=decltype(lambda56);
|
||||
|
||||
#if !defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||
auto lambda57 = []( const auto& ){};
|
||||
using f57=decltype(lambda57);
|
||||
auto lambda58 = [&]( const auto& x ) mutable { retrieved = x; };
|
||||
using f58=decltype(lambda58);
|
||||
auto lambda59 = []( auto& x ){ x = 0; };
|
||||
using f59=decltype(lambda59);
|
||||
auto lambda60 = [&]( auto& x ) mutable { retrieved = x; x = 0; };
|
||||
using f60=decltype(lambda60);
|
||||
#endif
|
||||
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f1, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f2, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f3, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f4, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f5, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f6, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f7, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f8, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f1*, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f2*, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f3*, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f4*, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f5*, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f6*, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f7*, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f8*, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f1&, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f2&, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f3&, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f4&, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f5&, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f6&, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f7&, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f8&, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f9, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f10, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f11, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f12, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f13&, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f14&, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f15&, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f16&, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f17&&, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f18&&, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f19&&, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f20&&, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f21, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f22, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f23, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f24, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f25, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f26, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f27, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f28, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f29&, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f30&, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f31&, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f32&, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f33&&, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f34&&, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f35&&, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f36&&, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f37, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f38, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f39, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f40, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f41, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f42, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f43, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f44, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f45, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f46, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f47, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f48, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f49, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f50, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f51, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f52, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f53, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f54, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f55, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f56, int>::value ));
|
||||
|
||||
#if !defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f57, int>::value ));
|
||||
BOOST_TEST(( takes_arg_as_const_reference<f58, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f59, int>::value ));
|
||||
BOOST_TEST(( !takes_arg_as_const_reference<f60, int>::value ));
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -520,7 +520,7 @@ namespace {
|
||||
X x;
|
||||
|
||||
std::thread t1, t2;
|
||||
boost::latch l(2);
|
||||
boost::compat::latch l(2);
|
||||
std::vector<std::string> strs(values.size());
|
||||
|
||||
t1 = std::thread([&l, &values, &x, &strs] {
|
||||
|
||||