From d3bf8ef262cc3814a382cfcfcfbffa61ca6812dd Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sat, 8 Jun 2024 17:32:42 -0700 Subject: [PATCH 01/13] [libc++] P0792R14: 'function_ref' --- libcxx/include/CMakeLists.txt | 4 + libcxx/include/__functional/function_ref.h | 46 +++++ .../__functional/function_ref_common.h | 72 +++++++ .../include/__functional/function_ref_impl.h | 181 ++++++++++++++++++ libcxx/include/__utility/nontype.h | 34 ++++ libcxx/include/functional | 1 + libcxx/include/module.modulemap | 2 + libcxx/include/utility | 10 + .../func.wrap.ref/call/const.pass.cpp | 124 ++++++++++++ .../call/const_noexcept.pass.cpp | 124 ++++++++++++ .../func.wrap.ref/call/default.pass.cpp | 119 ++++++++++++ .../func.wrap.ref/call/noexcept.pass.cpp | 119 ++++++++++++ 12 files changed, 836 insertions(+) create mode 100644 libcxx/include/__functional/function_ref.h create mode 100644 libcxx/include/__functional/function_ref_common.h create mode 100644 libcxx/include/__functional/function_ref_impl.h create mode 100644 libcxx/include/__utility/nontype.h create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const.pass.cpp create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const_noexcept.pass.cpp create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/default.pass.cpp create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/noexcept.pass.cpp diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index cfe1f44777bca..6dd28b79117af 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -393,6 +393,9 @@ set(files __functional/compose.h __functional/default_searcher.h __functional/function.h + __functional/function_ref_common.h + __functional/function_ref_impl.h + __functional/function_ref.h __functional/hash.h __functional/identity.h __functional/invoke.h @@ -855,6 +858,7 @@ set(files __utility/is_valid_range.h __utility/move.h __utility/no_destroy.h + __utility/nontype.h __utility/pair.h __utility/piecewise_construct.h __utility/priority_tag.h diff --git a/libcxx/include/__functional/function_ref.h b/libcxx/include/__functional/function_ref.h new file mode 100644 index 0000000000000..01cc22a64018e --- /dev/null +++ b/libcxx/include/__functional/function_ref.h @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_FUNCTION_REF_H +#define _LIBCPP___FUNCTIONAL_FUNCTION_REF_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +// NOLINTBEGIN(readability-duplicate-include) + +#define _LIBCPP_FUNCTION_REF_CV +#define _LIBCPP_FUNCTION_REF_NOEXCEPT false +#include <__functional/function_ref_impl.h> +#undef _LIBCPP_FUNCTION_REF_CV +#undef _LIBCPP_FUNCTION_REF_NOEXCEPT + +#define _LIBCPP_FUNCTION_REF_CV +#define _LIBCPP_FUNCTION_REF_NOEXCEPT true +#include <__functional/function_ref_impl.h> +#undef _LIBCPP_FUNCTION_REF_CV +#undef _LIBCPP_FUNCTION_REF_NOEXCEPT + +#define _LIBCPP_FUNCTION_REF_CV const +#define _LIBCPP_FUNCTION_REF_NOEXCEPT false +#include <__functional/function_ref_impl.h> +#undef _LIBCPP_FUNCTION_REF_CV +#undef _LIBCPP_FUNCTION_REF_NOEXCEPT + +#define _LIBCPP_FUNCTION_REF_CV const +#define _LIBCPP_FUNCTION_REF_NOEXCEPT true +#include <__functional/function_ref_impl.h> +#undef _LIBCPP_FUNCTION_REF_CV +#undef _LIBCPP_FUNCTION_REF_NOEXCEPT + +// NOLINTEND(readability-duplicate-include) + +#endif // _LIBCPP___FUNCTIONAL_FUNCTION_REF_H diff --git a/libcxx/include/__functional/function_ref_common.h b/libcxx/include/__functional/function_ref_common.h new file mode 100644 index 0000000000000..f7d5575ebaffd --- /dev/null +++ b/libcxx/include/__functional/function_ref_common.h @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_FUNCTION_REF_COMMON_H +#define _LIBCPP___FUNCTIONAL_FUNCTION_REF_COMMON_H + +#include <__config> +#include <__type_traits/invoke.h> +#include <__type_traits/is_object.h> +#include <__type_traits/remove_pointer.h> +#include <__utility/nontype.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 26 + +template +class function_ref; + +template +inline constexpr bool __is_function_ref = false; + +template +inline constexpr bool __is_function_ref> = true; + +template +struct __function_ref_bind; + +template +struct __function_ref_bind<_Rp (*)(_Gp, _ArgTypes...), _Tp> { + using type = _Rp(_ArgTypes...); +}; + +template +struct __function_ref_bind<_Rp (*)(_Gp, _ArgTypes...) noexcept, _Tp> { + using type = _Rp(_ArgTypes...) noexcept; +}; + +template + requires is_object_v<_Mp> +struct __function_ref_bind<_Mp _Gp::*, _Tp> { + using type = invoke_result_t<_Mp _Gp::*, _Tp&>; +}; + +template +using __function_ref_bind_t = __function_ref_bind<_Fp, _Tp>::type; + +template + requires is_function_v<_Fp> +function_ref(_Fp*) -> function_ref<_Fp>; + +template + requires is_function_v> +function_ref(nontype_t<_Fn>) -> function_ref>; + +template +function_ref(nontype_t<_Fn>, _Tp&&) -> function_ref<__function_ref_bind_t>; + +#endif // _LIBCPP_STD_VER >= 26 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_FUNCTION_REF_COMMON_H diff --git a/libcxx/include/__functional/function_ref_impl.h b/libcxx/include/__functional/function_ref_impl.h new file mode 100644 index 0000000000000..4e1cd13a02ae2 --- /dev/null +++ b/libcxx/include/__functional/function_ref_impl.h @@ -0,0 +1,181 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include <__assert> +#include <__config> +#include <__functional/function_ref_common.h> +#include <__functional/invoke.h> +#include <__memory/addressof.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_const.h> +#include <__type_traits/is_function.h> +#include <__type_traits/is_member_pointer.h> +#include <__type_traits/is_object.h> +#include <__type_traits/is_pointer.h> +#include <__type_traits/is_void.h> +#include <__type_traits/remove_cvref.h> +#include <__type_traits/remove_pointer.h> +#include <__type_traits/remove_reference.h> +#include <__utility/forward.h> +#include <__utility/nontype.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 26 + +template +class function_ref; + +template +class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT)> { +private: +# if _LIBCPP_FUNCTION_REF_NOEXCEPT == true + template + static constexpr bool __is_invocable_using = is_nothrow_invocable_r_v<_Rp, _Tp..., _ArgTypes...>; +# else + template + static constexpr bool __is_invocable_using = is_invocable_r_v<_Rp, _Tp..., _ArgTypes...>; +# endif + + union __storage_t { + void* __obj_ptr; + void const* __obj_const_ptr; + void (*__fn_ptr)(); + + constexpr explicit __storage_t() noexcept : __obj_ptr(nullptr) {}; + + template + constexpr explicit __storage_t(_Tp* __ptr) noexcept { + if constexpr (is_object_v<_Tp>) { + if constexpr (is_const_v<_Tp>) { + __obj_const_ptr = __ptr; + } else { + __obj_ptr = __ptr; + } + } else { + static_assert(is_function_v<_Tp>); + __fn_ptr = reinterpret_cast(__ptr); + } + } + } __storage_; + + template + _LIBCPP_HIDE_FROM_ABI static constexpr auto __get(__storage_t __storage) { + if constexpr (is_object_v<_Tp>) { + if constexpr (is_const_v<_Tp>) { + return static_cast<_Tp*>(__storage.__obj_const_ptr); + } else { + return static_cast<_Tp*>(__storage.__obj_ptr); + } + } else { + static_assert(is_function_v<_Tp>); + return reinterpret_cast<_Tp*>(__storage.__fn_ptr); + } + } + + using __vtable_call_t = _Rp (*)(__storage_t, _ArgTypes&&...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT); + __vtable_call_t __vtable_call_; + +public: + template + requires is_function_v<_Fp> && __is_invocable_using<_Fp> + _LIBCPP_HIDE_FROM_ABI function_ref(_Fp* __fn_ptr) noexcept + : __storage_(__fn_ptr), + __vtable_call_( + [](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { + return __get<_Fp>(__storage)(std::forward<_ArgTypes>(__args)...); + }) { + _LIBCPP_ASSERT_UNCATEGORIZED(__fn_ptr != nullptr, "the function pointer should not be a nullptr"); + } + + template > + requires(!__is_function_ref> && !is_member_pointer_v<_Tp> && + __is_invocable_using<_LIBCPP_FUNCTION_REF_CV _Tp&>) + _LIBCPP_HIDE_FROM_ABI function_ref(_Fp&& __obj) noexcept + : __storage_(std::addressof(__obj)), + __vtable_call_( + [](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { + _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage); + return __obj(std::forward<_ArgTypes>(__args)...); + }) {} + + template + requires __is_invocable_using + constexpr function_ref(nontype_t<_Fn>) noexcept + : __vtable_call_([](__storage_t, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { + return std::invoke_r<_Rp>(_Fn, std::forward<_ArgTypes>(__args)...); + }) { + if constexpr (is_pointer_v || is_member_pointer_v) { + static_assert(_Fn != nullptr, "the function pointer should not be a nullptr"); + } + } + + template > + requires(!is_rvalue_reference_v<_Up &&>) && __is_invocable_using + constexpr function_ref(nontype_t<_Fn>, _Up&& __obj) noexcept + : __storage_(std::addressof(__obj)), + __vtable_call_( + [](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { + _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage); + return std::invoke_r<_Rp>(_Fn, __obj, std::forward<_ArgTypes>(__args)...); + }) { + if constexpr (is_pointer_v || is_member_pointer_v) { + static_assert(_Fn != nullptr, "the function pointer should not be a nullptr"); + } + } + + template + requires __is_invocable_using + constexpr function_ref(nontype_t<_Fn>, _LIBCPP_FUNCTION_REF_CV _Tp* __obj_ptr) noexcept + : __storage_(__obj_ptr), + __vtable_call_( + [](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { + auto __obj = __get<_LIBCPP_FUNCTION_REF_CV _Tp>(__storage); + return std::invoke_r<_Rp>(_Fn, __obj, std::forward<_ArgTypes>(__args)...); + }) { + if constexpr (is_pointer_v || is_member_pointer_v) { + static_assert(_Fn != nullptr, "the function pointer should not be a nullptr"); + } + + if constexpr (is_member_pointer_v) { + _LIBCPP_ASSERT_UNCATEGORIZED(__obj_ptr != nullptr, "the object pointer should not be a nullptr"); + } + } + + constexpr function_ref(const function_ref&) noexcept = default; + + constexpr function_ref& operator=(const function_ref&) noexcept = default; + + template + requires(!__is_function_ref<_Tp>) && (!is_pointer_v<_Tp>) && (!__is_nontype_t<_Tp>) + function_ref& operator=(_Tp) = delete; + + constexpr _Rp operator()(_ArgTypes... __args) const noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) { + return __vtable_call_(__storage_, std::forward<_ArgTypes>(__args)...); + } +}; + +template +struct __function_ref_bind<_Rp (_Gp::*)(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT), + _Tp> { + using type = _Rp(_ArgTypes...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT); +}; + +template +struct __function_ref_bind<_Rp (_Gp::*)(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV & noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT), + _Tp> { + using type = _Rp(_ArgTypes...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT); +}; + +#endif // _LIBCPP_STD_VER >= 26 + +_LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__utility/nontype.h b/libcxx/include/__utility/nontype.h new file mode 100644 index 0000000000000..86893f17e2d96 --- /dev/null +++ b/libcxx/include/__utility/nontype.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___UTILITY_NONTYPE_H +#define _LIBCPP___UTILITY_NONTYPE_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 26 + +template +struct nontype_t { + explicit nontype_t() = default; +}; + +template +inline constexpr nontype_t<_Vp> nontype{}; + +#endif // _LIBCPP_STD_VER >= 26 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___UTILITY_NONTYPE_H diff --git a/libcxx/include/functional b/libcxx/include/functional index 27cf21e1a4c8b..f413e296fab9e 100644 --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -541,6 +541,7 @@ POLICY: For non-variadic implementations, the number of arguments is limited #include <__functional/compose.h> #include <__functional/default_searcher.h> #include <__functional/function.h> +#include <__functional/function_ref.h> #include <__functional/hash.h> #include <__functional/identity.h> #include <__functional/invoke.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 48391b2a12095..5143f3fadfdc2 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1339,6 +1339,7 @@ module std_private_functional_compose [system] { } module std_private_functional_default_searcher [system] { header "__functional/default_searcher.h" } module std_private_functional_function [system] { header "__functional/function.h" } +module std_private_functional_function_ref [system] { header "__functional/function_ref.h" } module std_private_functional_hash [system] { header "__functional/hash.h" export std_cstdint @@ -2073,6 +2074,7 @@ module std_private_utility_move [system] { export std_private_type_traits_remove_reference } module std_private_utility_no_destroy [system] { header "__utility/no_destroy.h" } +module std_private_utility_nontype [system] { header "__utility/nontype.h" } module std_private_utility_pair [system] { header "__utility/pair.h" export std_private_ranges_subrange_fwd diff --git a/libcxx/include/utility b/libcxx/include/utility index 90713da621c5d..07dba7593f2df 100644 --- a/libcxx/include/utility +++ b/libcxx/include/utility @@ -238,6 +238,15 @@ template template inline constexpr in_place_index_t in_place_index{}; +// nontype argument tag +template + struct nontype_t { + explicit nontype_t() = default; + }; +template constexpr nontype_t nontype{}; + +template constexpr nontype_t nontype{}; + // [utility.underlying], to_underlying template constexpr underlying_type_t to_underlying( T value ) noexcept; // C++23 @@ -259,6 +268,7 @@ template #include <__utility/in_place.h> #include <__utility/integer_sequence.h> #include <__utility/move.h> +#include <__utility/nontype.h> #include <__utility/pair.h> #include <__utility/piecewise_construct.h> #include <__utility/priority_tag.h> diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const.pass.cpp new file mode 100644 index 0000000000000..53d7a5922353d --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const.pass.cpp @@ -0,0 +1,124 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 + +#include +#include +#include +#include + +#include "test_macros.h" + +static_assert(std::is_invocable_v&>); +static_assert(std::is_invocable_v>); +static_assert(std::is_invocable_v&&>); +static_assert(std::is_invocable_v const&>); +static_assert(std::is_invocable_v const>); +static_assert(std::is_invocable_v const&&>); + +int fn() { return 42; } + +struct { + int operator()() const { return 42; } +} fn_obj; + +void test() { + // template function_ref(F* f) noexcept; + { + // initialized from a function + std::function_ref fn_ref = fn; + assert(fn_ref() == 42); + } + { + // initialized from a function pointer + std::function_ref fn_ref = &fn; + assert(fn_ref() == 42); + } + + // template constexpr function_ref(F&& f) noexcept; + { + // initialized from a function object + std::function_ref fn_ref = fn_obj; + assert(fn_ref() == 42); + } +} + +struct S { + int data_mem = 42; + + int fn_mem() const { return 42; } +}; + +void test_nontype_t() { + // template constexpr function_ref(nontype_t) noexcept; + { + // initialized from a function through `nontype_t` + std::function_ref fn_ref = std::nontype_t(); + assert(fn_ref() == 42); + } + { + // initialized from a function pointer through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&fn>(); + assert(fn_ref() == 42); + } + { + // initialized from a function object through `nontype_t` + std::function_ref fn_ref = std::nontype_t(); + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to data member through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&S::data_mem>(); + assert(fn_ref(s) == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&S::fn_mem>(); + assert(fn_ref(s) == 42); + } + + // template + // constexpr function_ref(nontype_t, U&& obj) noexcept; + { + S s; + // initialized from a pointer to data member through `nontype_t` and bound to an object through a reference + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), s}; + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` and bound to an object through a reference + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), s}; + assert(fn_ref() == 42); + } + + // template + // constexpr function_ref(nontype_t, cv T* obj) noexcept; + { + S s; + // initialized from a pointer to data member through `nontype_t` and bound to an object through a pointer + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), &s}; + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` and bound to an object through a pointer + static_assert(std::is_same_v); + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), &s}; + assert(fn_ref() == 42); + } +} + +int main(int, char**) { + test(); + test_nontype_t(); + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const_noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const_noexcept.pass.cpp new file mode 100644 index 0000000000000..18d44e4b7ef0b --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const_noexcept.pass.cpp @@ -0,0 +1,124 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 + +#include +#include +#include +#include + +#include "test_macros.h" + +static_assert(std::is_invocable_v&>); +static_assert(std::is_invocable_v>); +static_assert(std::is_invocable_v&&>); +static_assert(std::is_invocable_v const&>); +static_assert(std::is_invocable_v const >); +static_assert(std::is_invocable_v const&&>); + +int fn() noexcept { return 42; } + +struct { + int operator()() const noexcept { return 42; } +} fn_obj; + +void test() { + // template function_ref(F* f) noexcept; + { + // initialized from a function + std::function_ref fn_ref = fn; + assert(fn_ref() == 42); + } + { + // initialized from a function pointer + std::function_ref fn_ref = &fn; + assert(fn_ref() == 42); + } + + // template const noexceptexpr function_ref(F&& f) noexcept; + { + // initialized from a function object + std::function_ref fn_ref = fn_obj; + assert(fn_ref() == 42); + } +} + +struct S { + int data_mem = 42; + + int fn_mem() const noexcept { return 42; } +}; + +void test_nontype_t() { + // template const noexceptexpr function_ref(nontype_t) noexcept; + { + // initialized from a function through `nontype_t` + std::function_ref fn_ref = std::nontype_t(); + assert(fn_ref() == 42); + } + { + // initialized from a function pointer through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&fn>(); + assert(fn_ref() == 42); + } + { + // initialized from a function object through `nontype_t` + std::function_ref fn_ref = std::nontype_t(); + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to data member through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&S::data_mem>(); + assert(fn_ref(s) == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&S::fn_mem>(); + assert(fn_ref(s) == 42); + } + + // template + // const noexceptexpr function_ref(nontype_t, U&& obj) noexcept; + { + S s; + // initialized from a pointer to data member through `nontype_t` and bound to an object through a reference + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), s}; + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` and bound to an object through a reference + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), s}; + assert(fn_ref() == 42); + } + + // template + // const noexceptexpr function_ref(nontype_t, cv T* obj) noexcept; + { + S s; + // initialized from a pointer to data member through `nontype_t` and bound to an object through a pointer + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), &s}; + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` and bound to an object through a pointer + static_assert(std::is_same_v); + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), &s}; + assert(fn_ref() == 42); + } +} + +int main(int, char**) { + test(); + test_nontype_t(); + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/default.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/default.pass.cpp new file mode 100644 index 0000000000000..ebc07a6c3520c --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/default.pass.cpp @@ -0,0 +1,119 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 + +#include +#include +#include +#include + +#include "test_macros.h" + +static_assert(std::is_invocable_v&>); +static_assert(std::is_invocable_v>); +static_assert(std::is_invocable_v&&>); +static_assert(std::is_invocable_v const&>); +static_assert(std::is_invocable_v const>); +static_assert(std::is_invocable_v const&&>); + +int fn() { return 42; } + +struct { + int operator()() { return 42; } +} fn_obj; + +void test() { + // template function_ref(F* f) noexcept; + { + // initialized from a function + std::function_ref fn_ref = fn; + assert(fn_ref() == 42); + } + { + // initialized from a function pointer + std::function_ref fn_ref = &fn; + assert(fn_ref() == 42); + } + + // template constexpr function_ref(F&& f) noexcept; + { + // initialized from a function object + std::function_ref fn_ref = fn_obj; + assert(fn_ref() == 42); + } +} + +struct S { + int data_mem = 42; + + int fn_mem() { return 42; } +}; + +void test_nontype_t() { + // template constexpr function_ref(nontype_t) noexcept; + { + // initialized from a function through `nontype_t` + std::function_ref fn_ref = std::nontype_t(); + assert(fn_ref() == 42); + } + { + // initialized from a function pointer through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&fn>(); + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to data member through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&S::data_mem>(); + assert(fn_ref(s) == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&S::fn_mem>(); + assert(fn_ref(s) == 42); + } + + // template + // constexpr function_ref(nontype_t, U&& obj) noexcept; + { + S s; + // initialized from a pointer to data member through `nontype_t` and bound to an object through a reference + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), s}; + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` and bound to an object through a reference + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), s}; + assert(fn_ref() == 42); + } + + // template + // constexpr function_ref(nontype_t, cv T* obj) noexcept; + { + S s; + // initialized from a pointer to data member through `nontype_t` and bound to an object through a pointer + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), &s}; + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` and bound to an object through a pointer + static_assert(std::is_same_v); + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), &s}; + assert(fn_ref() == 42); + } +} + +int main(int, char**) { + test(); + test_nontype_t(); + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/noexcept.pass.cpp new file mode 100644 index 0000000000000..9b58e677ed6ba --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/noexcept.pass.cpp @@ -0,0 +1,119 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 + +#include +#include +#include +#include + +#include "test_macros.h" + +static_assert(std::is_invocable_v&>); +static_assert(std::is_invocable_v>); +static_assert(std::is_invocable_v&&>); +static_assert(std::is_invocable_v const&>); +static_assert(std::is_invocable_v const>); +static_assert(std::is_invocable_v const&&>); + +int fn() noexcept { return 42; } + +struct { + int operator()() noexcept { return 42; } +} fn_obj; + +void test() { + // template function_ref(F* f) noexcept; + { + // initialized from a function + std::function_ref fn_ref = fn; + assert(fn_ref() == 42); + } + { + // initialized from a function pointer + std::function_ref fn_ref = &fn; + assert(fn_ref() == 42); + } + + // template constexpr function_ref(F&& f) noexcept; + { + // initialized from a function object + std::function_ref fn_ref = fn_obj; + assert(fn_ref() == 42); + } +} + +struct S { + int data_mem = 42; + + int fn_mem() noexcept { return 42; } +}; + +void test_nontype_t() { + // template constexpr function_ref(nontype_t) noexcept; + { + // initialized from a function through `nontype_t` + std::function_ref fn_ref = std::nontype_t(); + assert(fn_ref() == 42); + } + { + // initialized from a function pointer through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&fn>(); + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to data member through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&S::data_mem>(); + assert(fn_ref(s) == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&S::fn_mem>(); + assert(fn_ref(s) == 42); + } + + // template + // constexpr function_ref(nontype_t, U&& obj) noexcept; + { + S s; + // initialized from a pointer to data member through `nontype_t` and bound to an object through a reference + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), s}; + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` and bound to an object through a reference + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), s}; + assert(fn_ref() == 42); + } + + // template + // constexpr function_ref(nontype_t, cv T* obj) noexcept; + { + S s; + // initialized from a pointer to data member through `nontype_t` and bound to an object through a pointer + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), &s}; + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` and bound to an object through a pointer + static_assert(std::is_same_v); + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), &s}; + assert(fn_ref() == 42); + } +} + +int main(int, char**) { + test(); + test_nontype_t(); + return 0; +} From d8ab8e551502f6f95acf140495b9e22e12e624c0 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sat, 8 Jun 2024 23:22:06 -0700 Subject: [PATCH 02/13] [libc++] P0792R14: 'function_ref' --- .../__functional/function_ref_common.h | 8 +- .../include/__functional/function_ref_impl.h | 48 +++++------ .../func.wrap.ref/ctor/ctad.pass.cpp | 84 +++++++++++++++++++ .../{call => invoke}/const.pass.cpp | 0 .../{call => invoke}/const_noexcept.pass.cpp | 0 .../{call => invoke}/default.pass.cpp | 0 .../{call => invoke}/noexcept.pass.cpp | 0 7 files changed, 111 insertions(+), 29 deletions(-) create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/ctor/ctad.pass.cpp rename libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/{call => invoke}/const.pass.cpp (100%) rename libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/{call => invoke}/const_noexcept.pass.cpp (100%) rename libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/{call => invoke}/default.pass.cpp (100%) rename libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/{call => invoke}/noexcept.pass.cpp (100%) diff --git a/libcxx/include/__functional/function_ref_common.h b/libcxx/include/__functional/function_ref_common.h index f7d5575ebaffd..d34a47286cf58 100644 --- a/libcxx/include/__functional/function_ref_common.h +++ b/libcxx/include/__functional/function_ref_common.h @@ -33,14 +33,14 @@ template inline constexpr bool __is_function_ref> = true; template -struct __function_ref_bind; +struct __function_ref_bind {}; -template +template struct __function_ref_bind<_Rp (*)(_Gp, _ArgTypes...), _Tp> { using type = _Rp(_ArgTypes...); }; -template +template struct __function_ref_bind<_Rp (*)(_Gp, _ArgTypes...) noexcept, _Tp> { using type = _Rp(_ArgTypes...) noexcept; }; @@ -48,7 +48,7 @@ struct __function_ref_bind<_Rp (*)(_Gp, _ArgTypes...) noexcept, _Tp> { template requires is_object_v<_Mp> struct __function_ref_bind<_Mp _Gp::*, _Tp> { - using type = invoke_result_t<_Mp _Gp::*, _Tp&>; + using type = invoke_result_t<_Mp _Gp::*, _Tp&>(); }; template diff --git a/libcxx/include/__functional/function_ref_impl.h b/libcxx/include/__functional/function_ref_impl.h index 4e1cd13a02ae2..2e6ed45f32b19 100644 --- a/libcxx/include/__functional/function_ref_impl.h +++ b/libcxx/include/__functional/function_ref_impl.h @@ -46,6 +46,8 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU static constexpr bool __is_invocable_using = is_invocable_r_v<_Rp, _Tp..., _ArgTypes...>; # endif + // use a union instead of a plain `void*` to avoid dropping const qualifiers and casting function pointers to data + // pointers union __storage_t { void* __obj_ptr; void const* __obj_const_ptr; @@ -82,18 +84,17 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU } } - using __vtable_call_t = _Rp (*)(__storage_t, _ArgTypes&&...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT); - __vtable_call_t __vtable_call_; + using __call_t = _Rp (*)(__storage_t, _ArgTypes&&...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT); + __call_t __call_; public: template requires is_function_v<_Fp> && __is_invocable_using<_Fp> _LIBCPP_HIDE_FROM_ABI function_ref(_Fp* __fn_ptr) noexcept : __storage_(__fn_ptr), - __vtable_call_( - [](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { - return __get<_Fp>(__storage)(std::forward<_ArgTypes>(__args)...); - }) { + __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { + return __get<_Fp>(__storage)(std::forward<_ArgTypes>(__args)...); + }) { _LIBCPP_ASSERT_UNCATEGORIZED(__fn_ptr != nullptr, "the function pointer should not be a nullptr"); } @@ -102,16 +103,15 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU __is_invocable_using<_LIBCPP_FUNCTION_REF_CV _Tp&>) _LIBCPP_HIDE_FROM_ABI function_ref(_Fp&& __obj) noexcept : __storage_(std::addressof(__obj)), - __vtable_call_( - [](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { - _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage); - return __obj(std::forward<_ArgTypes>(__args)...); - }) {} + __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { + _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage); + return __obj(std::forward<_ArgTypes>(__args)...); + }) {} template requires __is_invocable_using constexpr function_ref(nontype_t<_Fn>) noexcept - : __vtable_call_([](__storage_t, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { + : __call_([](__storage_t, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { return std::invoke_r<_Rp>(_Fn, std::forward<_ArgTypes>(__args)...); }) { if constexpr (is_pointer_v || is_member_pointer_v) { @@ -123,11 +123,10 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU requires(!is_rvalue_reference_v<_Up &&>) && __is_invocable_using constexpr function_ref(nontype_t<_Fn>, _Up&& __obj) noexcept : __storage_(std::addressof(__obj)), - __vtable_call_( - [](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { - _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage); - return std::invoke_r<_Rp>(_Fn, __obj, std::forward<_ArgTypes>(__args)...); - }) { + __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { + _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage); + return std::invoke_r<_Rp>(_Fn, __obj, std::forward<_ArgTypes>(__args)...); + }) { if constexpr (is_pointer_v || is_member_pointer_v) { static_assert(_Fn != nullptr, "the function pointer should not be a nullptr"); } @@ -137,11 +136,10 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU requires __is_invocable_using constexpr function_ref(nontype_t<_Fn>, _LIBCPP_FUNCTION_REF_CV _Tp* __obj_ptr) noexcept : __storage_(__obj_ptr), - __vtable_call_( - [](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { - auto __obj = __get<_LIBCPP_FUNCTION_REF_CV _Tp>(__storage); - return std::invoke_r<_Rp>(_Fn, __obj, std::forward<_ArgTypes>(__args)...); - }) { + __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { + auto __obj = __get<_LIBCPP_FUNCTION_REF_CV _Tp>(__storage); + return std::invoke_r<_Rp>(_Fn, __obj, std::forward<_ArgTypes>(__args)...); + }) { if constexpr (is_pointer_v || is_member_pointer_v) { static_assert(_Fn != nullptr, "the function pointer should not be a nullptr"); } @@ -160,17 +158,17 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU function_ref& operator=(_Tp) = delete; constexpr _Rp operator()(_ArgTypes... __args) const noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) { - return __vtable_call_(__storage_, std::forward<_ArgTypes>(__args)...); + return __call_(__storage_, std::forward<_ArgTypes>(__args)...); } }; -template +template struct __function_ref_bind<_Rp (_Gp::*)(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT), _Tp> { using type = _Rp(_ArgTypes...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT); }; -template +template struct __function_ref_bind<_Rp (_Gp::*)(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV & noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT), _Tp> { using type = _Rp(_ArgTypes...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT); diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/ctor/ctad.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/ctor/ctad.pass.cpp new file mode 100644 index 0000000000000..c7490fc0982e3 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/ctor/ctad.pass.cpp @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 + +#include +#include +#include +#include + +#include "test_macros.h" + +int fn(int, float) { return 42; } + +int fn_noexcept(int, float) noexcept { return 42; } + +struct S { + int data_mem = 42; + + int fn_mem(int, float) { return 42; } + int fn_mem_noexcept(int, float) noexcept { return 42; } +}; + +void test() { + // template + // function_ref(F*) -> function_ref; + { + std::function_ref fn_ref = fn; + static_assert(std::is_same_v>); + } + { + std::function_ref fn_ref = fn_noexcept; + static_assert(std::is_same_v>); + } + + // template + // function_ref(nontype_t) -> function_ref<...>; + { + std::function_ref fn_ref = std::nontype_t(); + static_assert(std::is_same_v>); + } + { + std::function_ref fn_ref = std::nontype_t(); + static_assert(std::is_same_v>); + } + + // template + // function_ref(nontype_t, T&&) -> function_ref<...>; + { + int arg = 0; + std::function_ref fn_ref = {std::nontype_t(), arg}; + static_assert(std::is_same_v>); + } + { + S s; + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), s}; + static_assert(std::is_same_v>); + } + { + const S s; + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), s}; + static_assert(std::is_same_v>); + } + { + S s; + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), s}; + static_assert(std::is_same_v>); + } + { + S s; + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem_noexcept>(), s}; + static_assert(std::is_same_v>); + } +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const.pass.cpp similarity index 100% rename from libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const.pass.cpp rename to libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const.pass.cpp diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const_noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const_noexcept.pass.cpp similarity index 100% rename from libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const_noexcept.pass.cpp rename to libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const_noexcept.pass.cpp diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/default.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/default.pass.cpp similarity index 100% rename from libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/default.pass.cpp rename to libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/default.pass.cpp diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/noexcept.pass.cpp similarity index 100% rename from libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/noexcept.pass.cpp rename to libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/noexcept.pass.cpp From 7fe10889b47e401aa18617620e8ff4c248816680 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sun, 9 Jun 2024 01:50:20 -0700 Subject: [PATCH 03/13] [libc++] P0792R14: 'function_ref' --- libcxx/modules/std/functional.inc | 4 ++++ libcxx/modules/std/utility.inc | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/libcxx/modules/std/functional.inc b/libcxx/modules/std/functional.inc index ddc7d023ee6dc..4d2be32f3f6bb 100644 --- a/libcxx/modules/std/functional.inc +++ b/libcxx/modules/std/functional.inc @@ -91,6 +91,10 @@ export namespace std { using std::function; +#if _LIBCPP_STD_VER >= 26 + using std::function_ref; +#endif // _LIBCPP_STD_VER >= 26 + using std::swap; using std::operator==; diff --git a/libcxx/modules/std/utility.inc b/libcxx/modules/std/utility.inc index 77c21b87640dd..28f8e36e30af9 100644 --- a/libcxx/modules/std/utility.inc +++ b/libcxx/modules/std/utility.inc @@ -89,6 +89,11 @@ export namespace std { using std::in_place_index; using std::in_place_index_t; +#if _LIBCPP_STD_VER >= 26 + using std::nontype; + using std::nontype_t; +#endif // _LIBCPP_STD_VER >= 23 + // [depr.relops] namespace rel_ops { using rel_ops::operator!=; From 285b767482c32dfc66dc56eb641ecb2bbe12dfe1 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sun, 9 Jun 2024 03:41:35 -0700 Subject: [PATCH 04/13] [libc++] P0792R14: 'function_ref' --- libcxx/include/CMakeLists.txt | 2 +- libcxx/include/__utility/nontype.h | 5 +++++ libcxx/include/module.modulemap | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 6dd28b79117af..27375cf2e9164 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -393,9 +393,9 @@ set(files __functional/compose.h __functional/default_searcher.h __functional/function.h + __functional/function_ref.h __functional/function_ref_common.h __functional/function_ref_impl.h - __functional/function_ref.h __functional/hash.h __functional/identity.h __functional/invoke.h diff --git a/libcxx/include/__utility/nontype.h b/libcxx/include/__utility/nontype.h index 86893f17e2d96..6a91d2cace162 100644 --- a/libcxx/include/__utility/nontype.h +++ b/libcxx/include/__utility/nontype.h @@ -27,6 +27,11 @@ struct nontype_t { template inline constexpr nontype_t<_Vp> nontype{}; +template +inline constexpr bool __is_nontype_t = false; +template +inline constexpr bool __is_nontype_t> = true; + #endif // _LIBCPP_STD_VER >= 26 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 5143f3fadfdc2..85ea6cdf35634 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1340,6 +1340,8 @@ module std_private_functional_compose [system] { module std_private_functional_default_searcher [system] { header "__functional/default_searcher.h" } module std_private_functional_function [system] { header "__functional/function.h" } module std_private_functional_function_ref [system] { header "__functional/function_ref.h" } +module std_private_functional_function_ref_common [system] { header "__functional/function_ref_common.h" } +module std_private_functional_function_ref_impl [system] { textual header "__functional/function_ref_impl.h" } module std_private_functional_hash [system] { header "__functional/hash.h" export std_cstdint From ee362ac8210b70cdb944ef78fe9e88e8548a7353 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sun, 9 Jun 2024 03:50:12 -0700 Subject: [PATCH 05/13] [libc++] P0792R14: 'function_ref' --- .../include/__functional/function_ref_impl.h | 18 +++++++++--------- libcxx/include/__utility/nontype.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libcxx/include/__functional/function_ref_impl.h b/libcxx/include/__functional/function_ref_impl.h index 2e6ed45f32b19..261beb2d04dad 100644 --- a/libcxx/include/__functional/function_ref_impl.h +++ b/libcxx/include/__functional/function_ref_impl.h @@ -53,10 +53,10 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU void const* __obj_const_ptr; void (*__fn_ptr)(); - constexpr explicit __storage_t() noexcept : __obj_ptr(nullptr) {}; + _LIBCPP_HIDE_FROM_ABI constexpr explicit __storage_t() noexcept : __obj_ptr(nullptr){}; template - constexpr explicit __storage_t(_Tp* __ptr) noexcept { + _LIBCPP_HIDE_FROM_ABI constexpr explicit __storage_t(_Tp* __ptr) noexcept { if constexpr (is_object_v<_Tp>) { if constexpr (is_const_v<_Tp>) { __obj_const_ptr = __ptr; @@ -110,7 +110,7 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU template requires __is_invocable_using - constexpr function_ref(nontype_t<_Fn>) noexcept + _LIBCPP_HIDE_FROM_ABI constexpr function_ref(nontype_t<_Fn>) noexcept : __call_([](__storage_t, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { return std::invoke_r<_Rp>(_Fn, std::forward<_ArgTypes>(__args)...); }) { @@ -121,7 +121,7 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU template > requires(!is_rvalue_reference_v<_Up &&>) && __is_invocable_using - constexpr function_ref(nontype_t<_Fn>, _Up&& __obj) noexcept + _LIBCPP_HIDE_FROM_ABI constexpr function_ref(nontype_t<_Fn>, _Up&& __obj) noexcept : __storage_(std::addressof(__obj)), __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage); @@ -134,7 +134,7 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU template requires __is_invocable_using - constexpr function_ref(nontype_t<_Fn>, _LIBCPP_FUNCTION_REF_CV _Tp* __obj_ptr) noexcept + _LIBCPP_HIDE_FROM_ABI constexpr function_ref(nontype_t<_Fn>, _LIBCPP_FUNCTION_REF_CV _Tp* __obj_ptr) noexcept : __storage_(__obj_ptr), __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { auto __obj = __get<_LIBCPP_FUNCTION_REF_CV _Tp>(__storage); @@ -149,15 +149,15 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU } } - constexpr function_ref(const function_ref&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr function_ref(const function_ref&) noexcept = default; - constexpr function_ref& operator=(const function_ref&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr function_ref& operator=(const function_ref&) noexcept = default; template requires(!__is_function_ref<_Tp>) && (!is_pointer_v<_Tp>) && (!__is_nontype_t<_Tp>) - function_ref& operator=(_Tp) = delete; + _LIBCPP_HIDE_FROM_ABI function_ref& operator=(_Tp) = delete; - constexpr _Rp operator()(_ArgTypes... __args) const noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) { + _LIBCPP_HIDE_FROM_ABI constexpr _Rp operator()(_ArgTypes... __args) const noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) { return __call_(__storage_, std::forward<_ArgTypes>(__args)...); } }; diff --git a/libcxx/include/__utility/nontype.h b/libcxx/include/__utility/nontype.h index 6a91d2cace162..3a10840154009 100644 --- a/libcxx/include/__utility/nontype.h +++ b/libcxx/include/__utility/nontype.h @@ -21,7 +21,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD template struct nontype_t { - explicit nontype_t() = default; + _LIBCPP_HIDE_FROM_ABI explicit nontype_t() = default; }; template From 379b00286259350f2a935869234fc0c654817fa8 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sun, 9 Jun 2024 03:55:54 -0700 Subject: [PATCH 06/13] [libc++] P0792R14: 'function_ref' --- libcxx/include/__functional/function_ref_common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/__functional/function_ref_common.h b/libcxx/include/__functional/function_ref_common.h index d34a47286cf58..b2d1864e582c5 100644 --- a/libcxx/include/__functional/function_ref_common.h +++ b/libcxx/include/__functional/function_ref_common.h @@ -11,6 +11,7 @@ #include <__config> #include <__type_traits/invoke.h> +#include <__type_traits/is_function.h> #include <__type_traits/is_object.h> #include <__type_traits/remove_pointer.h> #include <__utility/nontype.h> From c8847eff1e7f07124db4486dd750bdc6ec8e4432 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sun, 9 Jun 2024 04:01:41 -0700 Subject: [PATCH 07/13] [libc++] P0792R14: 'function_ref' --- libcxx/include/__functional/function_ref_impl.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/__functional/function_ref_impl.h b/libcxx/include/__functional/function_ref_impl.h index 261beb2d04dad..50951228c10a8 100644 --- a/libcxx/include/__functional/function_ref_impl.h +++ b/libcxx/include/__functional/function_ref_impl.h @@ -17,6 +17,7 @@ #include <__type_traits/is_member_pointer.h> #include <__type_traits/is_object.h> #include <__type_traits/is_pointer.h> +#include <__type_traits/is_reference.h> #include <__type_traits/is_void.h> #include <__type_traits/remove_cvref.h> #include <__type_traits/remove_pointer.h> From 0ebb4ea9e4b6539cebad83ff2345e18368d4049f Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sun, 9 Jun 2024 04:41:50 -0700 Subject: [PATCH 08/13] [libc++] P0792R14: 'function_ref' --- libcxx/include/__functional/function_ref.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/__functional/function_ref.h b/libcxx/include/__functional/function_ref.h index 01cc22a64018e..8fcebb8aa4825 100644 --- a/libcxx/include/__functional/function_ref.h +++ b/libcxx/include/__functional/function_ref.h @@ -10,6 +10,7 @@ #define _LIBCPP___FUNCTIONAL_FUNCTION_REF_H #include <__config> +#include <__functional/function_ref_common.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header From df08aa32027816a9d841b18a5e2b3d94721fe709 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sun, 9 Jun 2024 04:58:24 -0700 Subject: [PATCH 09/13] [libc++] P0792R14: 'function_ref' --- libcxx/include/module.modulemap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 85ea6cdf35634..00a39ea81e0a0 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1341,7 +1341,7 @@ module std_private_functional_default_searcher [system] { header "__fu module std_private_functional_function [system] { header "__functional/function.h" } module std_private_functional_function_ref [system] { header "__functional/function_ref.h" } module std_private_functional_function_ref_common [system] { header "__functional/function_ref_common.h" } -module std_private_functional_function_ref_impl [system] { textual header "__functional/function_ref_impl.h" } +module std_private_functional_function_ref_impl [system] { header "__functional/function_ref_impl.h" } module std_private_functional_hash [system] { header "__functional/hash.h" export std_cstdint From 5163e99c086114d18f9bad6803e9ad226339d53b Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sun, 9 Jun 2024 05:10:54 -0700 Subject: [PATCH 10/13] [libc++] P0792R14: 'function_ref' --- libcxx/include/module.modulemap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 00a39ea81e0a0..85ea6cdf35634 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1341,7 +1341,7 @@ module std_private_functional_default_searcher [system] { header "__fu module std_private_functional_function [system] { header "__functional/function.h" } module std_private_functional_function_ref [system] { header "__functional/function_ref.h" } module std_private_functional_function_ref_common [system] { header "__functional/function_ref_common.h" } -module std_private_functional_function_ref_impl [system] { header "__functional/function_ref_impl.h" } +module std_private_functional_function_ref_impl [system] { textual header "__functional/function_ref_impl.h" } module std_private_functional_hash [system] { header "__functional/hash.h" export std_cstdint From f018cd6773fd7da8d1cbf389cd7e08a8994fa134 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sun, 9 Jun 2024 11:18:14 -0700 Subject: [PATCH 11/13] [libc++] P0792R14: 'function_ref' --- libcxx/include/__functional/function_ref_impl.h | 1 - libcxx/include/module.modulemap | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/libcxx/include/__functional/function_ref_impl.h b/libcxx/include/__functional/function_ref_impl.h index 50951228c10a8..d992d6661cf1b 100644 --- a/libcxx/include/__functional/function_ref_impl.h +++ b/libcxx/include/__functional/function_ref_impl.h @@ -8,7 +8,6 @@ #include <__assert> #include <__config> -#include <__functional/function_ref_common.h> #include <__functional/invoke.h> #include <__memory/addressof.h> #include <__type_traits/invoke.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 85ea6cdf35634..c24d17b62931a 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1340,7 +1340,7 @@ module std_private_functional_compose [system] { module std_private_functional_default_searcher [system] { header "__functional/default_searcher.h" } module std_private_functional_function [system] { header "__functional/function.h" } module std_private_functional_function_ref [system] { header "__functional/function_ref.h" } -module std_private_functional_function_ref_common [system] { header "__functional/function_ref_common.h" } +module std_private_functional_function_ref_common [system] { textual header "__functional/function_ref_common.h" } module std_private_functional_function_ref_impl [system] { textual header "__functional/function_ref_impl.h" } module std_private_functional_hash [system] { header "__functional/hash.h" From 0adfe0b398443b3b35371eb255d4f62c8503cca2 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sun, 9 Jun 2024 11:23:21 -0700 Subject: [PATCH 12/13] [libc++] P0792R14: 'function_ref' --- libcxx/include/functional | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libcxx/include/functional b/libcxx/include/functional index f413e296fab9e..1a9bce7b00229 100644 --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -483,6 +483,11 @@ template template void swap(function&, function&) noexcept; +// [func.wrap.ref], non-owning wrapper +template class function_ref; // freestanding, not defined, since C++26 +template + class function_ref; // freestanding, since C++26 + template struct hash; template <> struct hash; From b343529bda1c3c015f689e46d9af004021fecbbb Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sun, 9 Jun 2024 11:58:22 -0700 Subject: [PATCH 13/13] [libc++] P0792R14: 'function_ref' --- libcxx/include/__functional/function_ref_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/__functional/function_ref_impl.h b/libcxx/include/__functional/function_ref_impl.h index d992d6661cf1b..daae5c87d9470 100644 --- a/libcxx/include/__functional/function_ref_impl.h +++ b/libcxx/include/__functional/function_ref_impl.h @@ -53,7 +53,7 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU void const* __obj_const_ptr; void (*__fn_ptr)(); - _LIBCPP_HIDE_FROM_ABI constexpr explicit __storage_t() noexcept : __obj_ptr(nullptr){}; + _LIBCPP_HIDE_FROM_ABI constexpr explicit __storage_t() noexcept : __obj_ptr(nullptr) {} template _LIBCPP_HIDE_FROM_ABI constexpr explicit __storage_t(_Tp* __ptr) noexcept {