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// No include guard, on purpose: move_only_function.h includes this file once per combination of
9// GENERATE_WITH_CV and GENERATE_WITH_REF to stamp out each specialization. A guard would keep the
10// first and silently drop the rest.
11
12// NOLINTBEGIN(misc-include-cleaner)
13// Due to the include stamping trick, the checker gets confused here
14
15// sen
17
18// std
19#include <cassert>
20#include <initializer_list>
21#include <type_traits>
22// NOLINTEND(misc-include-cleaner)
23
25{
26
27#if defined(_MSC_VER)
28# define NOEXCEPT_SPECIFIER
29# define NOEXCEPT_SPECIALIZATION
30#else
31# define NOEXCEPT_SPECIFIER noexcept(IsNoExcept)
32# define NOEXCEPT_SPECIALIZATION , bool IsNoExcept
33#endif
34
35template <typename ResultType, typename... ArgTypes NOEXCEPT_SPECIALIZATION>
36// NOLINTNEXTLINE: prevent confusing between ArgType matching and a c-style cast
38 : private MoveOnlyFunctionBase
39{
40#if defined(_MSC_VER)
41 // TODO (SEN-1001): implement noexcept detection/specialization support for windows
42 static constexpr bool isNoExcept = false;
43#else
44 static constexpr bool isNoExcept = IsNoExcept;
45#endif
46
47 template <typename CallableType>
48 // NOLINTNEXTLINE(readability-identifier-naming): follows standard concept naming
49 using is_callable = std::conditional_t<isNoExcept,
50 std::is_nothrow_invocable_r<ResultType, CallableType, ArgTypes...>,
51 std::is_invocable_r<ResultType, CallableType, ArgTypes...>>;
52
53 template <typename UnqualifiedCallableType>
54 // NOLINTNEXTLINE(readability-identifier-naming): extends standard concept naming
55 using is_qualified_callable =
56 std::conjunction<is_callable<UnqualifiedCallableType GENERATE_WITH_CV GENERATE_WITH_REF>,
57 is_callable<UnqualifiedCallableType GENERATE_WITH_SELF_QUALIFIERS>>;
58
59public:
60 using result_type = ResultType; // NOLINT(readability-identifier-naming): requested by the standard
61
62 MoveOnlyFunctionImpl() noexcept = default;
63
64 // NOLINTNEXTLINE(hicpp-explicit-conversions): needed for automatic nullptr comparisions
65 MoveOnlyFunctionImpl(std::nullptr_t) noexcept {}
66
68 : MoveOnlyFunctionBase(static_cast<MoveOnlyFunctionBase&&>(other))
69 , activeDispatcherFunction_(std::exchange(other.activeDispatcherFunction_, nullptr))
70 {
71 }
72
73 template <typename CallableType,
74 typename DecayedCallableType = std::decay_t<CallableType>,
75 std::enable_if_t<std::conjunction_v<std::negation<std::is_same<DecayedCallableType, MoveOnlyFunctionImpl>>,
76 std::negation<IsInPlaceType<DecayedCallableType>>,
77 is_qualified_callable<DecayedCallableType>>,
78 bool> = true>
79 // NOLINTNEXTLINE(hicpp-explicit-conversions): required by the standard
81 {
82 if constexpr (std::is_function_v<std::remove_pointer_t<DecayedCallableType>> ||
83 std::is_member_pointer_v<DecayedCallableType> || is_move_only_function_v<DecayedCallableType>)
84 {
85 // prevent compilers from trying to compare a reference to a function to a pointer
86 if constexpr (!std::is_reference_v<CallableType>)
87 {
88 if (callable == nullptr)
89 {
90 return;
91 }
92 }
93 }
94 initializeCallable<DecayedCallableType>(std::forward<CallableType>(callable));
95 activeDispatcherFunction_ = &dispatcherFunction<DecayedCallableType>;
96 }
97
98 template <typename CallableType,
99 typename... FunctionArgTypes,
100 std::enable_if_t<std::conjunction_v<std::is_constructible<CallableType, FunctionArgTypes...>,
101 is_qualified_callable<CallableType>>,
102 bool> = true>
103 explicit MoveOnlyFunctionImpl(std::in_place_type_t<CallableType> /*unused*/,
104 FunctionArgTypes&&... args) noexcept(isNothrowInit<CallableType, FunctionArgTypes...>())
105 : activeDispatcherFunction_(&dispatcherFunction<CallableType>)
106 {
107 static_assert(std::is_same_v<std::decay_t<CallableType>, CallableType>);
108 initializeCallable<CallableType>(std::forward<FunctionArgTypes>(args)...);
109 }
110
111 template <
112 typename CallableType,
113 typename ILArgTypes,
114 typename... FunctionArgTypes,
115 std::enable_if_t<
116 std::conjunction_v<std::is_constructible<CallableType, std::initializer_list<ILArgTypes>&, FunctionArgTypes...>,
117 is_qualified_callable<CallableType>>,
118 bool> = true>
119 explicit MoveOnlyFunctionImpl(std::in_place_type_t<CallableType> /*unused*/,
120 std::initializer_list<ILArgTypes> initializeList,
121 FunctionArgTypes&&... args) noexcept(isNothrowInit<CallableType,
122 std::initializer_list<ILArgTypes>&,
123 FunctionArgTypes...>())
124 : activeDispatcherFunction_(&dispatcherFunction<CallableType>)
125 {
126 static_assert(std::is_same_v<std::decay_t<CallableType>, CallableType>);
127 initializeCallable<CallableType>(initializeList, std::forward<FunctionArgTypes>(args)...);
128 }
129
131 {
133 activeDispatcherFunction_ = std::exchange(other.activeDispatcherFunction_, nullptr);
134 return *this;
135 }
136
138 MoveOnlyFunctionImpl& operator=(std::nullptr_t) noexcept
139 {
141 activeDispatcherFunction_ = nullptr;
142 return *this;
143 }
144
146
148 ResultType operator()(ArgTypes... args) GENERATE_WITH_CV GENERATE_WITH_REF noexcept(isNoExcept)
149 {
150 assert(*this != nullptr && "Trying to execute empty callable object.");
151 return activeDispatcherFunction_(this, std::forward<ArgTypes>(args)...);
152 }
153
155 explicit operator bool() const noexcept { return activeDispatcherFunction_ != nullptr; }
156
158 friend bool operator==(const MoveOnlyFunctionImpl& lhs, std::nullptr_t) noexcept
159 {
160 return lhs.activeDispatcherFunction_ == nullptr;
161 }
162
164 friend bool operator!=(const MoveOnlyFunctionImpl& lhs, std::nullptr_t) noexcept
165 {
166 return lhs.activeDispatcherFunction_ != nullptr;
167 }
168
170 friend void swap(MoveOnlyFunctionImpl& lhs, MoveOnlyFunctionImpl& rhs) noexcept { lhs.swap(rhs); }
171
173 void swap(MoveOnlyFunctionImpl& other) noexcept
174 {
176 std::swap(activeDispatcherFunction_, other.activeDispatcherFunction_);
177 }
178
179private:
180 template <typename ParameterType>
181 using SanitizedParameterType = std::conditional_t<std::is_scalar_v<ParameterType>, ParameterType, ParameterType&&>;
182
183 template <typename Tp>
184 static ResultType dispatcherFunction(MoveOnlyFunctionBase GENERATE_WITH_CV* self,
185 SanitizedParameterType<ArgTypes>... args) noexcept(isNoExcept)
186 {
188 std::forward<Tp GENERATE_WITH_SELF_QUALIFIERS>(*getCallableAs<Tp GENERATE_WITH_CV>(self)),
189 std::forward<SanitizedParameterType<ArgTypes>>(args)...);
190 }
191
192 using DispatcherFunctionType = ResultType (*)(MoveOnlyFunctionBase GENERATE_WITH_CV*,
193 SanitizedParameterType<ArgTypes>...) noexcept(isNoExcept);
194 DispatcherFunctionType activeDispatcherFunction_ = nullptr;
195};
196
197} // namespace sen::std_util::detail
198
199#undef GENERATE_WITH_CV
200#undef GENERATE_WITH_REF
201#undef GENERATE_WITH_SELF_QUALIFIERS
202#undef NOEXCEPT_SPECIFIER
203#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:173
friend bool operator==(const MoveOnlyFunctionImpl &lhs, std::nullptr_t) noexcept
Compares a std::move_only_function with nullptr.
Definition move_only_function_impl.h:158
MoveOnlyFunctionImpl(CallableType &&callable) noexcept(isNothrowInit< DecayedCallableType, CallableType >())
Definition move_only_function_impl.h:80
MoveOnlyFunctionImpl & operator=(std::nullptr_t) noexcept
Replaces or destroys the target.
Definition move_only_function_impl.h:138
ResultType operator()(ArgTypes... args) GENERATE_WITH_CV GENERATE_WITH_REF noexcept(isNoExcept)
Invokes the target.
Definition move_only_function_impl.h:148
MoveOnlyFunctionImpl(MoveOnlyFunctionImpl &&other) noexcept
Definition move_only_function_impl.h:67
friend bool operator!=(const MoveOnlyFunctionImpl &lhs, std::nullptr_t) noexcept
Compares a std::move_only_function with nullptr.
Definition move_only_function_impl.h:164
MoveOnlyFunctionImpl & operator=(MoveOnlyFunctionImpl &&other) noexcept
Definition move_only_function_impl.h:130
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:119
MoveOnlyFunctionImpl(std::in_place_type_t< CallableType >, FunctionArgTypes &&... args) noexcept(isNothrowInit< CallableType, FunctionArgTypes... >())
Definition move_only_function_impl.h:103
friend void swap(MoveOnlyFunctionImpl &lhs, MoveOnlyFunctionImpl &rhs) noexcept
Specializes the std::swap algorithm.
Definition move_only_function_impl.h:170
#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:32
#define NOEXCEPT_SPECIFIER
Definition move_only_function_impl.h:31
Definition move_only_function_impl.h:25
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.