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 // prevent compilers from trying to compare a reference to a function to a pointer
82 if constexpr (!std::is_reference_v<CallableType>)
83 {
84 if (callable == nullptr)
85 {
86 return;
87 }
88 }
89 }
90 initializeCallable<DecayedCallableType>(std::forward<CallableType>(callable));
91 activeDispatcherFunction_ = &dispatcherFunction<DecayedCallableType>;
92 }
93
94 template <typename CallableType,
95 typename... FunctionArgTypes,
96 std::enable_if_t<std::conjunction_v<std::is_constructible<CallableType, FunctionArgTypes...>,
97 is_qualified_callable<CallableType>>,
98 bool> = true>
99 explicit MoveOnlyFunctionImpl(std::in_place_type_t<CallableType> /*unused*/,
100 FunctionArgTypes&&... args) noexcept(isNothrowInit<CallableType, FunctionArgTypes...>())
101 : activeDispatcherFunction_(&dispatcherFunction<CallableType>)
102 {
103 static_assert(std::is_same_v<std::decay_t<CallableType>, CallableType>);
104 initializeCallable<CallableType>(std::forward<FunctionArgTypes>(args)...);
105 }
106
107 template <
108 typename CallableType,
109 typename ILArgTypes,
110 typename... FunctionArgTypes,
111 std::enable_if_t<
112 std::conjunction_v<std::is_constructible<CallableType, std::initializer_list<ILArgTypes>&, FunctionArgTypes...>,
113 is_qualified_callable<CallableType>>,
114 bool> = true>
115 explicit MoveOnlyFunctionImpl(std::in_place_type_t<CallableType> /*unused*/,
116 std::initializer_list<ILArgTypes> initializeList,
117 FunctionArgTypes&&... args) noexcept(isNothrowInit<CallableType,
118 std::initializer_list<ILArgTypes>&,
119 FunctionArgTypes...>())
120 : activeDispatcherFunction_(&dispatcherFunction<CallableType>)
121 {
122 static_assert(std::is_same_v<std::decay_t<CallableType>, CallableType>);
123 initializeCallable<CallableType>(initializeList, std::forward<FunctionArgTypes>(args)...);
124 }
125
127 {
129 activeDispatcherFunction_ = std::exchange(other.activeDispatcherFunction_, nullptr);
130 return *this;
131 }
132
134 MoveOnlyFunctionImpl& operator=(std::nullptr_t) noexcept
135 {
137 activeDispatcherFunction_ = nullptr;
138 return *this;
139 }
140
142
144 ResultType operator()(ArgTypes... args) GENERATE_WITH_CV GENERATE_WITH_REF noexcept(isNoExcept)
145 {
146 assert(*this != nullptr && "Trying to execute empty callable object.");
147 return activeDispatcherFunction_(this, std::forward<ArgTypes>(args)...);
148 }
149
151 explicit operator bool() const noexcept { return activeDispatcherFunction_ != nullptr; }
152
154 friend bool operator==(const MoveOnlyFunctionImpl& lhs, std::nullptr_t) noexcept
155 {
156 return lhs.activeDispatcherFunction_ == nullptr;
157 }
158
160 friend bool operator!=(const MoveOnlyFunctionImpl& lhs, std::nullptr_t) noexcept
161 {
162 return lhs.activeDispatcherFunction_ != nullptr;
163 }
164
166 friend void swap(MoveOnlyFunctionImpl& lhs, MoveOnlyFunctionImpl& rhs) noexcept { lhs.swap(rhs); }
167
169 void swap(MoveOnlyFunctionImpl& other) noexcept
170 {
172 std::swap(activeDispatcherFunction_, other.activeDispatcherFunction_);
173 }
174
175private:
176 template <typename ParameterType>
177 using SanitizedParameterType = std::conditional_t<std::is_scalar_v<ParameterType>, ParameterType, ParameterType&&>;
178
179 template <typename Tp>
180 static ResultType dispatcherFunction(MoveOnlyFunctionBase GENERATE_WITH_CV* self,
181 SanitizedParameterType<ArgTypes>... args) noexcept(isNoExcept)
182 {
184 std::forward<Tp GENERATE_WITH_SELF_QUALIFIERS>(*getCallableAs<Tp GENERATE_WITH_CV>(self)),
185 std::forward<SanitizedParameterType<ArgTypes>>(args)...);
186 }
187
188 using DispatcherFunctionType = ResultType (*)(MoveOnlyFunctionBase GENERATE_WITH_CV*,
189 SanitizedParameterType<ArgTypes>...) noexcept(isNoExcept);
190 DispatcherFunctionType activeDispatcherFunction_ = nullptr;
191};
192
193} // namespace sen::std_util::detail
194
195#undef GENERATE_WITH_CV
196#undef GENERATE_WITH_REF
197#undef GENERATE_WITH_SELF_QUALIFIERS
198#undef NOEXCEPT_SPECIFIER
199#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:169
friend bool operator==(const MoveOnlyFunctionImpl &lhs, std::nullptr_t) noexcept
Compares a std::move_only_function with nullptr.
Definition move_only_function_impl.h:154
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:134
ResultType operator()(ArgTypes... args) GENERATE_WITH_CV GENERATE_WITH_REF noexcept(isNoExcept)
Invokes the target.
Definition move_only_function_impl.h:144
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:160
MoveOnlyFunctionImpl & operator=(MoveOnlyFunctionImpl &&other) noexcept
Definition move_only_function_impl.h:126
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:115
MoveOnlyFunctionImpl(std::in_place_type_t< CallableType >, FunctionArgTypes &&... args) noexcept(isNothrowInit< CallableType, FunctionArgTypes... >())
Definition move_only_function_impl.h:99
friend void swap(MoveOnlyFunctionImpl &lhs, MoveOnlyFunctionImpl &rhs) noexcept
Specializes the std::swap algorithm.
Definition move_only_function_impl.h:166
#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.