Skip to content

Commit 352ddc9

Browse files
committed
Test pointer and template lambdas with Fn/Mut/Once
The pointer path can't be constexpr unfortunately, but you can always wrap the pointer in a lambda to make it constexpr if needed.
1 parent acd6067 commit 352ddc9

File tree

4 files changed

+80
-26
lines changed

4 files changed

+80
-26
lines changed

subspace/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ target_sources(subspace PUBLIC
5151
"fn/bind.h"
5252
"fn/box_fn_defn.h"
5353
"fn/box_fn_impl.h"
54-
"fn/stackfn_defn.h"
54+
"fn/fn_defn.h"
5555
"iter/__private/into_iterator_archetype.h"
5656
"iter/__private/iterator_end.h"
5757
"iter/__private/iterator_loop.h"
@@ -152,7 +152,7 @@ add_executable(subspace_unittests
152152
"construct/into_unittest.cc"
153153
"construct/default_unittest.cc"
154154
"fn/box_fn_unittest.cc"
155-
"fn/stackfn_unittest.cc"
155+
"fn/fn_unittest.cc"
156156
"iter/iterator_unittest.cc"
157157
"mem/addressof_unittest.cc"
158158
"mem/clone_unittest.cc"

subspace/fn/fn.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@
1717
#include "subspace/fn/bind.h"
1818
#include "subspace/fn/box_fn_defn.h"
1919
#include "subspace/fn/box_fn_impl.h"
20-
#include "subspace/fn/stackfn_defn.h"
20+
#include "subspace/fn/fn_defn.h"

subspace/fn/stackfn_defn.h renamed to subspace/fn/fn_defn.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ template <class F>
5353
struct Invoker {
5454
template <class R, class... Args>
5555
static R fnptr_call_mut(const union Storage& s, Args... args) {
56-
F f = static_cast<F>(s.fnptr);
56+
F f = reinterpret_cast<F>(s.fnptr);
5757
return (*f)(::sus::forward<Args>(args)...);
5858
}
5959

@@ -65,7 +65,7 @@ struct Invoker {
6565

6666
template <class R, class... Args>
6767
static R fnptr_call_const(const union Storage& s, Args... args) {
68-
const F f = static_cast<const F>(s.fnptr);
68+
const F f = reinterpret_cast<const F>(s.fnptr);
6969
return (*f)(::sus::forward<Args>(args)...);
7070
}
7171

@@ -131,9 +131,9 @@ class [[sus_trivial_abi]] Fn<R(CallArgs...)> {
131131
///
132132
/// #[doc.overloads=ctor.fnpointer]
133133
template <__private::FunctionPointer<R, CallArgs...> F>
134-
constexpr Fn(F ptr) noexcept {
134+
Fn(F ptr) noexcept {
135135
::sus::check(ptr != nullptr);
136-
storage_.fnptr = static_cast<void (*)()>(ptr);
136+
storage_.fnptr = reinterpret_cast<void (*)()>(ptr);
137137
invoke_ = &__private::Invoker<F>::template fnptr_call_const<R, CallArgs...>;
138138
}
139139

@@ -253,9 +253,9 @@ class [[sus_trivial_abi]] FnMut<R(CallArgs...)> {
253253
///
254254
/// #[doc.overloads=ctor.fnpointer]
255255
template <__private::FunctionPointer<R, CallArgs...> F>
256-
constexpr FnMut(F ptr) noexcept {
256+
FnMut(F ptr) noexcept {
257257
::sus::check(ptr != nullptr);
258-
storage_.fnptr = static_cast<void (*)()>(ptr);
258+
storage_.fnptr = reinterpret_cast<void (*)()>(ptr);
259259
invoke_ = &__private::Invoker<F>::template fnptr_call_mut<R, CallArgs...>;
260260
}
261261

@@ -332,7 +332,7 @@ class [[sus_trivial_abi]] FnMut<R(CallArgs...)> {
332332
friend class FnOnce;
333333

334334
constexpr FnMut(union __private::Storage storage,
335-
__private::InvokeFnPtr<R, CallArgs...> invoke)
335+
__private::InvokeFnPtr<R, CallArgs...> invoke)
336336
: storage_(storage), invoke_(invoke) {}
337337

338338
union __private::Storage storage_;
@@ -383,9 +383,9 @@ class [[sus_trivial_abi]] FnOnce<R(CallArgs...)> {
383383
///
384384
/// #[doc.overloads=ctor.fnpointer]
385385
template <__private::FunctionPointer<R, CallArgs...> F>
386-
constexpr FnOnce(F ptr) noexcept {
386+
FnOnce(F ptr) noexcept {
387387
::sus::check(ptr != nullptr);
388-
storage_.fnptr = static_cast<void (*)()>(ptr);
388+
storage_.fnptr = reinterpret_cast<void (*)()>(ptr);
389389
invoke_ = &__private::Invoker<F>::template fnptr_call_mut<R, CallArgs...>;
390390
}
391391

subspace/fn/stackfn_unittest.cc renamed to subspace/fn/fn_unittest.cc

Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
#include "subspace/fn/fn.h"
16+
1517
#include <concepts>
1618

1719
#include "googletest/include/gtest/gtest.h"
1820
#include "subspace/construct/into.h"
19-
#include "subspace/fn/fn.h"
2021
#include "subspace/mem/forward.h"
2122
#include "subspace/mem/move.h"
2223
#include "subspace/mem/replace.h"
@@ -116,9 +117,9 @@ static_assert(sus::mem::relocate_by_memcpy<Fn<void()>>);
116117
static_assert(std::is_constructible_v<FnOnce<void()>, decltype([]() {})>);
117118
static_assert(std::is_constructible_v<FnMut<void()>, decltype([]() {})>);
118119
static_assert(std::is_constructible_v<Fn<void()>, decltype([]() {})>);
119-
static_assert(std::is_constructible_v<FnOnce<void()>, decltype(&v_v_function)>);
120-
static_assert(std::is_constructible_v<FnMut<void()>, decltype(&v_v_function)>);
121-
static_assert(std::is_constructible_v<Fn<void()>, decltype(&v_v_function)>);
120+
static_assert(std::is_constructible_v<FnOnce<void()>, decltype(v_v_function)>);
121+
static_assert(std::is_constructible_v<FnMut<void()>, decltype(v_v_function)>);
122+
static_assert(std::is_constructible_v<Fn<void()>, decltype(v_v_function)>);
122123
// Non-void types for the same.
123124
static_assert(std::is_constructible_v<FnOnce<int(float)>,
124125
decltype([](float) { return 1; })>);
@@ -127,10 +128,10 @@ static_assert(std::is_constructible_v<FnMut<int(float)>,
127128
static_assert(
128129
std::is_constructible_v<Fn<int(float)>, decltype([](float) { return 1; })>);
129130
static_assert(
130-
std::is_constructible_v<FnOnce<int(float)>, decltype(&i_f_function)>);
131+
std::is_constructible_v<FnOnce<int(float)>, decltype(i_f_function)>);
131132
static_assert(
132-
std::is_constructible_v<FnMut<int(float)>, decltype(&i_f_function)>);
133-
static_assert(std::is_constructible_v<Fn<int(float)>, decltype(&i_f_function)>);
133+
std::is_constructible_v<FnMut<int(float)>, decltype(i_f_function)>);
134+
static_assert(std::is_constructible_v<Fn<int(float)>, decltype(i_f_function)>);
134135
// Lambdas with bound args can be bound to FnOnce, FnMut and Fn.
135136
static_assert(std::is_constructible_v<FnOnce<void()>,
136137
decltype([i = int(1)]() { (void)i; })>);
@@ -148,11 +149,11 @@ static_assert(std::is_constructible_v<
148149
// The return type of the FnOnce must match that of the lambda. It will not
149150
// allow converting to void.
150151
static_assert(std::is_constructible_v<FnOnce<SubClass*(BaseClass*)>,
151-
decltype(&s_b_function)>);
152-
static_assert(!std::is_constructible_v<FnOnce<void(BaseClass*)>,
153-
decltype(&b_b_function)>);
152+
decltype(s_b_function)>);
153+
static_assert(
154+
!std::is_constructible_v<FnOnce<void(BaseClass*)>, decltype(b_b_function)>);
154155
static_assert(!std::is_constructible_v<FnOnce<SubClass*(BaseClass*)>,
155-
decltype(&b_b_function)>);
156+
decltype(b_b_function)>);
156157
static_assert(std::is_constructible_v<FnOnce<SubClass*(BaseClass*)>,
157158
decltype(s_b_lambda)>);
158159
static_assert(
@@ -161,9 +162,9 @@ static_assert(!std::is_constructible_v<FnOnce<SubClass*(BaseClass*)>,
161162
decltype(b_b_lambda)>);
162163
// Similarly, argument types can't be converted to a different type.
163164
static_assert(std::is_constructible_v<FnOnce<SubClass*(SubClass*)>,
164-
decltype(&s_s_function)>);
165+
decltype(s_s_function)>);
165166
static_assert(!std::is_constructible_v<FnOnce<SubClass*(BaseClass*)>,
166-
decltype(&s_s_function)>);
167+
decltype(s_s_function)>);
167168
static_assert(std::is_constructible_v<FnOnce<SubClass*(SubClass*)>,
168169
decltype(s_s_lambda)>);
169170
static_assert(!std::is_constructible_v<FnOnce<SubClass*(BaseClass*)>,
@@ -234,6 +235,34 @@ static_assert(!can_run<void, int&, int&&>);
234235
static_assert(!can_run<void, int&, const int&&>);
235236

236237
TEST(Fn, Pointer) {
238+
{
239+
auto receive_fn = [](FnOnce<i32(i32, i32)> f, i32 a, i32 b) {
240+
return sus::move(f)(a, b);
241+
};
242+
auto* ptr = +[](i32 a, i32 b) { return a * 2 + b; };
243+
EXPECT_EQ(receive_fn(ptr, 1, 2), 4);
244+
}
245+
{
246+
auto receive_fn = [](FnMut<i32(i32, i32)> f, i32 a, i32 b) {
247+
f(a, b);
248+
return sus::move(f)(a, b);
249+
};
250+
auto* ptr = +[](i32 a, i32 b) { return a * 2 + b; };
251+
EXPECT_EQ(receive_fn(ptr, 1, 2), 4);
252+
}
253+
{
254+
{
255+
auto receive_fn = [](Fn<i32(i32, i32)> f, i32 a, i32 b) {
256+
f(a, b);
257+
return sus::move(f)(a, b);
258+
};
259+
auto* ptr = +[](i32 a, i32 b) { return a * 2 + b; };
260+
EXPECT_EQ(receive_fn(ptr, 1, 2), 4);
261+
}
262+
}
263+
}
264+
265+
TEST(Fn, CapturelessLambda) {
237266
{
238267
auto receive_fn = [](FnOnce<i32(i32, i32)> f, i32 a, i32 b) {
239268
return sus::move(f)(a, b);
@@ -291,7 +320,32 @@ TEST(Fn, Lambda) {
291320
}
292321
}
293322

294-
void g() {}
323+
TEST(Fn, TemplateLambda) {
324+
{
325+
auto receive_fn = [](FnOnce<i32(i32)> f, i32 b) { return sus::move(f)(b); };
326+
auto lambda = [a = 1_i32](auto b) { return a * 2 + b; };
327+
EXPECT_EQ(receive_fn(lambda, 2), 4);
328+
}
329+
{
330+
auto receive_fn = [](FnMut<i32(i32)> f, i32 b) {
331+
f(b);
332+
return sus::move(f)(b);
333+
};
334+
auto lambda = [a = 1_i32](auto b) mutable {
335+
a += 1;
336+
return a * 2 + b;
337+
};
338+
EXPECT_EQ(receive_fn(lambda, 2), 8);
339+
}
340+
{
341+
auto receive_fn = [](Fn<i32(i32)> f, i32 b) {
342+
f(b);
343+
return sus::move(f)(b);
344+
};
345+
auto lambda = [a = 1_i32](auto b) { return a * 2 + b; };
346+
EXPECT_EQ(receive_fn(lambda, 2), 4);
347+
}
348+
}
295349

296350
TEST(FnDeathTest, NullPointer) {
297351
void (*f)() = nullptr;

0 commit comments

Comments
 (0)