Compare commits

..

15 Commits

Author SHA1 Message Date
joaquintides e8cd7da67a updated concurrent map benchmark plots 2023-07-18 18:16:48 +02:00
joaquintides d2797abcb7 dropped unnecessary type trimming 2023-07-13 12:26:50 +02:00
joaquintides ffb34fdcde rewritten to appease VS2017 and older 2023-07-13 09:52:59 +02:00
joaquintides 38eca0efc0 refactored takes_arg_as_const_reference.hpp again, fixed tests 2023-07-12 18:35:35 +02:00
joaquintides 4f8a037957 worked around noexcept-type warning 2023-07-11 21:04:02 +02:00
joaquintides 61d92b5847 refactored takes_arg_as_const_reference.hpp 2023-07-11 20:08:03 +02:00
joaquintides 33f4b04f69 worked around VS2015 issue 2023-07-10 19:54:45 +02:00
joaquintides 8b024986da restricted force_evaluation workaround to VS 2023-07-10 18:17:40 +02:00
joaquintides 4948a3a12e simplified force_evaluation 2023-07-10 17:47:42 +02:00
joaquintides 35c265f313 worked around C3517 error in VS2017 and older 2023-07-10 12:07:42 +02:00
joaquintides 15b63cc169 made some lambdas generic (copypaste error) 2023-07-10 10:14:46 +02:00
joaquintides 3de21a474c used shared group access for visitation functions taking its arg as a cref 2023-07-09 20:01:24 +02:00
joaquintides 6a6a3084da worked around noexcept forbidding in function typedefs 2023-07-09 19:32:09 +02:00
joaquintides abd69e859e fixed error with non-local capturing lambdas 2023-07-09 19:10:59 +02:00
joaquintides ff20d71676 added takes_arg_as_const_reference.hpp and tests 2023-07-09 18:42:14 +02:00
9 changed files with 355 additions and 490 deletions
+38 -54
View File
@@ -32,16 +32,6 @@ env:
CODECOV_NAME: Github Actions
jobs:
runner-selection:
# runs-on: ubuntu-latest
runs-on: ${{ github.repository_owner == 'boostorg' && fromJSON('[ "self-hosted", "linux", "x64", "ubuntu-latest-aws" ]') || 'ubuntu-latest' }}
outputs:
labelmatrix: ${{ steps.aws_hosted_runners.outputs.labelmatrix }}
steps:
- name: AWS Hosted Runners
id: aws_hosted_runners
uses: cppalliance/aws-hosted-runners@v1.0.0
posix:
defaults:
run:
@@ -52,55 +42,52 @@ jobs:
matrix:
include:
# 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-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' }
- { 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-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,
compiler: gcc-12, cxxstd: '03,11,14', os: 'ubuntu-22.04', ccache_key: "san1" }
compiler: gcc-12, cxxstd: '03,11,14', os: ubuntu-22.04, ccache_key: "san1" }
- { name: "gcc-12 w/ sanitizers (17,20,2b)", sanitize: yes,
compiler: gcc-12, cxxstd: '17,20,2b', os: 'ubuntu-22.04', ccache_key: "san2" }
compiler: gcc-12, cxxstd: '17,20,2b', os: ubuntu-22.04, ccache_key: "san2" }
- { 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" }
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-12)", cxxstd: '11,14,17,20,2b', os: 'ubuntu-22.04', compiler: gcc-12,
- { 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' }
- { compiler: clang-10, cxxstd: '03,11,14,17,20', os: 'ubuntu-20.04', stdlib: libc++, install: 'clang-10 libc++-10-dev libc++abi-10-dev' }
- { compiler: clang-11, cxxstd: '03,11,14,17,20', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-11 libc++-11-dev libc++abi-11-dev' }
# clang-12 doesn't work on 'ubuntu-22.04', the linker can't find -lunwind for some reason
- { compiler: clang-7, cxxstd: '03,11,14,17', os: ubuntu-20.04, stdlib: libc++, install: 'clang-7 libc++-7-dev libc++abi-7-dev' }
- { compiler: clang-10, cxxstd: '03,11,14,17,20', os: ubuntu-20.04, stdlib: libc++, install: 'clang-10 libc++-10-dev libc++abi-10-dev' }
- { compiler: clang-11, cxxstd: '03,11,14,17,20', os: ubuntu-22.04, stdlib: libc++, install: 'clang-11 libc++-11-dev libc++abi-11-dev' }
# clang-12 doesn't work on ubuntu-22.04, the linker can't find -lunwind for some reason
- { name: "clang-12 w/ sanitizers (03,11,14)", sanitize: yes,
compiler: clang-12, cxxstd: '03,11,14', os: 'ubuntu-20.04', stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san1" }
compiler: clang-12, cxxstd: '03,11,14', os: ubuntu-20.04, stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san1" }
- { 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-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' }
# not using libc++ because of https://github.com/llvm/llvm-project/issues/52771
- { name: "clang-14 w/ sanitizers (03,11,14)", sanitize: yes,
compiler: clang-14, cxxstd: '03,11,14', os: 'ubuntu-22.04', ccache_key: "san1" }
compiler: clang-14, cxxstd: '03,11,14', os: ubuntu-22.04, ccache_key: "san1" }
- { name: "clang-14 w/ sanitizers (17,20,2b)", sanitize: yes,
compiler: clang-14, cxxstd: '17,20,2b', os: 'ubuntu-22.04', ccache_key: "san2" }
compiler: clang-14, cxxstd: '17,20,2b', os: ubuntu-22.04, ccache_key: "san2" }
- { name: "cfoa tsan (clang-14)", 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', 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' }
- { 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, 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' }
- { 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: 360
# posix (gcc-12 w/ sanitizers is taking longer than 210 minutes
# timeout-minutes: 210
needs: [runner-selection]
runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)[matrix.os] }}
timeout-minutes: 210
runs-on: ${{matrix.os}}
container: ${{matrix.container}}
env: {B2_USE_CCACHE: 1}
@@ -244,16 +231,15 @@ jobs:
fail-fast: false
matrix:
include:
- { toolset: msvc-14.0, cxxstd: '14,latest', addrmd: '32,64', os: 'windows-2019', variant: 'debug,release' }
- { toolset: msvc-14.2, cxxstd: '14,17,20,latest', addrmd: '32,64', os: 'windows-2019', variant: 'debug,release' }
- { toolset: msvc-14.3, cxxstd: '14,17,20,latest', addrmd: '32,64', os: 'windows-2022', variant: 'debug,release' }
- { toolset: msvc-14.3, cxxstd: '14', addrmd: '64', os: 'windows-2022', variant: 'debug', defines: '_ALLOW_RTCc_IN_STL', cxxflags: '/RTCc' }
- { toolset: msvc-14.3, cxxstd: '14', addrmd: '32', os: 'windows-2022', variant: 'debug', defines: '_ALLOW_RTCc_IN_STL', cxxflags: '"/RTCc /arch:IA32"' }
- { toolset: clang-win, cxxstd: '14,17,latest', addrmd: '32,64', os: 'windows-2022', variant: 'debug,release' }
- { toolset: gcc, cxxstd: '03,11,14,17,2a', addrmd: '64', os: 'windows-2019', variant: 'debug,release' }
- { toolset: msvc-14.0, cxxstd: '14,latest', addrmd: '32,64', os: windows-2019, variant: 'debug,release' }
- { toolset: msvc-14.2, cxxstd: '14,17,20,latest', addrmd: '32,64', os: windows-2019, variant: 'debug,release' }
- { toolset: msvc-14.3, cxxstd: '14,17,20,latest', addrmd: '32,64', os: windows-2022, variant: 'debug,release' }
- { toolset: msvc-14.3, cxxstd: '14', addrmd: '64', os: windows-2022, variant: 'debug', defines: '_ALLOW_RTCc_IN_STL', cxxflags: '/RTCc' }
- { toolset: msvc-14.3, cxxstd: '14', addrmd: '32', os: windows-2022, variant: 'debug', defines: '_ALLOW_RTCc_IN_STL', cxxflags: '"/RTCc /arch:IA32"' }
- { toolset: clang-win, cxxstd: '14,17,latest', addrmd: '32,64', os: windows-2022, variant: 'debug,release' }
- { toolset: gcc, cxxstd: '03,11,14,17,2a', addrmd: '64', os: windows-2019, variant: 'debug,release' }
needs: [runner-selection]
runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)[matrix.os] }}
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
@@ -310,8 +296,7 @@ jobs:
- { sys: MINGW32, compiler: gcc, cxxstd: '03,11,17,20' }
- { sys: MINGW64, compiler: gcc, cxxstd: '03,11,17,20' }
needs: [runner-selection]
runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)['windows-latest'] }}
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
@@ -365,12 +350,11 @@ jobs:
fail-fast: false
matrix:
include:
- { os: 'ubuntu-20.04', build_shared: ON, build_type: Debug, generator: 'Unix Makefiles' }
- { os: 'windows-2019', build_shared: ON, build_type: Debug, generator: 'Visual Studio 16 2019' }
- { os: ubuntu-20.04, build_shared: ON, build_type: Debug, generator: 'Unix Makefiles' }
- { os: windows-2019, build_shared: ON, build_type: Debug, generator: 'Visual Studio 16 2019' }
timeout-minutes: 120
needs: [runner-selection]
runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)[matrix.os] }}
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
-5
View File
@@ -6,11 +6,6 @@
:github-pr-url: https://github.com/boostorg/unordered/pull
:cpp: C++
== Release 1.84.0
* Added debug mode mechanisms for detecting illegal reentrancies into
a `boost::concurrent_flat_map` from user code.
== Release 1.83.0 - Major update
* Added `boost::concurrent_flat_map`, a fast, thread-safe hashmap based on open addressing.
@@ -1,138 +0,0 @@
/* 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_ANNOTATED_MUTEX_HPP
#define BOOST_UNORDERED_DETAIL_FOA_ANNOTATED_MUTEX_HPP
#include <boost/config.hpp>
#include <utility>
namespace boost{
namespace unordered{
namespace detail{
namespace foa{
/* reference: https://clang.llvm.org/docs/ThreadSafetyAnalysis.htm */
#if defined(BOOST_CLANG)&&!defined(SWIG)
#define BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(x) __attribute__((x))
#else
#define BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(x)
#endif
#define BOOST_UNORDERED_CAPABILITY(x) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(capability(x))
#define BOOST_UNORDERED_SCOPED_CAPABILITY \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(scoped_lockable)
#define BOOST_UNORDERED_GUARDED_BY(x) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(guarded_by(x))
#define BOOST_UNORDERED_PT_GUARDED_BY(x) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(pt_guarded_by(x))
#define BOOST_UNORDERED_ACQUIRED_BEFORE(...) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(acquired_before(__VA_ARGS__))
#define BOOST_UNORDERED_ACQUIRED_AFTER(...) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(acquired_after(__VA_ARGS__))
#define BOOST_UNORDERED_REQUIRES(...) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(requires_capability(__VA_ARGS__))
#define BOOST_UNORDERED_REQUIRES_SHARED(...) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(requires_shared_capability(__VA_ARGS__))
#define BOOST_UNORDERED_ACQUIRE(...) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(acquire_capability(__VA_ARGS__))
#define BOOST_UNORDERED_ACQUIRE_SHARED(...) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(acquire_shared_capability(__VA_ARGS__))
#define BOOST_UNORDERED_RELEASE(...) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(release_capability(__VA_ARGS__))
#define BOOST_UNORDERED_RELEASE_SHARED(...) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(release_shared_capability(__VA_ARGS__))
#define BOOST_UNORDERED_RELEASE_GENERIC(...) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(release_generic_capability(__VA_ARGS__))
#define BOOST_UNORDERED_TRY_ACQUIRE(...) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(try_acquire_capability(__VA_ARGS__))
#define BOOST_UNORDERED_TRY_ACQUIRE_SHARED(...) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR( \
try_acquire_shared_capability(__VA_ARGS__))
#define BOOST_UNORDERED_EXCLUDES(...) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(locks_excluded(__VA_ARGS__))
#define BOOST_UNORDERED_ASSERT_CAPABILITY(x) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(assert_capability(x))
#define BOOST_UNORDERED_ASSERT_SHARED_CAPABILITY(x) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(assert_shared_capability(x))
#define BOOST_UNORDERED_RETURN_CAPABILITY(x) \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(lock_returned(x))
#define BOOST_UNORDERED_NO_THREAD_SAFETY_ANALYSIS \
BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(no_thread_safety_analysis)
template<typename Mutex>
struct BOOST_UNORDERED_CAPABILITY("mutex") annotated_mutex:Mutex
{
using super=Mutex;
using super::super;
void lock() noexcept(noexcept(super::lock()))
BOOST_UNORDERED_ACQUIRE()
{
super::lock();
}
bool try_lock() noexcept(noexcept(super::try_lock()))
BOOST_UNORDERED_TRY_ACQUIRE(true)
{
return super::try_lock();
}
void unlock() noexcept(noexcept(super::unlock()))
BOOST_UNORDERED_RELEASE()
{
super::unlock();
}
void lock_shared() noexcept(noexcept(super::lock_shared()))
BOOST_UNORDERED_ACQUIRE_SHARED()
{
super::lock_shared();
}
bool try_lock_shared() noexcept(noexcept(super::try_lock_shared()))
BOOST_UNORDERED_TRY_ACQUIRE_SHARED(true)
{
return super::try_lock();
}
void unlock_shared() noexcept(noexcept(super::unlock_shared()))
BOOST_UNORDERED_RELEASE_SHARED()
{
super::unlock_shared();
}
};
} /* namespace foa */
} /* namespace detail */
} /* namespace unordered */
} /* namespace boost */
#endif
@@ -17,12 +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/annotated_mutex.hpp>
#include <boost/unordered/detail/foa/core.hpp>
#include <boost/unordered/detail/foa/reentrancy_check.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>
@@ -109,10 +110,8 @@ public:
return mutexes[pos];
}
void lock()noexcept BOOST_UNORDERED_NO_THREAD_SAFETY_ANALYSIS
{for(std::size_t n=0;n<N;)mutexes[n++].lock();}
void unlock()noexcept BOOST_UNORDERED_NO_THREAD_SAFETY_ANALYSIS
{for(auto n=N;n>0;)mutexes[--n].unlock();}
void lock()noexcept{for(std::size_t n=0;n<N;)mutexes[n++].lock();}
void unlock()noexcept{for(auto n=N;n>0;)mutexes[--n].unlock();}
private:
cache_aligned_array<Mutex,N> mutexes;
@@ -130,10 +129,8 @@ public:
/* not used but VS in pre-C++17 mode needs to see it for RVO */
shared_lock(const shared_lock&);
void lock() BOOST_UNORDERED_NO_THREAD_SAFETY_ANALYSIS
{BOOST_ASSERT(!owns);m.lock_shared();owns=true;}
void unlock() BOOST_UNORDERED_NO_THREAD_SAFETY_ANALYSIS
{BOOST_ASSERT(owns);m.unlock_shared();owns=false;}
void lock(){BOOST_ASSERT(!owns);m.lock_shared();owns=true;}
void unlock(){BOOST_ASSERT(owns);m.unlock_shared();owns=false;}
private:
Mutex &m;
@@ -217,7 +214,7 @@ struct atomic_integral
struct group_access
{
using mutex_type=annotated_mutex<rw_spinlock>;
using mutex_type=rw_spinlock;
using shared_lock_guard=shared_lock<mutex_type>;
using exclusive_lock_guard=lock_guard<mutex_type>;
using insert_counter_type=std::atomic<boost::uint32_t>;
@@ -491,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>
@@ -508,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
@@ -526,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));
}
@@ -588,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)...);
}
@@ -604,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>
@@ -617,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>
@@ -630,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>
@@ -646,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>
@@ -661,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>
@@ -689,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;
}
@@ -705,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;
}
@@ -722,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);
}
});
@@ -841,11 +838,11 @@ public:
}
private:
using mutex_type=annotated_mutex<rw_spinlock>;
using multimutex_type=annotated_mutex<multimutex<mutex_type,128>>; // TODO: adapt 128 to the machine
using shared_lock_guard=reentrancy_checked<shared_lock<mutex_type>>;
using exclusive_lock_guard=reentrancy_checked<lock_guard<multimutex_type>>;
using exclusive_bilock_guard=reentrancy_bichecked<scoped_bilock<multimutex_type>>;
using mutex_type=rw_spinlock;
using multimutex_type=multimutex<mutex_type,128>; // TODO: adapt 128 to the machine
using shared_lock_guard=shared_lock<mutex_type>;
using exclusive_lock_guard=lock_guard<multimutex_type>;
using exclusive_bilock_guard=scoped_bilock<multimutex_type>;
using group_shared_lock_guard=typename group_access::shared_lock_guard;
using group_exclusive_lock_guard=typename group_access::exclusive_lock_guard;
using group_insert_counter_type=typename group_access::insert_counter_type;
@@ -865,18 +862,18 @@ private:
{
thread_local auto id=(++thread_counter)%mutexes.size();
return shared_lock_guard{this,mutexes[id]};
return shared_lock_guard{mutexes[id]};
}
inline exclusive_lock_guard exclusive_access()const
{
return exclusive_lock_guard{this,mutexes};
return exclusive_lock_guard{mutexes};
}
static inline exclusive_bilock_guard exclusive_access(
const concurrent_table& x,const concurrent_table& y)
{
return {&x,&y,x.mutexes,y.mutexes};
return {x.mutexes,y.mutexes};
}
template<typename Hash2,typename Pred2>
@@ -884,7 +881,7 @@ private:
const concurrent_table& x,
const concurrent_table<TypePolicy,Hash2,Pred2,Allocator>& y)
{
return {&x,&y,x.mutexes,y.mutexes};
return {x.mutexes,y.mutexes};
}
/* Tag-dispatched shared/exclusive group access */
@@ -892,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();
@@ -1,181 +0,0 @@
/* 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_REENTRANCY_CHECK_HPP
#define BOOST_UNORDERED_DETAIL_FOA_REENTRANCY_CHECK_HPP
#include <boost/assert.hpp>
#include <boost/unordered/detail/foa/annotated_mutex.hpp>
#include <utility>
#if !defined(BOOST_UNORDERED_DISABLE_REENTRANCY_CHECK)&& \
!defined(BOOST_ASSERT_IS_VOID)
#define BOOST_UNORDERED_REENTRANCY_CHECK
#endif
namespace boost{
namespace unordered{
namespace detail{
namespace foa{
#if defined(BOOST_UNORDERED_REENTRANCY_CHECK)
class entry_trace
{
public:
entry_trace(const void* px_):px{px_}
{
if(px){
BOOST_ASSERT_MSG(!find(px),"reentrancy not allowed");
header()=this;
}
}
/* not used but VS in pre-C++17 mode needs to see it for RVO */
entry_trace(const entry_trace&);
~entry_trace(){clear();}
void clear()
{
if(px){
header()=next;
px=nullptr;
}
}
private:
static entry_trace*& header()
{
thread_local entry_trace *pe=nullptr;
return pe;
}
static bool find(const void* px)
{
for(auto pe=header();pe;pe=pe->next){
if(pe->px==px)return true;
}
return false;
}
const void *px;
entry_trace *next=header();
};
template<typename>
struct reentrancy_checked;
template<template <typename> class LockGuard,typename Mutex>
struct BOOST_UNORDERED_SCOPED_CAPABILITY reentrancy_checked<LockGuard<Mutex>>
{
reentrancy_checked(const void* px,Mutex& m_)
BOOST_UNORDERED_ACQUIRE(m_):
tr{px},lck{m_},m{m_}{}
reentrancy_checked(const reentrancy_checked& x) BOOST_UNORDERED_ACQUIRE(x.m);
~reentrancy_checked() BOOST_UNORDERED_RELEASE() = default;
void unlock() BOOST_UNORDERED_RELEASE()
{
lck.unlock();
tr.clear();
}
entry_trace tr;
LockGuard<Mutex> lck;
Mutex& m;
};
template<typename>
struct reentrancy_bichecked;
template<template <typename> class LockGuard,typename Mutex>
struct BOOST_UNORDERED_SCOPED_CAPABILITY reentrancy_bichecked<LockGuard<Mutex>>
{
template<typename Mutex1, typename Mutex2>
reentrancy_bichecked(const void* px,const void* py,Mutex1& m1_,Mutex2& m2_)
BOOST_UNORDERED_ACQUIRE(m1_,m2_):
tr1{px},tr2{py!=px?py:nullptr},lck{m1_,m2_},m1{m1_},m2{m2_}{}
reentrancy_bichecked(const reentrancy_bichecked& x)
BOOST_UNORDERED_ACQUIRE(x.m1,x.m2);
~reentrancy_bichecked() BOOST_UNORDERED_RELEASE() = default;
void unlock() BOOST_UNORDERED_RELEASE()
{
lck.unlock();
tr2.clear();
tr1.clear();
}
entry_trace tr1,tr2;
LockGuard<Mutex> lck;
Mutex &m1,&m2;
};
#else
template<typename>
struct reentrancy_checked;
template<template <typename> class LockGuard,typename Mutex>
struct BOOST_UNORDERED_SCOPED_CAPABILITY reentrancy_checked<LockGuard<Mutex>>
{
reentrancy_checked(const void*,Mutex& m_)
BOOST_UNORDERED_ACQUIRE(m_):
lck{m_},m{m_}{}
reentrancy_checked(const reentrancy_checked& x) BOOST_UNORDERED_ACQUIRE(x.m);
~reentrancy_checked() BOOST_UNORDERED_RELEASE() = default;
void unlock() BOOST_UNORDERED_RELEASE()
{
lck.unlock();
}
LockGuard<Mutex> lck;
Mutex& m;
};
template<typename>
struct reentrancy_bichecked;
template<template <typename> class LockGuard,typename Mutex>
struct BOOST_UNORDERED_SCOPED_CAPABILITY reentrancy_bichecked<LockGuard<Mutex>>
{
template<typename Mutex1, typename Mutex2>
reentrancy_bichecked(const void*,const void*,Mutex1& m1_,Mutex2& m2_)
BOOST_UNORDERED_ACQUIRE(m1_,m2_):
lck{m1_,m2_},m1{m1_},m2{m2_}{}
reentrancy_bichecked(const reentrancy_bichecked& x)
BOOST_UNORDERED_ACQUIRE(x.m1,x.m2);
~reentrancy_bichecked() BOOST_UNORDERED_RELEASE() = default;
void unlock() BOOST_UNORDERED_RELEASE()
{
lck.unlock();
}
LockGuard<Mutex> lck;
Mutex &m1,&m2;
};
#endif
} /* namespace foa */
} /* namespace detail */
} /* namespace unordered */
} /* namespace boost */
#endif
@@ -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
+1 -1
View File
@@ -202,7 +202,7 @@ local CFOA_TESTS =
rw_spinlock_test6
rw_spinlock_test7
rw_spinlock_test8
reentrancy_check_test
takes_arg_as_cref_tests
;
for local test in $(CFOA_TESTS)
-79
View File
@@ -1,79 +0,0 @@
// Copyright 2023 Joaquin M Lopez Munoz
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <cstdlib>
#define BOOST_ENABLE_ASSERT_HANDLER
static bool reentrancy_detected = false;
namespace boost {
// Caveat lector: a proper handler shouldn't throw as it may be executed
// within a noexcept function.
void assertion_failed_msg(
char const*, char const*, char const*, char const*, long)
{
reentrancy_detected = true;
throw 0;
}
void assertion_failed(char const*, char const*, char const*, long) // LCOV_EXCL_START
{
std::abort();
} // LCOV_EXCL_STOP
}
#include <boost/unordered/concurrent_flat_map.hpp>
#include <boost/core/lightweight_test.hpp>
template<typename F>
void detect_reentrancy(F f)
{
reentrancy_detected = false;
try {
f();
}
catch(int) {}
BOOST_TEST(reentrancy_detected);
}
int main()
{
using map = boost::concurrent_flat_map<int, int>;
using value_type = typename map::value_type;
map m1, m2;
m1.emplace(0, 0);
m2.emplace(1, 0);
detect_reentrancy([&] {
m1.visit_all([&](value_type&) { (void)m1.contains(0); });
}); // LCOV_EXCL_LINE
detect_reentrancy([&] {
m1.visit_all([&](value_type&) { m1.rehash(0); });
}); // LCOV_EXCL_LINE
detect_reentrancy([&] {
m1.visit_all([&](value_type&) {
m2.visit_all([&](value_type&) {
m1=m2;
}); // LCOV_EXCL_START
});
});
// LCOV_EXCL_STOP
detect_reentrancy([&] {
m1.visit_all([&](value_type&) {
m2.visit_all([&](value_type&) {
m2=m1;
}); // LCOV_EXCL_START
});
});
// LCOV_EXCL_STOP
return boost::report_errors();
}
+178
View File
@@ -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();
}