• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_TYPE_TRAITS_H_
6 #define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_TYPE_TRAITS_H_
7 
8 #include <type_traits>
9 
10 namespace cpp17 {
11 namespace internal {
12 
13 template <typename T>
14 static constexpr bool is_reference_wrapper = false;
15 template <typename T>
16 static constexpr bool is_reference_wrapper<std::reference_wrapper<T>> = true;
17 
18 // These are from [func.require] ¶ 1.1-7
19 template <typename MemFn, typename Class, typename T>
20 static constexpr bool invoke_pmf_base = std::is_member_function_pointer<MemFn Class::*>::value&&
21     std::is_base_of<Class, std::remove_reference_t<T>>::value;
22 
23 template <typename MemFn, typename Class, typename T>
24 static constexpr bool invoke_pmf_refwrap = std::is_member_function_pointer<MemFn Class::*>::value&&
25     is_reference_wrapper<std::remove_cv_t<std::remove_reference_t<T>>>;
26 
27 template <typename MemFn, typename Class, typename T>
28 static constexpr bool invoke_pmf_other =
29     std::is_member_function_pointer<MemFn Class::*>::value && !invoke_pmf_base<MemFn, Class, T> &&
30     !invoke_pmf_refwrap<MemFn, Class, T>;
31 
32 template <typename MemObj, typename Class, typename T>
33 static constexpr bool invoke_pmd_base = std::is_member_object_pointer<MemObj Class::*>::value&&
34     std::is_base_of<Class, std::remove_reference_t<T>>::value;
35 
36 template <typename MemObj, typename Class, typename T>
37 static constexpr bool invoke_pmd_refwrap = std::is_member_object_pointer<MemObj Class::*>::value&&
38     is_reference_wrapper<std::remove_cv_t<std::remove_reference_t<T>>>;
39 
40 template <typename MemObj, typename Class, typename T>
41 static constexpr bool invoke_pmd_other =
42     std::is_member_object_pointer<MemObj Class::*>::value && !invoke_pmd_base<MemObj, Class, T> &&
43     !invoke_pmd_refwrap<MemObj, Class, T>;
44 
45 // ¶ 1.7 says to just return f(t1, t2, ..., tn) in all other cases
46 
47 // Just internal forward declarations for SFINAE; cpp20::invoke is defined in
48 // lib/stdcompat/functional.h
49 template <typename MemFn, typename Class, typename T, typename... Args>
50 constexpr auto invoke(MemFn Class::*f, T&& obj, Args&&... args)
51     -> std::enable_if_t<invoke_pmf_base<MemFn, Class, T>,
52                         decltype((std::forward<T>(obj).*f)(std::forward<Args>(args)...))>;
53 
54 template <typename MemFn, typename Class, typename T, typename... Args>
55 constexpr auto invoke(MemFn Class::*f, T&& obj, Args&&... args)
56     -> std::enable_if_t<invoke_pmf_refwrap<MemFn, Class, T>,
57                         decltype((obj.get().*f)(std::forward<Args>(args)...))>;
58 
59 template <typename MemFn, typename Class, typename T, typename... Args>
60 constexpr auto invoke(MemFn Class::*f, T&& obj, Args&&... args)
61     -> std::enable_if_t<invoke_pmf_other<MemFn, Class, T>,
62                         decltype(((*std::forward<T>(obj)).*f)(std::forward<Args>(args)...))>;
63 
64 template <typename MemObj, typename Class, typename T>
65 constexpr auto invoke(MemObj Class::*f, T&& obj)
66     -> std::enable_if_t<invoke_pmd_base<MemObj, Class, T>, decltype(std::forward<T>(obj).*f)>;
67 
68 template <typename MemObj, typename Class, typename T>
69 constexpr auto invoke(MemObj Class::*f, T&& obj)
70     -> std::enable_if_t<invoke_pmd_refwrap<MemObj, Class, T>, decltype(obj.get().*f)>;
71 
72 template <typename MemObj, typename Class, typename T>
73 constexpr auto invoke(MemObj Class::*f, T&& obj)
74     -> std::enable_if_t<invoke_pmd_other<MemObj, Class, T>, decltype((*std::forward<T>(obj)).*f)>;
75 
76 template <typename F, typename... Args>
77 constexpr auto invoke(F&& f, Args&&... args)
78     -> decltype(std::forward<F>(f)(std::forward<Args>(args)...));
79 
80 template <typename R, typename F, typename... Args,
81           typename = std::enable_if_t<std::is_void<R>::value>>
82 constexpr auto invoke_r(F&& f, Args&&... args)
83     -> decltype(static_cast<void>(::cpp17::internal::invoke(std::forward<F>(f),
84                                                             std::forward<Args>(args)...)));
85 
86 template <typename R, typename F, typename... Args,
87           typename = std::enable_if_t<!std::is_void<R>::value>>
88 constexpr auto invoke_r(F&& f, Args&&... args)
89     -> std::enable_if_t<std::is_convertible<decltype(::cpp17::internal::invoke(
90                                                 std::forward<F>(f), std::forward<Args>(args)...)),
91                                             R>::value,
92                         R>;
93 
94 template <typename R, typename F, typename... Args>
95 constexpr auto is_valid_invoke(std::nullptr_t)
96     -> decltype(invoke_r<R>(std::declval<F>(), std::declval<Args>()...), std::true_type());
97 
98 template <typename R, typename F, typename... Args>
99 constexpr std::false_type is_valid_invoke(...);
100 
101 template <bool Enable, typename F, typename... Args>
102 struct invoke_result {};
103 
104 template <typename F, typename... Args>
105 struct invoke_result<true, F, Args...> {
106   using type = decltype(::cpp17::internal::invoke(std::declval<F>(), std::declval<Args>()...));
107 };
108 
109 }  // namespace internal
110 }  // namespace cpp17
111 
112 #endif  // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_TYPE_TRAITS_H_
113