diff --git a/include/boost/unordered/detail/foa/takes_arg_as_const_reference.hpp b/include/boost/unordered/detail/foa/takes_arg_as_const_reference.hpp new file mode 100644 index 00000000..f8f446da --- /dev/null +++ b/include/boost/unordered/detail/foa/takes_arg_as_const_reference.hpp @@ -0,0 +1,171 @@ +/* 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 +#include + +/* VS warns when a pp function is directly called with an empty arg */ +#define BOOST_UNORDERED_EMPTY_PP_ARG() + +namespace boost{ +namespace unordered{ +namespace detail{ +namespace foa{ + +template +struct remove_noexcept{using type=Sig;}; + +template +using remove_noexcept_t=typename remove_noexcept::type; + +template +struct remove_noexcept + {using type=R(Args...);}; + +template +struct remove_noexcept + {using type=R(Args...,...);}; + +template +struct remove_noexcept + {using type=R(&)(Args...);}; + +template +struct remove_noexcept + {using type=R(&)(Args...,...);}; + +template +struct remove_noexcept + {using type=R(Args...);}; + +template +struct remove_noexcept + {using type=R(Args...,...);}; + +#define BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(qualifier) \ +template \ +struct remove_noexcept \ + {using type=R(C::*)(Args...)qualifier;}; \ + \ +template \ +struct remove_noexcept \ + {using type=R(C::*)(Args...,...)qualifier;}; + +BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(BOOST_UNORDERED_EMPTY_PP_ARG()) +BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(const) +BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(volatile) +BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(const volatile) +BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(&) +BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(const&) +BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(volatile&) +BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(const volatile&) +BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(&&) +BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(const&&) +BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(volatile&&) +BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(const volatile&&) + +#undef BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN + +template +struct has_const_reference_arg:std::false_type{}; + +template +struct has_const_reference_arg< + R(const Arg&,Args...) +>:std::true_type{}; + +template +struct has_const_reference_arg< + R(const Arg&,Args...,...) +>:std::true_type{}; + +template +struct has_const_reference_arg< + R(&)(const Arg&,Args...) +>:std::true_type{}; + +template +struct has_const_reference_arg< + R(&)(const Arg&,Args...,...) +>:std::true_type{}; + +template +struct has_const_reference_arg< + R(*)(const Arg&,Args...) +>:std::true_type{}; + +template +struct has_const_reference_arg< + R(*)(const Arg&,Args...,...) +>:std::true_type{}; + +#define BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(qualifier) \ +template \ +struct has_const_reference_arg< \ + R(C::*)(const Arg&,Args...)qualifier \ +>:std::true_type{}; \ + \ +template \ +struct has_const_reference_arg< \ + R(C::*)(const Arg&,Args...,...)qualifier \ +>:std::true_type{}; + +BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(BOOST_UNORDERED_EMPTY_PP_ARG()) +BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(const) +BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(volatile) +BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(const volatile) +BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(&) +BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(const&) +BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(volatile&) +BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(const volatile&) +BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(&&) +BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(const&&) +BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(volatile&&) +BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(const volatile&&) + +#undef BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN + +/* 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 +struct takes_arg_as_const_reference: + has_const_reference_arg>{}; + +template +struct takes_arg_as_const_reference< + F,Arg, + boost::void_t)> +>: +takes_arg_as_const_reference< + decltype(&F::template operator()),Arg +>{}; + +template +struct takes_arg_as_const_reference< + F,Arg, + boost::void_t +>: +takes_arg_as_const_reference< + decltype(&F::operator()),Arg +>{}; + + +} /* namespace foa */ +} /* namespace detail */ +} /* namespace unordered */ +} /* namespace boost */ + +#undef BOOST_UNORDERED_EMPTY_PP_ARG + +#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e25f1083..98608c58 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -202,6 +202,7 @@ local CFOA_TESTS = rw_spinlock_test6 rw_spinlock_test7 rw_spinlock_test8 + takes_arg_as_cref_tests ; for local test in $(CFOA_TESTS) diff --git a/test/cfoa/takes_arg_as_cref_tests.cpp b/test/cfoa/takes_arg_as_cref_tests.cpp new file mode 100644 index 00000000..5840ce0f --- /dev/null +++ b/test/cfoa/takes_arg_as_cref_tests.cpp @@ -0,0 +1,177 @@ +// Copyright 2023 Joaquin M Lopez Munoz +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +using boost::unordered::detail::foa::takes_arg_as_const_reference; + +using f1 = void ( const int& ); +using f2 = void ( const int& ) noexcept; +using f3 = void ( const int&, char* ); +using f4 = void ( const int&, ... ); +using f5 = void ( int& ); +using f6 = void ( int& ) noexcept; +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 void operator()( const Arg& ); }; +struct f42 { template void operator()( const Arg& ) const; }; +struct f43 { template void operator()( const Arg& ) const noexcept; }; +struct f44 { template void operator()( Arg& ); }; +struct f45 { template void operator()( Arg& ) const; }; +struct f46 { template void operator()( Arg& ) const noexcept; }; +struct f47 { template void operator()( Arg ); }; +struct f48 { template void operator()( Arg ) const; }; +struct f49 { template void operator()( Arg ) const noexcept; }; +struct f50 // expected false negative +{ + void operator()( const int& ); + template void operator()( Arg& ); +}; +struct f51 // expected false negative +{ + void operator()( const int& ); + void operator()( char* ); +}; +auto lambda52 = []( const int& ){}; +using f52=decltype(lambda52); +int retrieved=0; +auto lambda53 = [&]( const int& x ) mutable { retrieved = x; }; +using f53=decltype(lambda53); +auto lambda54 = []( int& ){}; +using f54=decltype(lambda54); +auto lambda55 = [&]( int& x ) mutable { retrieved = x; }; +using f55=decltype(lambda55); + +#if !defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) +auto lambda56 = []( const auto& ){}; +using f56=decltype(lambda56); +auto lambda57 = [&]( const int& x ) mutable { retrieved = x; }; +using f57=decltype(lambda57); +auto lambda58 = []( int& ){}; +using f58=decltype(lambda58); +auto lambda59 = [&]( int& x ) mutable { retrieved = x; }; +using f59=decltype(lambda59); +#endif + +using f60=void; // detection doesn't crash even if requirements violated + +int main() +{ + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + +#if !defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( !takes_arg_as_const_reference::value )); +#endif + + BOOST_TEST(( !takes_arg_as_const_reference::value )); + + return boost::report_errors(); +}