Skip to content

Commit 8490cfa

Browse files
committed
Proxying now returns RefBase objects.
1 parent 40b9657 commit 8490cfa

File tree

5 files changed

+90
-48
lines changed

5 files changed

+90
-48
lines changed

implementation/field_ref.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ class FieldRef {
115115
void Set(T&& value) {
116116
FieldHelper<CDecl_t<typename IdT::RawValT>, IdT::kRank,
117117
IdT::kIsStatic>::SetValue(SelfVal(), GetFieldID(class_ref_),
118-
Proxy_t<T>::ProxyAsArg(
119-
std::forward<T>(value)));
118+
ForwardWithRefStrip(
119+
Proxy_t<T>::ProxyAsArg(
120+
std::forward<T>(value))));
120121
}
121122

122123
private:

implementation/overload_ref.h

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@
4141
#include "jni_dep.h"
4242
#include "metaprogramming/double_locked_value.h"
4343
#include "metaprogramming/string_concatenate.h"
44+
#include "implementation/id.h"
4445

4546
namespace jni {
46-
4747
// Transforms a OverloadRef IdT into a fully qualified ID. Storage is keyed
4848
// against these IDs to reduce excess MethodID lookups.
4949
template <typename IdT>
@@ -56,7 +56,7 @@ struct OverloadRefUniqueId {
5656
// Dashes are solely for readability in debugging.
5757
static constexpr std::string_view TypeName() {
5858
return metaprogramming::StringConcatenate_v<
59-
kClassQualifier, kDash, kOverloadName, kDash, Signature_v<IdT>>;
59+
kClassQualifier, kDash, kOverloadName, kDash, Signature_v<IdT>>;
6060
}
6161
};
6262

@@ -68,25 +68,25 @@ struct OverloadRef {
6868
using SelfIdT = typename IdT::template ChangeIdType<IdType::CLASS>;
6969

7070
using ReturnProxied = std::conditional_t<
71-
ReturnIdT::kIsSelf,
72-
Return_t<typename SelfIdT::MaterializeCDeclT, SelfIdT>,
73-
Return_t<typename ReturnIdT::MaterializeCDeclT, ReturnIdT>>;
71+
ReturnIdT::kIsSelf,
72+
Return_t<typename SelfIdT::MaterializeCDeclT, SelfIdT>,
73+
Return_t<typename ReturnIdT::MaterializeCDeclT, ReturnIdT>>;
7474

7575
static jmethodID GetMethodID(jclass clazz) {
7676
static auto get_lambda =
7777
[clazz](metaprogramming::DoubleLockedValue<jmethodID>* storage) {
78-
if (kConfiguration.release_method_ids_on_teardown_) {
79-
DefaultRefs<jmethodID>().push_back(storage);
80-
}
78+
if (kConfiguration.release_method_ids_on_teardown_) {
79+
DefaultRefs<jmethodID>().push_back(storage);
80+
}
8181

82-
if constexpr (IdT::kIsStatic) {
83-
return jni::JniHelper::GetStaticMethodID(clazz, IdT::Name(),
84-
Signature_v<IdT>.data());
85-
} else {
86-
return jni::JniHelper::GetMethodID(clazz, IdT::Name(),
87-
Signature_v<IdT>.data());
88-
}
89-
};
82+
if constexpr (IdT::kIsStatic) {
83+
return jni::JniHelper::GetStaticMethodID(clazz, IdT::Name(),
84+
Signature_v<IdT>.data());
85+
} else {
86+
return jni::JniHelper::GetMethodID(clazz, IdT::Name(),
87+
Signature_v<IdT>.data());
88+
}
89+
};
9090

9191
return RefStorage<decltype(get_lambda), OverloadRefUniqueId<IdT>>::Get(
9292
get_lambda);
@@ -102,30 +102,36 @@ struct OverloadRef {
102102
if constexpr (std::is_same_v<ReturnProxied, void>) {
103103
return InvokeHelper<void, kRank, kStatic>::Invoke(
104104
object, clazz, mthd,
105-
Proxy_t<Params>::ProxyAsArg(std::forward<Params>(params))...);
105+
ForwardWithRefStrip(Proxy_t<Params>::ProxyAsArg(
106+
std::forward<Params>(params)))...);
106107
} else if constexpr (IdT::kIsConstructor) {
107108
return ReturnProxied{
108109
AdoptLocal{},
109110
LifecycleHelper<jobject, LifecycleType::LOCAL>::Construct(
110111
clazz, mthd,
111-
Proxy_t<Params>::ProxyAsArg(std::forward<Params>(params))...)};
112+
ForwardWithRefStrip(
113+
Proxy_t<Params>::ProxyAsArg(
114+
std::forward<Params>(params)))...)};
112115
} else {
113116
if constexpr (std::is_base_of_v<RefBaseBase, ReturnProxied>) {
114117
return ReturnProxied{
115118
AdoptLocal{},
116119
InvokeHelper<typename ReturnIdT::CDecl, kRank, kStatic>::Invoke(
117120
object, clazz, mthd,
118-
Proxy_t<Params>::ProxyAsArg(std::forward<Params>(params))...)};
121+
ForwardWithRefStrip(
122+
Proxy_t<Params>::ProxyAsArg(std::forward<Params>(params)))
123+
...)};
119124
} else {
120125
return static_cast<ReturnProxied>(
121-
InvokeHelper<typename ReturnIdT::CDecl, kRank, kStatic>::Invoke(
122-
object, clazz, mthd,
123-
Proxy_t<Params>::ProxyAsArg(std::forward<Params>(params))...));
126+
InvokeHelper<typename ReturnIdT::CDecl, kRank, kStatic>::Invoke(
127+
object, clazz, mthd,
128+
ForwardWithRefStrip(
129+
Proxy_t<Params>::ProxyAsArg(
130+
std::forward<Params>(params)))...));
124131
}
125132
}
126133
}
127134
};
135+
} // namespace jni
128136

129-
} // namespace jni
130-
131-
#endif // JNI_BIND_OVERLOAD_REF_H
137+
#endif // JNI_BIND_OVERLOAD_REF_H

implementation/proxy_definitions_string.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
#include "jni_dep.h"
3838

3939
namespace jni {
40-
4140
template <typename JString>
4241
struct Proxy<JString,
4342
typename std::enable_if_t<std::is_same_v<JString, jstring>>>
@@ -72,36 +71,37 @@ struct Proxy<JString,
7271
// correctly release local instances, but here we are stripping that so it can
7372
// be used in a method. This could be obviated by wrapping the calling scope
7473
// in a local stack frame.
75-
static jstring ProxyAsArg(jstring s) { return s; }
74+
static RefBase<jstring> ProxyAsArg(jstring s) {
75+
return {s};
76+
}
7677

7778
template <typename T,
7879
typename = std::enable_if_t<std::is_same_v<T, const char*> ||
7980
std::is_same_v<T, std::string> ||
8081
std::is_same_v<T, std::string_view>>>
81-
static jstring ProxyAsArg(T s) {
82+
static RefBase<jstring> ProxyAsArg(T s) {
8283
if constexpr (std::is_same_v<T, const char*>) {
83-
return LifecycleHelper<jstring, LifecycleType::LOCAL>::Construct(s);
84+
return {LifecycleHelper<jstring, LifecycleType::LOCAL>::Construct(s)};
8485
} else {
85-
return LifecycleHelper<jstring, LifecycleType::LOCAL>::Construct(
86-
s.data());
86+
return {LifecycleHelper<jstring, LifecycleType::LOCAL>::Construct(
87+
s.data())};
8788
}
8889
}
8990

9091
template <typename T,
9192
typename = std::enable_if_t<std::is_same_v<T, GlobalString> ||
9293
std::is_same_v<T, LocalString>>>
93-
static jstring ProxyAsArg(T& t) {
94-
return jstring{t};
94+
static RefBase<jstring> ProxyAsArg(T& t) {
95+
return {std::move(t)};
9596
}
9697

9798
template <typename T,
9899
typename = std::enable_if_t<std::is_same_v<T, GlobalString> ||
99100
std::is_same_v<T, LocalString>>>
100-
static jstring ProxyAsArg(T&& t) {
101-
return t.Release();
101+
static RefBase<jstring> ProxyAsArg(T&& t) {
102+
return {std::move(t)};
102103
}
103104
};
104-
105-
} // namespace jni
105+
} // namespace jni
106106

107107
#endif // JNI_BIND_IMPLEMENTATION_PROXY_DEFINITIONS_STRING_H_

implementation/ref_base.h

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,23 @@
2424
#include "implementation/jni_helper/lifecycle.h"
2525

2626
namespace jni {
27-
28-
struct RefBaseBase {};
27+
struct RefBaseBase {
28+
};
2929

3030
// Used to detect RefBase in type proxying.
3131
// This is useful, e.g. when you want to say "an object that might be passed"
3232
// but the object's type (i.e. full name + loader information) is unknown.
33-
template <typename StorageType>
33+
template <typename StorageType_>
3434
class RefBase : public RefBaseBase {
35-
public:
35+
public:
3636
template <typename Base, LifecycleType lifecycleType, typename JniT,
3737
typename ViableSpan>
3838
friend struct EntryBase;
3939

40-
RefBase(StorageType object) : object_ref_(object) {}
40+
using StorageType = StorageType_;
41+
42+
RefBase(StorageType object) : object_ref_(object) {
43+
}
4144

4245
RefBase(const RefBase& rhs) = delete;
4346

@@ -48,7 +51,8 @@ class RefBase : public RefBaseBase {
4851

4952
template <typename T,
5053
typename = std::enable_if_t<std::is_same_v<T, StorageType>>>
51-
RefBase(RefBase<T>&& rhs) : object_ref_(rhs.Release()) {}
54+
RefBase(RefBase<T>&& rhs) : object_ref_(rhs.Release()) {
55+
}
5256

5357
// Releases ownership of the underlying object, further use is undefined.
5458
StorageType Release() {
@@ -57,16 +61,46 @@ class RefBase : public RefBaseBase {
5761

5862
return return_value;
5963
}
60-
explicit operator StorageType() const { return object_ref_; }
6164

62-
protected:
65+
explicit operator StorageType() const {
66+
return object_ref_;
67+
}
68+
69+
protected:
6370
StorageType object_ref_ = nullptr;
6471
};
6572

6673
//==============================================================================
6774
template <typename T>
6875
using RefBaseT_t = typename T::RefBaseT;
6976

70-
} // namespace jni
77+
template <typename T>
78+
using RefBaseStorageT_t = typename T::StorageType;
79+
80+
//==============================================================================
81+
82+
namespace detail {
83+
template <typename T>
84+
auto ForwardWithRefStripImpl(T&& t, std::true_type /* is_ref_base */) {
85+
using U = std::remove_reference_t<T>;
86+
using CastT = RefBaseStorageT_t<U>;
87+
return CastT(std::forward<T>(t)); // return by value, move or copy
88+
}
89+
90+
template <typename T>
91+
decltype(auto) ForwardWithRefStripImpl(
92+
T&& t, std::false_type /* not ref base */) {
93+
return std::forward<T>(t); // perfect forward
94+
}
95+
} // namespace detail
96+
97+
template <typename T>
98+
decltype(auto) ForwardWithRefStrip(T&& t) {
99+
using U = std::remove_reference_t<T>;
100+
return detail::ForwardWithRefStripImpl(
101+
std::forward<T>(t),
102+
std::is_base_of<RefBaseBase, U>{});
103+
}
104+
} // namespace jni
71105

72106
#endif // JNI_BIND_REF_BASE_H_

jni_test.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ class JniTestWithNoDefaultJvmRef : public ::testing::Test {
111111
ON_CALL(*env_, GetFieldID).WillByDefault(Return(Fake<jfieldID>()));
112112
ON_CALL(*env_, NewObjectArray).WillByDefault(Return(Fake<jobjectArray>()));
113113
ON_CALL(*env_, NewObjectV).WillByDefault(Return(Fake<jobject>()));
114+
ON_CALL(*env_, NewStringUTF).WillByDefault(Return(Fake<jstring>()));
114115

115116
ON_CALL(*env_, NewLocalRef)
116117
.WillByDefault(testing::Invoke(

0 commit comments

Comments
 (0)