-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement simple passthrough type that can enable custom destructor i…
…mplementations executed before proxied object. This proxy could also forward operator(), but frustratingly, it isn't sufficient to forward for types like `LocalObject`, because it would imply passing `const char*` which the InvocableMap can't see through in a constexpr way. I had hoped this coudl be used for a "non-deleting" LocalObject. See #207 for context. PiperOrigin-RevId: 574202123
- Loading branch information
1 parent
a2e21c6
commit 06fd124
Showing
3 changed files
with
152 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#ifndef JNI_BIND_METAPROGRAMMING_PASSTHROUGH_H_ | ||
#define JNI_BIND_METAPROGRAMMING_PASSTHROUGH_H_ | ||
|
||
#include <utility> | ||
|
||
namespace jni::metaprogramming { | ||
|
||
template <typename T> | ||
struct DefaultDeleter { | ||
static void Do(T&) {} | ||
}; | ||
|
||
template <typename T, typename CustomDeleter = DefaultDeleter<T>> | ||
struct Passthrough { | ||
template <typename... Ts> | ||
Passthrough(Ts... ts) : t_(std::forward<Ts>(ts)...) {} | ||
|
||
~Passthrough() { CustomDeleter::Do(t_); } | ||
|
||
T& operator*() { return t_; } | ||
T* operator->() { return &t_; } | ||
|
||
template <typename... Us> | ||
auto operator()(Us&&... us) { | ||
return t_(us...); | ||
} | ||
|
||
template <typename U> | ||
explicit operator U() const { | ||
return static_cast<U>(t_); | ||
} | ||
|
||
T t_; | ||
}; | ||
|
||
template <typename T, typename U, typename CustomDeleter> | ||
bool operator==(const T& lhs, const Passthrough<U, CustomDeleter>& rhs) { | ||
return lhs == static_cast<T>(rhs.t_); | ||
} | ||
|
||
template <typename T, typename U, typename CustomDeleter> | ||
bool operator==(const Passthrough<U, CustomDeleter>& lhs, const T& rhs) { | ||
return static_cast<T>(lhs.t_) == rhs; | ||
} | ||
|
||
template <typename T, typename U, typename CustomDeleter> | ||
bool operator!=(const T& lhs, const Passthrough<U, CustomDeleter>& rhs) { | ||
return !(lhs == rhs); | ||
} | ||
|
||
template <typename T, typename U, typename CustomDeleter> | ||
bool operator!=(const Passthrough<U, CustomDeleter>& lhs, const T& rhs) { | ||
return !(lhs == rhs); | ||
} | ||
|
||
} // namespace jni::metaprogramming | ||
|
||
#endif // JNI_BIND_METAPROGRAMMING_PASSTHROUGH_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
#include "metaprogramming/passthrough.h" | ||
|
||
#include <gtest/gtest.h> | ||
|
||
using ::jni::metaprogramming::Passthrough; | ||
|
||
template <typename T> | ||
struct ReleaseObjectRef { | ||
static void Do(T& t) { t.val_0 = 0xabababab; } | ||
}; | ||
|
||
static bool fail_happened = false; | ||
|
||
struct A { | ||
A() {} | ||
A(int val_0) : val_0(val_0) {} | ||
A(int val_0, int val_1) : val_0(val_0), val_1(val_1) {} | ||
A(int val_0, int val_1, int val_2) | ||
: val_0(val_0), val_1(val_1), val_2(val_2) {} | ||
|
||
int Sum() { return val_0 + val_1 + val_2; } | ||
|
||
void Foo() {} | ||
|
||
~A() { | ||
if (val_0 == 0xdeadbeef) { | ||
// never happens because custom dtor. | ||
fail_happened = true; | ||
} | ||
} | ||
|
||
int val_0 = 123; | ||
int val_1 = 456; | ||
int val_2 = 789; | ||
}; | ||
|
||
bool operator==(const A& lhs, const A& rhs) { | ||
return lhs.val_0 == rhs.val_0 && lhs.val_1 == rhs.val_1 && | ||
lhs.val_2 == rhs.val_2; | ||
} | ||
|
||
bool operator!=(A& lhs, A& rhs) { return !(lhs == rhs); } | ||
|
||
namespace { | ||
|
||
TEST(Passthrough, ConstructsI) { | ||
Passthrough<A> val{999}; | ||
EXPECT_EQ(val, (A{999})); | ||
} | ||
|
||
TEST(Passthrough, ConstructsII) { | ||
Passthrough<A> val{999, 888}; | ||
EXPECT_EQ(val, (A{999, 888})); | ||
} | ||
|
||
TEST(Passthrough, ConstructsIII) { | ||
Passthrough<A> val{999, 888, 777}; | ||
EXPECT_EQ(val, (A{999, 888, 777})); | ||
} | ||
|
||
TEST(Passthrough, PeersThroughPointer) { | ||
Passthrough<A> val{}; | ||
val->Foo(); | ||
} | ||
|
||
TEST(Passthrough, PeersThroughDereference) { | ||
Passthrough<A> val{}; | ||
(*val).Foo(); | ||
} | ||
|
||
TEST(Passthrough, CustomDtorIsInvoked) { | ||
{ Passthrough<A, ReleaseObjectRef<A>> val{0xdeadbeef}; } | ||
|
||
EXPECT_FALSE(fail_happened); | ||
|
||
{ Passthrough<A> val{0xdeadbeef}; } | ||
EXPECT_TRUE(fail_happened); | ||
} | ||
|
||
} // namespace |