@@ -29,11 +29,59 @@ class BaseHybridClass {
29
29
30
30
struct FBEXPORT HybridData : public JavaClass<HybridData> {
31
31
constexpr static auto kJavaDescriptor = " Lcom/facebook/jni/HybridData;" ;
32
- void setNativePointer (std::unique_ptr<BaseHybridClass> new_value);
33
- BaseHybridClass* getNativePointer ();
34
32
static local_ref<HybridData> create ();
35
33
};
36
34
35
+ class HybridDestructor : public JavaClass <HybridDestructor> {
36
+ public:
37
+ static auto constexpr kJavaDescriptor = " Lcom/facebook/jni/HybridData$Destructor;" ;
38
+
39
+ template <typename T=detail::BaseHybridClass>
40
+ T* getNativePointer () {
41
+ static auto pointerField = javaClassStatic ()->getField <jlong>(" mNativePointer" );
42
+ auto * value = reinterpret_cast <detail::BaseHybridClass*>(getFieldValue (pointerField));
43
+ if (!value) {
44
+ throwNewJavaException (" java/lang/NullPointerException" , " java.lang.NullPointerException" );
45
+ }
46
+ return value;
47
+ }
48
+
49
+ template <typename T=detail::BaseHybridClass>
50
+ void setNativePointer (std::unique_ptr<T> new_value) {
51
+ static auto pointerField = javaClassStatic ()->getField <jlong>(" mNativePointer" );
52
+ auto old_value = std::unique_ptr<T>(reinterpret_cast <T*>(getFieldValue (pointerField)));
53
+ if (new_value && old_value) {
54
+ FBCRASH (" Attempt to set C++ native pointer twice" );
55
+ }
56
+ setFieldValue (pointerField, reinterpret_cast <jlong>(new_value.release ()));
57
+ }
58
+ };
59
+
60
+ template <typename T>
61
+ detail::BaseHybridClass* getNativePointer (T t) {
62
+ return getHolder (t)->getNativePointer ();
63
+ }
64
+
65
+ template <typename T>
66
+ void setNativePointer (T t, std::unique_ptr<detail::BaseHybridClass> new_value) {
67
+ getHolder (t)->setNativePointer (std::move (new_value));
68
+ }
69
+
70
+ template <typename T>
71
+ local_ref<HybridDestructor> getHolder (T t) {
72
+ static auto holderField = t->getClass ()->template getField <HybridDestructor::javaobject>(" mDestructor" );
73
+ return t->getFieldValue (holderField);
74
+ }
75
+
76
+ // JavaClass for HybridClassBase
77
+ struct FBEXPORT HybridClassBase : public JavaClass<HybridClassBase> {
78
+ constexpr static auto kJavaDescriptor = " Lcom/facebook/jni/HybridClassBase;" ;
79
+
80
+ static bool isHybridClassBase (alias_ref<jclass> jclass) {
81
+ return HybridClassBase::javaClassStatic ()->isAssignableFrom (jclass);
82
+ }
83
+ };
84
+
37
85
template <typename Base, typename Enabled = void >
38
86
struct HybridTraits {
39
87
// This static assert should actually always fail if we don't use one of the
@@ -139,7 +187,7 @@ class FBEXPORT HybridClass : public detail::HybridTraits<Base>::CxxBase {
139
187
140
188
static local_ref<detail::HybridData> makeHybridData (std::unique_ptr<T> cxxPart) {
141
189
auto hybridData = detail::HybridData::create ();
142
- hybridData-> setNativePointer (std::move (cxxPart));
190
+ setNativePointer (hybridData, std::move (cxxPart));
143
191
return hybridData;
144
192
}
145
193
@@ -148,6 +196,11 @@ class FBEXPORT HybridClass : public detail::HybridTraits<Base>::CxxBase {
148
196
return makeHybridData (std::unique_ptr<T>(new T (std::forward<Args>(args)...)));
149
197
}
150
198
199
+ template <typename ... Args>
200
+ static void setCxxInstance (alias_ref<jhybridobject> o, Args&&... args) {
201
+ setNativePointer (o, std::unique_ptr<T>(new T (std::forward<Args>(args)...)));
202
+ }
203
+
151
204
public:
152
205
// Factory method for creating a hybrid object where the arguments
153
206
// are used to initialize the C++ part directly without passing them
@@ -161,11 +214,23 @@ class FBEXPORT HybridClass : public detail::HybridTraits<Base>::CxxBase {
161
214
// C++ object fails, or any JNI methods throw.
162
215
template <typename ... Args>
163
216
static local_ref<JavaPart> newObjectCxxArgs (Args&&... args) {
164
- auto hybridData = makeCxxInstance (std::forward<Args>(args)...);
165
- return JavaPart::newInstance (hybridData);
217
+ static bool isHybrid = detail::HybridClassBase::isHybridClassBase (javaClassStatic ());
218
+ auto cxxPart = std::unique_ptr<T>(new T (std::forward<Args>(args)...));
219
+
220
+ local_ref<JavaPart> result;
221
+ if (isHybrid) {
222
+ result = JavaPart::newInstance ();
223
+ setNativePointer (result, std::move (cxxPart));
224
+ }
225
+ else {
226
+ auto hybridData = makeHybridData (std::move (cxxPart));
227
+ result = JavaPart::newInstance (hybridData);
228
+ }
229
+
230
+ return result;
166
231
}
167
232
168
- // TODO? Create reusable interface for Allocatable classes and use it to
233
+ // TODO? Create reusable interface for Allocatable classes and use it to
169
234
// strengthen type-checking (and possibly provide a default
170
235
// implementation of allocate().)
171
236
template <typename ... Args>
@@ -195,17 +260,25 @@ class FBEXPORT HybridClass : public detail::HybridTraits<Base>::CxxBase {
195
260
196
261
template <typename T, typename B>
197
262
inline T* HybridClass<T, B>::JavaPart::cthis() {
198
- static auto field =
199
- HybridClass<T, B>::JavaPart::javaClassStatic ()->template getField <detail::HybridData::javaobject>(" mHybridData" );
200
- auto hybridData = this ->getFieldValue (field);
201
- if (!hybridData) {
202
- throwNewJavaException (" java/lang/NullPointerException" , " java.lang.NullPointerException" );
263
+ detail::BaseHybridClass* result = 0 ;
264
+ static bool isHybrid = detail::HybridClassBase::isHybridClassBase (this ->getClass ());
265
+ if (isHybrid) {
266
+ result = getNativePointer (this );
267
+ } else {
268
+ static auto field =
269
+ HybridClass<T, B>::JavaPart::javaClassStatic ()->template getField <detail::HybridData::javaobject>(" mHybridData" );
270
+ auto hybridData = this ->getFieldValue (field);
271
+ if (!hybridData) {
272
+ throwNewJavaException (" java/lang/NullPointerException" , " java.lang.NullPointerException" );
273
+ }
274
+
275
+ result = getNativePointer (hybridData);
203
276
}
204
- // I'd like to use dynamic_cast here, but -fno-rtti is the default.
205
- T* value = static_cast <T*>(hybridData->getNativePointer ());
277
+
206
278
// This would require some serious programmer error.
207
- FBASSERTMSGF (value != 0 , " Incorrect C++ type in hybrid field" );
208
- return value;
279
+ FBASSERTMSGF (result != 0 , " Incorrect C++ type in hybrid field" );
280
+ // I'd like to use dynamic_cast here, but -fno-rtti is the default.
281
+ return static_cast <T*>(result);
209
282
};
210
283
211
284
template <typename T, typename B>
0 commit comments