commit changes in fbjni

This commit is contained in:
Pritesh Nandgaonkar
2018-06-15 11:53:38 +01:00
parent c179078acd
commit f4b76a3688
3 changed files with 188 additions and 242 deletions

View File

@@ -9,7 +9,7 @@ android {
targetSdkVersion rootProject.targetSdkVersion targetSdkVersion rootProject.targetSdkVersion
ndk { ndk {
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' abiFilters 'arm64-v8a', 'x86'
} }
externalNativeBuild { externalNativeBuild {

View File

@@ -5,98 +5,68 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
#pragma once
#pragma once #include <memory>
#include <type_traits>
#include <memory> #include <fb/assert.h>
#include <type_traits> #include <fb/visibility.h>
#include "CoreClasses.h" #include "CoreClasses.h"
namespace facebook { namespace facebook {
namespace jni { namespace jni {
namespace detail { namespace detail {
class BaseHybridClass { class BaseHybridClass {
public: public:
virtual ~BaseHybridClass() {} virtual ~BaseHybridClass() {}
}; };
struct HybridData : public JavaClass<HybridData> { struct FBEXPORT HybridData : public JavaClass<HybridData> {
constexpr static auto kJavaDescriptor = "Lcom/facebook/jni/HybridData;"; constexpr static auto kJavaDescriptor = "Lcom/facebook/jni/HybridData;";
void setNativePointer(std::unique_ptr<BaseHybridClass> new_value);
BaseHybridClass* getNativePointer();
static local_ref<HybridData> create(); static local_ref<HybridData> create();
}; };
class HybridDestructor : public JavaClass<HybridDestructor> { template <typename Base, typename Enabled = void>
public: struct HybridTraits {
static auto constexpr kJavaDescriptor = "Lcom/facebook/jni/HybridData$Destructor;";
detail::BaseHybridClass* getNativePointer();
void setNativePointer(std::unique_ptr<detail::BaseHybridClass> new_value);
};
template<typename T>
detail::BaseHybridClass* getNativePointer(T t) {
return getHolder(t)->getNativePointer();
}
template<typename T>
void setNativePointer(T t, std::unique_ptr<detail::BaseHybridClass> new_value) {
getHolder(t)->setNativePointer(std::move(new_value));
}
template<typename T>
local_ref<HybridDestructor> getHolder(T t) {
static auto holderField = t->getClass()->template getField<HybridDestructor::javaobject>("mDestructor");
return t->getFieldValue(holderField);
}
// JavaClass for HybridClassBase
struct HybridClassBase : public JavaClass<HybridClassBase> {
constexpr static auto kJavaDescriptor = "Lcom/facebook/jni/HybridClassBase;";
static bool isHybridClassBase(alias_ref<jclass> jclass) {
return HybridClassBase::javaClassStatic()->isAssignableFrom(jclass);
}
};
template <typename Base, typename Enabled = void>
struct HybridTraits {
// This static assert should actually always fail if we don't use one of the // This static assert should actually always fail if we don't use one of the
// specializations below. // specializations below.
static_assert( static_assert(
std::is_base_of<JObject, Base>::value || std::is_base_of<JObject, Base>::value ||
std::is_base_of<BaseHybridClass, Base>::value, std::is_base_of<BaseHybridClass, Base>::value,
"The base of a HybridClass must be either another HybridClass or derived from JObject."); "The base of a HybridClass must be either another HybridClass or derived from JObject.");
}; };
template <> template <>
struct HybridTraits<BaseHybridClass> { struct HybridTraits<BaseHybridClass> {
using CxxBase = BaseHybridClass; using CxxBase = BaseHybridClass;
using JavaBase = JObject; using JavaBase = JObject;
}; };
template <typename Base> template <typename Base>
struct HybridTraits< struct HybridTraits<
Base, Base,
typename std::enable_if<std::is_base_of<BaseHybridClass, Base>::value>::type> { typename std::enable_if<std::is_base_of<BaseHybridClass, Base>::value>::type> {
using CxxBase = Base; using CxxBase = Base;
using JavaBase = typename Base::JavaPart; using JavaBase = typename Base::JavaPart;
}; };
template <typename Base> template <typename Base>
struct HybridTraits< struct HybridTraits<
Base, Base,
typename std::enable_if<std::is_base_of<JObject, Base>::value>::type> { typename std::enable_if<std::is_base_of<JObject, Base>::value>::type> {
using CxxBase = BaseHybridClass; using CxxBase = BaseHybridClass;
using JavaBase = Base; using JavaBase = Base;
}; };
// convert to HybridClass* from jhybridobject // convert to HybridClass* from jhybridobject
template <typename T> template <typename T>
struct Convert< struct FBEXPORT Convert<
T, typename std::enable_if< T, typename std::enable_if<
std::is_base_of<BaseHybridClass, typename std::remove_pointer<T>::type>::value>::type> { std::is_base_of<BaseHybridClass, typename std::remove_pointer<T>::type>::value>::type> {
typedef typename std::remove_pointer<T>::type::jhybridobject jniType; typedef typename std::remove_pointer<T>::type::jhybridobject jniType;
@@ -107,22 +77,22 @@
return wrap_alias(t)->cthis(); return wrap_alias(t)->cthis();
} }
// There is no automatic return conversion for objects. // There is no automatic return conversion for objects.
}; };
template<typename T> template<typename T>
struct RefReprType<T, typename std::enable_if<std::is_base_of<BaseHybridClass, T>::value, void>::type> { struct RefReprType<T, typename std::enable_if<std::is_base_of<BaseHybridClass, T>::value, void>::type> {
static_assert(std::is_same<T, void>::value, static_assert(std::is_same<T, void>::value,
"HybridFoo (where HybridFoo derives from HybridClass<HybridFoo>) is not supported in this context. " "HybridFoo (where HybridFoo derives from HybridClass<HybridFoo>) is not supported in this context. "
"For an xxx_ref<HybridFoo>, you may want: xxx_ref<HybridFoo::javaobject> or HybridFoo*."); "For an xxx_ref<HybridFoo>, you may want: xxx_ref<HybridFoo::javaobject> or HybridFoo*.");
using Repr = T; using Repr = T;
}; };
} }
template <typename T, typename Base = detail::BaseHybridClass> template <typename T, typename Base = detail::BaseHybridClass>
class HybridClass : public detail::HybridTraits<Base>::CxxBase { class FBEXPORT HybridClass : public detail::HybridTraits<Base>::CxxBase {
public: public:
struct JavaPart : JavaClass<JavaPart, typename detail::HybridTraits<Base>::JavaBase> { struct JavaPart : JavaClass<JavaPart, typename detail::HybridTraits<Base>::JavaBase> {
// At this point, T is incomplete, and so we cannot access // At this point, T is incomplete, and so we cannot access
// T::kJavaDescriptor directly. jtype_traits support this escape hatch for // T::kJavaDescriptor directly. jtype_traits support this escape hatch for
@@ -138,7 +108,6 @@
T* cthis(); T* cthis();
friend class HybridClass; friend class HybridClass;
friend T;
}; };
using jhybridobject = typename JavaPart::javaobject; using jhybridobject = typename JavaPart::javaobject;
@@ -154,7 +123,7 @@
return findClassLocal(className.c_str()); return findClassLocal(className.c_str());
} }
protected: protected:
typedef HybridClass HybridBase; typedef HybridClass HybridBase;
// This ensures that a C++ hybrid part cannot be created on its own // This ensures that a C++ hybrid part cannot be created on its own
@@ -168,7 +137,7 @@
static local_ref<detail::HybridData> makeHybridData(std::unique_ptr<T> cxxPart) { static local_ref<detail::HybridData> makeHybridData(std::unique_ptr<T> cxxPart) {
auto hybridData = detail::HybridData::create(); auto hybridData = detail::HybridData::create();
setNativePointer(hybridData, std::move(cxxPart)); hybridData->setNativePointer(std::move(cxxPart));
return hybridData; return hybridData;
} }
@@ -177,12 +146,7 @@
return makeHybridData(std::unique_ptr<T>(new T(std::forward<Args>(args)...))); return makeHybridData(std::unique_ptr<T>(new T(std::forward<Args>(args)...)));
} }
template <typename... Args> public:
static void setCxxInstance(alias_ref<jhybridobject> o, Args&&... args) {
setNativePointer(o, std::unique_ptr<T>(new T(std::forward<Args>(args)...)));
}
public:
// Factory method for creating a hybrid object where the arguments // Factory method for creating a hybrid object where the arguments
// are used to initialize the C++ part directly without passing them // are used to initialize the C++ part directly without passing them
// through java. This method requires the Java part to have a ctor // through java. This method requires the Java part to have a ctor
@@ -195,20 +159,8 @@
// C++ object fails, or any JNI methods throw. // C++ object fails, or any JNI methods throw.
template <typename... Args> template <typename... Args>
static local_ref<JavaPart> newObjectCxxArgs(Args&&... args) { static local_ref<JavaPart> newObjectCxxArgs(Args&&... args) {
static bool isHybrid = detail::HybridClassBase::isHybridClassBase(javaClassStatic()); auto hybridData = makeCxxInstance(std::forward<Args>(args)...);
auto cxxPart = std::unique_ptr<T>(new T(std::forward<Args>(args)...)); return JavaPart::newInstance(hybridData);
local_ref<JavaPart> result;
if (isHybrid) {
result = JavaPart::newInstance();
setNativePointer(result, std::move(cxxPart));
}
else {
auto hybridData = makeHybridData(std::move(cxxPart));
result = JavaPart::newInstance(hybridData);
}
return result;
} }
// TODO? Create reusable interface for Allocatable classes and use it to // TODO? Create reusable interface for Allocatable classes and use it to
@@ -237,49 +189,43 @@
// mapException returns, then the std::exception will be translated // mapException returns, then the std::exception will be translated
// to Java. // to Java.
static void mapException(const std::exception& ex) {} static void mapException(const std::exception& ex) {}
}; };
template <typename T, typename B> template <typename T, typename B>
inline T* HybridClass<T, B>::JavaPart::cthis() { inline T* HybridClass<T, B>::JavaPart::cthis() {
detail::BaseHybridClass* result = 0;
static bool isHybrid = detail::HybridClassBase::isHybridClassBase(this->getClass());
if (isHybrid) {
result = getNativePointer(this);
} else {
static auto field = static auto field =
HybridClass<T, B>::JavaPart::javaClassStatic()->template getField<detail::HybridData::javaobject>("mHybridData"); HybridClass<T, B>::JavaPart::javaClassStatic()->template getField<detail::HybridData::javaobject>("mHybridData");
auto hybridData = this->getFieldValue(field); auto hybridData = this->getFieldValue(field);
if (!hybridData) { if (!hybridData) {
throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException"); throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException");
} }
result = getNativePointer(hybridData);
}
// I'd like to use dynamic_cast here, but -fno-rtti is the default. // I'd like to use dynamic_cast here, but -fno-rtti is the default.
return static_cast<T*>(result); T* value = static_cast<T*>(hybridData->getNativePointer());
}; // This would require some serious programmer error.
FBASSERTMSGF(value != 0, "Incorrect C++ type in hybrid field");
return value;
};
template <typename T, typename B> template <typename T, typename B>
/* static */ inline std::string HybridClass<T, B>::JavaPart::get_instantiated_java_descriptor() { /* static */ inline std::string HybridClass<T, B>::JavaPart::get_instantiated_java_descriptor() {
return T::kJavaDescriptor; return T::kJavaDescriptor;
} }
template <typename T, typename B> template <typename T, typename B>
/* static */ inline std::string HybridClass<T, B>::JavaPart::get_instantiated_base_name() { /* static */ inline std::string HybridClass<T, B>::JavaPart::get_instantiated_base_name() {
auto name = get_instantiated_java_descriptor(); auto name = get_instantiated_java_descriptor();
return name.substr(1, name.size() - 2); return name.substr(1, name.size() - 2);
} }
// Given a *_ref object which refers to a hybrid class, this will reach inside // Given a *_ref object which refers to a hybrid class, this will reach inside
// of it, find the mHybridData, extract the C++ instance pointer, cast it to // of it, find the mHybridData, extract the C++ instance pointer, cast it to
// the appropriate type, and return it. // the appropriate type, and return it.
template <typename T> template <typename T>
inline auto cthis(T jthis) -> decltype(jthis->cthis()) { inline auto cthis(T jthis) -> decltype(jthis->cthis()) {
return jthis->cthis(); return jthis->cthis();
} }
void HybridDataOnLoad(); void HybridDataOnLoad();
} }
} }

View File

@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
#include "fb/fbjni.h" #include "fb/fbjni.h"
namespace facebook { namespace facebook {