Skip to content

Commit

Permalink
[libc++] Implement std::not_fn<NTTP> (llvm#86133)
Browse files Browse the repository at this point in the history
Implement `std::not_fn<NTTP>` from "P2714R1 Bind front and back to NTTP callables".
  • Loading branch information
JMazurkiewicz authored Jan 10, 2025
1 parent c391082 commit c91d805
Show file tree
Hide file tree
Showing 12 changed files with 446 additions and 8 deletions.
2 changes: 2 additions & 0 deletions libcxx/docs/FeatureTestMacroTable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,8 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_mdspan`` ``202406L``
---------------------------------------------------------- -----------------
``__cpp_lib_not_fn`` ``202306L``
---------------------------------------------------------- -----------------
``__cpp_lib_optional_range_support`` *unimplemented*
---------------------------------------------------------- -----------------
``__cpp_lib_out_ptr`` ``202311L``
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx2cPapers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"`P1383R2 <https://wg21.link/P1383R2>`__","More ``constexpr`` for ``<cmath>`` and ``<complex>``","2023-06 (Varna)","","",""
"`P2734R0 <https://wg21.link/P2734R0>`__","Adding the new SI prefixes","2023-06 (Varna)","|Complete|","17",""
"`P2548R6 <https://wg21.link/P2548R6>`__","``copyable_function``","2023-06 (Varna)","","",""
"`P2714R1 <https://wg21.link/P2714R1>`__","Bind front and back to NTTP callables","2023-06 (Varna)","","",""
"`P2714R1 <https://wg21.link/P2714R1>`__","Bind front and back to NTTP callables","2023-06 (Varna)","|Partial|","20","``not_fn`` only"
"`P2630R4 <https://wg21.link/P2630R4>`__","``submdspan``","2023-06 (Varna)","","",""
"","","","","",""
"`P0543R3 <https://wg21.link/P0543R3>`__","Saturation arithmetic","2023-11 (Kona)","|Complete|","18",""
Expand Down
23 changes: 23 additions & 0 deletions libcxx/include/__functional/not_fn.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include <__type_traits/decay.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_constructible.h>
#include <__type_traits/is_member_pointer.h>
#include <__type_traits/is_pointer.h>
#include <__utility/forward.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
Expand Down Expand Up @@ -48,6 +50,27 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 auto not_fn(_Fn&& __f) {

#endif // _LIBCPP_STD_VER >= 17

#if _LIBCPP_STD_VER >= 26

template <auto _Fn>
struct __nttp_not_fn_t {
template <class... _Args>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) const
noexcept(noexcept(!std::invoke(_Fn, std::forward<_Args>(__args)...)))
-> decltype(!std::invoke(_Fn, std::forward<_Args>(__args)...)) {
return !std::invoke(_Fn, std::forward<_Args>(__args)...);
}
};

template <auto _Fn>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr auto not_fn() noexcept {
if constexpr (using _Ty = decltype(_Fn); is_pointer_v<_Ty> || is_member_pointer_v<_Ty>)
static_assert(_Fn != nullptr, "f cannot be equal to nullptr");
return __nttp_not_fn_t<_Fn>();
}

#endif // _LIBCPP_STD_VER >= 26

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___FUNCTIONAL_NOT_FN_H
4 changes: 3 additions & 1 deletion libcxx/include/functional
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,9 @@ template <class Predicate> // deprecated in C++17, removed in C++20
binary_negate<Predicate> not2(const Predicate& pred);
template <class F>
constexpr unspecified not_fn(F&& f); // C++17, constexpr in C++20
constexpr unspecified not_fn(F&& f); // C++17, constexpr in C++20
template <auto f>
constexpr unspecified not_fn() noexcept; // C++26
// [func.bind.partial], function templates bind_front and bind_back
template<class F, class... Args>
Expand Down
5 changes: 4 additions & 1 deletion libcxx/include/version
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ __cpp_lib_nonmember_container_access 201411L <array> <deque>
<iterator> <list> <map>
<regex> <set> <string>
<unordered_map> <unordered_set> <vector>
__cpp_lib_not_fn 201603L <functional>
__cpp_lib_not_fn 202306L <functional>
201603L // C++17
__cpp_lib_null_iterators 201304L <iterator>
__cpp_lib_optional 202110L <optional>
202106L // C++20
Expand Down Expand Up @@ -557,6 +558,8 @@ __cpp_lib_void_t 201411L <type_traits>
// # define __cpp_lib_linalg 202311L
# undef __cpp_lib_mdspan
# define __cpp_lib_mdspan 202406L
# undef __cpp_lib_not_fn
# define __cpp_lib_not_fn 202306L
// # define __cpp_lib_optional_range_support 202406L
# undef __cpp_lib_out_ptr
# define __cpp_lib_out_ptr 202311L
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//===----------------------------------------------------------------------===//
//
// 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

// <functional>

// Type of `std::not_fn<NTTP>()` is always empty.

#include <functional>
#include <type_traits>

struct NonEmptyFunctionObject {
bool val = true;
bool operator()() const;
};

bool func();

struct SomeClass {
bool member_object;
bool member_function();
};

using ResultWithEmptyFuncObject = decltype(std::not_fn<std::false_type{}>());
static_assert(std::is_empty_v<ResultWithEmptyFuncObject>);

using ResultWithNotEmptyFuncObject = decltype(std::not_fn<NonEmptyFunctionObject{}>());
static_assert(std::is_empty_v<ResultWithNotEmptyFuncObject>);

using ResultWithFunctionPointer = decltype(std::not_fn<&func>());
static_assert(std::is_empty_v<ResultWithFunctionPointer>);

using ResultWithMemberObjectPointer = decltype(std::not_fn<&SomeClass::member_object>());
static_assert(std::is_empty_v<ResultWithMemberObjectPointer>);

using ResultWithMemberFunctionPointer = decltype(std::not_fn<&SomeClass::member_function>());
static_assert(std::is_empty_v<ResultWithMemberFunctionPointer>);
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
//
// 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

// <functional>

// Test the libc++ extension that std::not_fn<NTTP> is marked as [[nodiscard]].

#include <functional>
#include <type_traits>

void test() {
using F = std::true_type;
std::not_fn<F{}>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}

auto negated = std::not_fn<F{}>();
negated(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
__cpp_lib_invoke_r 202106L [C++23]
__cpp_lib_move_only_function 202110L [C++23]
__cpp_lib_not_fn 201603L [C++17]
202306L [C++26]
__cpp_lib_ranges 202110L [C++20]
202406L [C++23]
__cpp_lib_reference_wrapper 202403L [C++26]
Expand Down Expand Up @@ -525,8 +526,8 @@
# ifndef __cpp_lib_not_fn
# error "__cpp_lib_not_fn should be defined in c++26"
# endif
# if __cpp_lib_not_fn != 201603L
# error "__cpp_lib_not_fn should have the value 201603L in c++26"
# if __cpp_lib_not_fn != 202306L
# error "__cpp_lib_not_fn should have the value 202306L in c++26"
# endif

# ifndef __cpp_lib_ranges
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@
__cpp_lib_node_extract 201606L [C++17]
__cpp_lib_nonmember_container_access 201411L [C++17]
__cpp_lib_not_fn 201603L [C++17]
202306L [C++26]
__cpp_lib_null_iterators 201304L [C++14]
__cpp_lib_optional 201606L [C++17]
202106L [C++20]
Expand Down Expand Up @@ -7405,8 +7406,8 @@
# ifndef __cpp_lib_not_fn
# error "__cpp_lib_not_fn should be defined in c++26"
# endif
# if __cpp_lib_not_fn != 201603L
# error "__cpp_lib_not_fn should have the value 201603L in c++26"
# if __cpp_lib_not_fn != 202306L
# error "__cpp_lib_not_fn should have the value 202306L in c++26"
# endif

# ifndef __cpp_lib_null_iterators
Expand Down
Loading

0 comments on commit c91d805

Please sign in to comment.