Sen API
Sen Libraries
Loading...
Searching...
No Matches
move_only_function_impl.h
Go to the documentation of this file.
1// === move_only_function_impl.h =======================================================================================
2// Sen Infrastructure
3// Released under the Apache License v2.0 (SPDX-License-Identifier Apache-2.0).
4// See the LICENSE.txt file for more information.
5// © Airbus SAS, Airbus Helicopters, and Airbus Defence and Space SAU/GmbH/SAS.
6// =====================================================================================================================
7
8// NOLINTBEGIN(misc-include-cleaner)
9// Due to the include stamping trick, the checker gets confused here
10
11// sen
13
14// std
15#include <cassert>
16#include <initializer_list>
17#include <type_traits>
18// NOLINTEND(misc-include-cleaner)
19
21{
22
23#if defined(_MSC_VER)
24# define NOEXCEPT_SPECIFIER
25# define NOEXCEPT_SPECIALIZATION
26#else
27# define NOEXCEPT_SPECIFIER noexcept(IsNoExcept)
28# define NOEXCEPT_SPECIALIZATION , bool IsNoExcept
29#endif
30
31template <typename ResultType, typename... ArgTypes NOEXCEPT_SPECIALIZATION>
32// NOLINTNEXTLINE: prevent confusing between ArgType matching and a c-style cast
34 : private MoveOnlyFunctionBase
35{
36#if defined(_MSC_VER)
37 // TODO (SEN-1001): implement noexcept detection/specialization support for windows
38 static constexpr bool isNoExcept = false;
39#else
40 static constexpr bool isNoExcept = IsNoExcept;
41#endif
42
43 template <typename CallableType>
44 // NOLINTNEXTLINE(readability-identifier-naming): follows standard concept naming
45 using is_callable = std::conditional_t<isNoExcept,
46 std::is_nothrow_invocable_r<ResultType, CallableType, ArgTypes...>,
47 std::is_invocable_r<ResultType, CallableType, ArgTypes...>>;
48
49 template <typename UnqualifiedCallableType>
50 // NOLINTNEXTLINE(readability-identifier-naming): extends standard concept naming
51 using is_qualified_callable =
52 std::conjunction<is_callable<UnqualifiedCallableType GENERATE_WITH_CV GENERATE_WITH_REF>,
53 is_callable<UnqualifiedCallableType GENERATE_WITH_SELF_QUALIFIERS>>;
54
55public:
56 using result_type = ResultType; // NOLINT(readability-identifier-naming): requested by the standard
57
58 MoveOnlyFunctionImpl() noexcept = default;
59
60 // NOLINTNEXTLINE(hicpp-explicit-conversions): needed for automatic nullptr comparisions
61 MoveOnlyFunctionImpl(std::nullptr_t) noexcept {}
62
64 : MoveOnlyFunctionBase(static_cast<MoveOnlyFunctionBase&&>(other))
65 , activeDispatcherFunction_(std::exchange(other.activeDispatcherFunction_, nullptr))
66 {
67 }
68
69 template <typename CallableType,
70 typename DecayedCallableType = std::decay_t<CallableType>,
71 std::enable_if_t<std::conjunction_v<std::negation<std::is_same<DecayedCallableType, MoveOnlyFunctionImpl>>,
72 std::negation<IsInPlaceType<DecayedCallableType>>,
73 is_qualified_callable<DecayedCallableType>>,
74 bool> = true>
75 // NOLINTNEXTLINE(hicpp-explicit-conversions): required by the standard
77 {
78 if constexpr (std::is_function_v<std::remove_pointer_t<DecayedCallableType>> ||
79 std::is_member_pointer_v<DecayedCallableType> || is_move_only_function_v<DecayedCallableType>)
80 {
81
82#if defined(_MSC_VER) && _MSC_VER < 1932
83 // prevent older MSVC versions from trying to compare a reference to a function to a pointer
84 if constexpr (!std::is_reference_v<CallableType>)
85 {
86#endif
87 if (callable == nullptr)
88 {
89 return;
90 }
91#if defined(_MSC_VER) && _MSC_VER < 1932
92 }
93#endif
94 }
95 initializeCallable<DecayedCallableType>(std::forward<CallableType>(callable));
96 activeDispatcherFunction_ = &dispatcherFunction<DecayedCallableType>;
97 }
98
99 template <typename CallableType,
100 typename... FunctionArgTypes,
101 std::enable_if_t<std::conjunction_v<std::is_constructible<CallableType, FunctionArgTypes...>,
102 is_qualified_callable<CallableType>>,
103 bool> = true>
104 explicit MoveOnlyFunctionImpl(std::in_place_type_t<CallableType> /*unused*/,
105 FunctionArgTypes&&... args) noexcept(isNothrowInit<CallableType, FunctionArgTypes...>())
106 : activeDispatcherFunction_(&dispatcherFunction<CallableType>)
107 {
108 static_assert(std::is_same_v<std::decay_t<CallableType>, CallableType>);
109 initializeCallable<CallableType>(std::forward<FunctionArgTypes>(args)...);
110 }
111
112 template <
113 typename CallableType,
114 typename ILArgTypes,
115 typename... FunctionArgTypes,
116 std::enable_if_t<
117 std::conjunction_v<std::is_constructible<CallableType, std::initializer_list<ILArgTypes>&, FunctionArgTypes...>,
118 is_qualified_callable<CallableType>>,
119 bool> = true>
120 explicit MoveOnlyFunctionImpl(std::in_place_type_t<CallableType> /*unused*/,
121 std::initializer_list<ILArgTypes> initializeList,
122 FunctionArgTypes&&... args) noexcept(isNothrowInit<CallableType,
123 std::initializer_list<ILArgTypes>&,
124 FunctionArgTypes...>())
125 : activeDispatcherFunction_(&dispatcherFunction<CallableType>)
126 {
127 static_assert(std::is_same_v<std::decay_t<CallableType>, CallableType>);
128 initializeCallable<CallableType>(initializeList, std::forward<FunctionArgTypes>(args)...);
129 }
130
132 {
134 activeDispatcherFunction_ = std::exchange(other.activeDispatcherFunction_, nullptr);
135 return *this;
136 }
137
139 MoveOnlyFunctionImpl& operator=(std::nullptr_t) noexcept
140 {
142 activeDispatcherFunction_ = nullptr;
143 return *this;
144 }
145
147
149 ResultType operator()(ArgTypes... args) GENERATE_WITH_CV GENERATE_WITH_REF noexcept(isNoExcept)
150 {
151 assert(*this != nullptr && "Trying to execute empty callable object.");
152 return activeDispatcherFunction_(this, std::forward<ArgTypes>(args)...);
153 }
154
156 explicit operator bool() const noexcept { return activeDispatcherFunction_ != nullptr; }
157
159 friend bool operator==(const MoveOnlyFunctionImpl& lhs, std::nullptr_t) noexcept
160 {
161 return lhs.activeDispatcherFunction_ == nullptr;
162 }
163
165 friend bool operator!=(const MoveOnlyFunctionImpl& lhs, std::nullptr_t) noexcept
166 {
167 return lhs.activeDispatcherFunction_ != nullptr;
168 }
169
171 friend void swap(MoveOnlyFunctionImpl& lhs, MoveOnlyFunctionImpl& rhs) noexcept { lhs.swap(rhs); }
172
174 void swap(MoveOnlyFunctionImpl& other) noexcept
175 {
177 std::swap(activeDispatcherFunction_, other.activeDispatcherFunction_);
178 }
179
180private:
181 template <typename ParameterType>
182 using SanitizedParameterType = std::conditional_t<std::is_scalar_v<ParameterType>, ParameterType, ParameterType&&>;
183
184 template <typename Tp>
185 static ResultType dispatcherFunction(MoveOnlyFunctionBase GENERATE_WITH_CV* self,
186 SanitizedParameterType<ArgTypes>... args) noexcept(isNoExcept)
187 {
189 std::forward<Tp GENERATE_WITH_SELF_QUALIFIERS>(*getCallableAs<Tp GENERATE_WITH_CV>(self)),
190 std::forward<SanitizedParameterType<ArgTypes>>(args)...);
191 }
192
193 using DispatcherFunctionType = ResultType (*)(MoveOnlyFunctionBase GENERATE_WITH_CV*,
194 SanitizedParameterType<ArgTypes>...) noexcept(isNoExcept);
195 DispatcherFunctionType activeDispatcherFunction_ = nullptr;
196};
197
198} // namespace sen::std_util::detail
199
200#undef GENERATE_WITH_CV
201#undef GENERATE_WITH_REF
202#undef GENERATE_WITH_SELF_QUALIFIERS
203#undef NOEXCEPT_SPECIFIER
204#undef NOEXCEPT_SPECIALIZATION
Definition move_only_function.h:56
MoveOnlyFunctionBase() noexcept
Definition move_only_function.h:86
static constexpr bool isNothrowInit() noexcept
Returns true if the given CallableType can be initialized without throwing given the specified ArgTyp...
Definition move_only_function.h:60
void swap(MoveOnlyFunctionBase &other) noexcept
Definition move_only_function.h:128
void initializeCallable(ArgTypes &&... args) noexcept(isNothrowInit< CallableType, ArgTypes... >())
Definition move_only_function.h:94
MoveOnlyFunctionBase & operator=(MoveOnlyFunctionBase &&other) noexcept
Definition move_only_function.h:111
void swap(MoveOnlyFunctionImpl &other) noexcept
Swaps the target of the std::move_only_function objects.
Definition move_only_function_impl.h:174
friend bool operator==(const MoveOnlyFunctionImpl &lhs, std::nullptr_t) noexcept
Compares a std::move_only_function with nullptr.
Definition move_only_function_impl.h:159
MoveOnlyFunctionImpl(CallableType &&callable) noexcept(isNothrowInit< DecayedCallableType, CallableType >())
Definition move_only_function_impl.h:76
MoveOnlyFunctionImpl & operator=(std::nullptr_t) noexcept
Replaces or destroys the target.
Definition move_only_function_impl.h:139
ResultType operator()(ArgTypes... args) GENERATE_WITH_CV GENERATE_WITH_REF noexcept(isNoExcept)
Invokes the target.
Definition move_only_function_impl.h:149
MoveOnlyFunctionImpl(MoveOnlyFunctionImpl &&other) noexcept
Definition move_only_function_impl.h:63
friend bool operator!=(const MoveOnlyFunctionImpl &lhs, std::nullptr_t) noexcept
Compares a std::move_only_function with nullptr.
Definition move_only_function_impl.h:165
MoveOnlyFunctionImpl & operator=(MoveOnlyFunctionImpl &&other) noexcept
Definition move_only_function_impl.h:131
MoveOnlyFunctionImpl(std::in_place_type_t< CallableType >, std::initializer_list< ILArgTypes > initializeList, FunctionArgTypes &&... args) noexcept(isNothrowInit< CallableType, std::initializer_list< ILArgTypes > &, FunctionArgTypes... >())
Definition move_only_function_impl.h:120
MoveOnlyFunctionImpl(std::in_place_type_t< CallableType >, FunctionArgTypes &&... args) noexcept(isNothrowInit< CallableType, FunctionArgTypes... >())
Definition move_only_function_impl.h:104
friend void swap(MoveOnlyFunctionImpl &lhs, MoveOnlyFunctionImpl &rhs) noexcept
Specializes the std::swap algorithm.
Definition move_only_function_impl.h:171
#define GENERATE_WITH_REF
Definition move_only_function.h:219
#define GENERATE_WITH_CV
Definition move_only_function.h:218
#define NOEXCEPT_SPECIALIZATION
Definition move_only_function_impl.h:28
#define NOEXCEPT_SPECIFIER
Definition move_only_function_impl.h:27
Definition move_only_function_impl.h:21
constexpr bool is_move_only_function_v
Definition move_only_function.h:210
constexpr R invoke_r(F &&f, Args &&... args) noexcept(std::is_nothrow_invocable_r_v< R, F, Args... >)
Definition move_only_function.h:29
STL namespace.