Commit b0e39230 authored by Jacob Potter's avatar Jacob Potter

Unify Java->C++, C++->Java, ObjC->Java, and Java->ObjC wrapper caches and handles.

parent 2895f8f2
......@@ -26,7 +26,7 @@ CJNIEXPORT void JNICALL Java_com_dropbox_textsort_SortItems_00024CppProxy_native
{
try {
DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);
const auto& ref = ::djinni::CppProxyHandle<::textsort::SortItems>::get(nativeRef);
const auto& ref = ::djinni::objectFromHandleAddress<::textsort::SortItems>(nativeRef);
ref->sort(::djinni_generated::NativeSortOrder::toCpp(jniEnv, j_order),
::djinni_generated::NativeItemList::toCpp(jniEnv, j_items));
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )
......
......@@ -10,7 +10,7 @@ NativeTextboxListener::NativeTextboxListener() : ::djinni::JniInterface<::textso
NativeTextboxListener::~NativeTextboxListener() = default;
NativeTextboxListener::JavaProxy::JavaProxy(JniType j) : JavaProxyCacheEntry(j) { }
NativeTextboxListener::JavaProxy::JavaProxy(JniType j) : Handle(::djinni::jniGetThreadEnv(), j) { }
NativeTextboxListener::JavaProxy::~JavaProxy() = default;
......@@ -18,7 +18,7 @@ void NativeTextboxListener::JavaProxy::update(const ::textsort::ItemList & c_ite
auto jniEnv = ::djinni::jniGetThreadEnv();
::djinni::JniLocalScope jscope(jniEnv, 10);
const auto& data = ::djinni::JniClass<::djinni_generated::NativeTextboxListener>::get();
jniEnv->CallVoidMethod(getGlobalRef(), data.method_update,
jniEnv->CallVoidMethod(Handle::get().get(), data.method_update,
::djinni::get(::djinni_generated::NativeItemList::fromCpp(jniEnv, c_items)));
::djinni::jniExceptionCheck(jniEnv);
}
......
......@@ -34,9 +34,7 @@ private:
void update(const ::textsort::ItemList & items) override;
private:
using ::djinni::JavaProxyCacheEntry::getGlobalRef;
friend ::djinni::JniInterface<::textsort::TextboxListener, ::djinni_generated::NativeTextboxListener>;
friend ::djinni::JavaProxyCache<JavaProxy>;
};
const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass("com/dropbox/textsort/TextboxListener") };
......
......@@ -21,7 +21,7 @@ static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for th
@end
@implementation TXSSortItems {
::djinni::DbxCppWrapperCache<::textsort::SortItems>::Handle _cppRefHandle;
::djinni::CppProxyCache::Handle<std::shared_ptr<::textsort::SortItems>> _cppRefHandle;
}
- (id)initWithCpp:(const std::shared_ptr<::textsort::SortItems>&)cppRef
......@@ -62,9 +62,7 @@ auto SortItems::fromCpp(const CppType& cpp) -> ObjcType
if (!cpp) {
return nil;
}
return ::djinni::DbxCppWrapperCache<::textsort::SortItems>::getInstance()->get(cpp, [] (const CppType& p) {
return [[TXSSortItems alloc] initWithCpp:p];
});
return ::djinni::get_cpp_proxy<TXSSortItems>(cpp);
}
} // namespace djinni_generated
......
......@@ -12,14 +12,14 @@ namespace djinni_generated {
class TextboxListener::ObjcProxy final
: public ::textsort::TextboxListener
, public ::djinni::DbxObjcWrapperCache<ObjcProxy>::Handle
, public ::djinni::ObjcProxyCache::Handle<ObjcType>
{
public:
using Handle::Handle;
void update(const ::textsort::ItemList & c_items) override
{
@autoreleasepool {
[(ObjcType)Handle::get() update:(::djinni_generated::ItemList::fromCpp(c_items))];
[Handle::get() update:(::djinni_generated::ItemList::fromCpp(c_items))];
}
}
};
......@@ -33,7 +33,7 @@ auto TextboxListener::toCpp(ObjcType objc) -> CppType
if (!objc) {
return nullptr;
}
return ::djinni::DbxObjcWrapperCache<ObjcProxy>::getInstance()->get(objc);
return ::djinni::get_objc_proxy<ObjcProxy>(objc);
}
auto TextboxListener::fromCpp(const CppType& cpp) -> ObjcType
......
......@@ -214,9 +214,7 @@ class JNIGenerator(spec: Spec) extends Generator(spec) {
}
w.wl
w.wlOutdent(s"private:")
w.wl(s"using ::djinni::JavaProxyCacheEntry::getGlobalRef;")
w.wl(s"friend ::djinni::JniInterface<$cppSelf, ${withNs(Some(spec.jniNamespace), jniSelf)}>;")
w.wl(s"friend ::djinni::JavaProxyCache<JavaProxy>;")
}
w.wl
w.wl(s"const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(${q(classLookup)}) };")
......@@ -241,7 +239,7 @@ class JNIGenerator(spec: Spec) extends Generator(spec) {
w.wl
if (i.ext.java) {
writeJniTypeParams(w, typeParams)
w.wl(s"$jniSelfWithParams::JavaProxy::JavaProxy(JniType j) : JavaProxyCacheEntry(j) { }")
w.wl(s"$jniSelfWithParams::JavaProxy::JavaProxy(JniType j) : Handle(::djinni::jniGetThreadEnv(), j) { }")
w.wl
writeJniTypeParams(w, typeParams)
w.wl(s"$jniSelfWithParams::JavaProxy::~JavaProxy() = default;")
......@@ -258,7 +256,7 @@ class JNIGenerator(spec: Spec) extends Generator(spec) {
val call = m.ret.fold("jniEnv->CallVoidMethod(")(r => "auto jret = " + toJniCall(r, (jt: String) => s"jniEnv->Call${jt}Method("))
w.w(call)
val javaMethodName = idJava.method(m.ident)
w.w(s"getGlobalRef(), data.method_$javaMethodName")
w.w(s"Handle::get().get(), data.method_$javaMethodName")
if(m.params.nonEmpty){
w.wl(",")
writeAlignedCall(w, " " * call.length(), m.params, ")", p => {
......@@ -321,7 +319,7 @@ class JNIGenerator(spec: Spec) extends Generator(spec) {
val nativeAddon = if (m.static) "" else "native_"
nativeHook(nativeAddon + idJava.method(m.ident), m.static, m.params, m.ret, {
//w.wl(s"::${spec.jniNamespace}::JniLocalScope jscope(jniEnv, 10);")
if (!m.static) w.wl(s"const auto& ref = ::djinni::CppProxyHandle<$cppSelf>::get(nativeRef);")
if (!m.static) w.wl(s"const auto& ref = ::djinni::objectFromHandleAddress<$cppSelf>(nativeRef);")
m.params.foreach(p => {
if (isInterface(p.ty.resolved) && spec.cppNnCheckExpression.nonEmpty) {
// We have a non-optional interface in nn mode, assert that we're getting a non-null value
......
......@@ -134,7 +134,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
w.wl("@end")
w.wl
w.wl(s"@implementation $objcSelf {")
w.wl(s" ::djinni::DbxCppWrapperCache<$cppSelf>::Handle _cppRefHandle;")
w.wl(s" ::djinni::CppProxyCache::Handle<std::shared_ptr<$cppSelf>> _cppRefHandle;")
w.wl("}")
w.wl
w.wl(s"- (id)initWithCpp:(const std::shared_ptr<$cppSelf>&)cppRef")
......@@ -185,7 +185,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
wrapNamespace(w, spec.objcppNamespace, w => {
w.wl(s"class $helperClass::ObjcProxy final")
w.wl(s": public $cppSelf")
w.wl(s", public ::djinni::DbxObjcWrapperCache<ObjcProxy>::Handle") // Use base class to avoid name conflicts with user-defined methods having the same name as this new data member
w.wl(s", public ::djinni::ObjcProxyCache::Handle<ObjcType>") // Use base class to avoid name conflicts with user-defined methods having the same name as this new data member
w.bracedSemi {
w.wlOutdent("public:")
w.wl("using Handle::Handle;")
......@@ -195,7 +195,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
w.wl(s"$ret ${idCpp.method(m.ident)}${params.mkString("(", ", ", ")")} override").braced {
w.w("@autoreleasepool").braced {
val ret = m.ret.fold("")(_ => "auto r = ")
val call = s"[(ObjcType)Handle::get() ${idObjc.method(m.ident)}"
val call = s"[Handle::get() ${idObjc.method(m.ident)}"
writeAlignedObjcCall(w, ret + call, m.params, "]", p => (idObjc.field(p.ident), s"(${objcppMarshal.fromCpp(p.ty, "c_" + idCpp.local(p.ident))})"))
w.wl(";")
m.ret.fold()(ty => (spec.cppNnCheckExpression, isInterface(ty.resolved)) match {
......@@ -242,7 +242,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
w.wl(s"return (($objcSelf*)objc)->_cppRefHandle.get();")
}
}
w.wl(s"return ::djinni::DbxObjcWrapperCache<$objcExtSelf>::getInstance()->get(objc);")
w.wl(s"return ::djinni::get_objc_proxy<$objcExtSelf>(objc);")
}
}
w.wl
......@@ -265,9 +265,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
w.wl("return cppPtr->Handle::get();")
}
}
w.w(s"return ::djinni::DbxCppWrapperCache<$cppSelf>::getInstance()->get(cpp, [] (const CppType& p)").bracedEnd(");") {
w.wl(s"return [[$objcSelf alloc] initWithCpp:p];")
}
w.wl(s"return ::djinni::get_cpp_proxy<$objcSelf>(cpp);")
}
}
})
......
......@@ -15,6 +15,7 @@
//
#include "djinni_support.hpp"
#include "../proxy_cache_impl.hpp"
#include <cassert>
#include <cstdlib>
#include <cstring>
......@@ -464,48 +465,7 @@ void jniDefaultSetPendingFromCurrent(JNIEnv * env, const char * /*ctx*/) noexcep
// exceptions which aren't std::exception subclasses).
}
struct JavaProxyCacheState {
std::mutex mtx;
std::unordered_map<jobject, std::weak_ptr<void>, JavaIdentityHash, JavaIdentityEquals> m;
int counter = 0;
static JavaProxyCacheState & get() {
static JavaProxyCacheState st;
return st;
}
};
JavaProxyCacheEntry::JavaProxyCacheEntry(jobject localRef, JNIEnv * env)
: m_globalRef(env, localRef) {
DJINNI_ASSERT(m_globalRef, env);
}
JavaProxyCacheEntry::JavaProxyCacheEntry(jobject localRef)
: JavaProxyCacheEntry(localRef, jniGetThreadEnv()) {}
JavaProxyCacheEntry::~JavaProxyCacheEntry() noexcept {
JavaProxyCacheState & st = JavaProxyCacheState::get();
const std::lock_guard<std::mutex> lock(st.mtx);
st.m.erase(m_globalRef.get());
}
std::shared_ptr<void> javaProxyCacheLookup(jobject obj, std::pair<std::shared_ptr<void>, jobject>(*factory)(jobject)) {
JavaProxyCacheState & st = JavaProxyCacheState::get();
const std::lock_guard<std::mutex> lock(st.mtx);
const auto it = st.m.find(obj);
if (it != st.m.end()) {
std::shared_ptr<void> ptr = it->second.lock();
if (ptr) {
return ptr;
}
}
// Otherwise, construct a new T, save it, and return it.
std::pair<std::shared_ptr<void>, jobject> ret = factory(obj);
st.m[ret.second] = ret.first;
return ret.first;
}
template class ProxyCache<JavaProxyCacheTraits>;
CppProxyClassInfo::CppProxyClassInfo(const char * className)
: clazz(jniFindClass(className)),
......@@ -544,11 +504,13 @@ private:
public:
// Constructor
JavaWeakRef(jobject obj) : JavaWeakRef(jniGetThreadEnv(), obj) {}
JavaWeakRef(JNIEnv * jniEnv, jobject obj) : m_weakRef(jniEnv, create(jniEnv, obj)) {}
// Get the object pointed to if it's still strongly reachable or, return null if not.
// (Analogous to weak_ptr::lock.) Returns a local reference.
jobject get(JNIEnv * jniEnv) {
jobject lock() const {
const auto & jniEnv = jniGetThreadEnv();
const JniInfo & weakRefClass = JniClass<JniInfo>::get();
jobject javaObj = jniEnv->CallObjectMethod(m_weakRef.get(), weakRefClass.method_get);
jniExceptionCheck(jniEnv);
......@@ -559,47 +521,6 @@ private:
GlobalRef<jobject> m_weakRef;
};
struct CppProxyCacheState {
std::mutex mtx;
std::unordered_map<void *, JavaWeakRef> m;
static CppProxyCacheState & get() {
static CppProxyCacheState st;
return st;
}
};
/*static*/ void JniCppProxyCache::erase(void * key) {
CppProxyCacheState & st = CppProxyCacheState::get();
const std::lock_guard<std::mutex> lock(st.mtx);
st.m.erase(key);
}
/*static*/ jobject JniCppProxyCache::get(const std::shared_ptr<void> & cppObj,
JNIEnv * jniEnv,
const CppProxyClassInfo & proxyClass,
jobject (*factory)(const std::shared_ptr<void> &,
JNIEnv *,
const CppProxyClassInfo &)) {
CppProxyCacheState & st = CppProxyCacheState::get();
const std::lock_guard<std::mutex> lock(st.mtx);
auto it = st.m.find(cppObj.get());
if (it != st.m.end()) {
// It's in the map. See if the WeakReference still points to an object.
if (jobject javaObj = it->second.get(jniEnv)) {
return javaObj;
} else {
// The WeakReference is expired, so prune it from the map eagerly.
st.m.erase(it);
}
}
jobject wrapper = factory(cppObj, jniEnv, proxyClass);
/* Make a Java WeakRef object */
st.m.emplace(cppObj.get(), JavaWeakRef(jniEnv, wrapper));
return wrapper;
}
template class ProxyCache<JniCppProxyCacheTraits>;
} // namespace djinni
This diff is collapsed.
......@@ -18,71 +18,36 @@
#import <Foundation/Foundation.h>
#include <memory>
#include <mutex>
#include <unordered_map>
namespace djinni {
template <class T>
class DbxCppWrapperCache {
public:
static const std::shared_ptr<DbxCppWrapperCache> & getInstance() {
static const std::shared_ptr<DbxCppWrapperCache> instance(new DbxCppWrapperCache);
// Return by const-ref. This is safe to call any time except during static destruction.
// Returning by reference lets us avoid touching the refcount unless needed.
return instance;
}
#include "../proxy_cache_interface.hpp"
template <typename AllocFunc>
id get(const std::shared_ptr<T> & cppRef, const AllocFunc & alloc) {
std::unique_lock<std::mutex> lock(m_mutex);
T* ptr = cppRef.get();
auto got = m_mapping.find(ptr);
id ret;
if (got != m_mapping.end()) {
ret = got->second;
if (ret == nil) {
ret = alloc(cppRef);
m_mapping[ptr] = ret;
}
} else {
ret = alloc(cppRef);
m_mapping[ptr] = ret;
}
return ret;
}
void remove(const std::shared_ptr<T> & cppRef) {
std::unique_lock<std::mutex> lock(m_mutex);
T* ptr = cppRef.get();
if (m_mapping[ptr] == nil) {
m_mapping.erase(ptr);
}
}
namespace djinni {
class Handle {
public:
Handle() = default;
Handle(const Handle &) = delete;
Handle & operator=(const Handle &) = delete;
~Handle() {
if (_ptr) {
_cache->remove(_ptr);
}
}
void assign(const std::shared_ptr<T>& ptr) { _ptr = ptr; }
const std::shared_ptr<T>& get() const noexcept { return _ptr; }
struct CppProxyCacheTraits {
using UnowningImplPointer = void *;
using OwningImplPointer = std::shared_ptr<void>;
using OwningProxyPointer = __strong id;
using WeakProxyPointer = __weak id;
using UnowningImplPointerHash = std::hash<void *>;
using UnowningImplPointerEqual = std::equal_to<void *>;
};
private:
const std::shared_ptr<DbxCppWrapperCache> _cache = getInstance();
std::shared_ptr<T> _ptr;
// This declares that GenericProxyCache will be instantiated separately. The actual
// explicit instantiations are in DJIProxyCaches.mm.
extern template class ProxyCache<CppProxyCacheTraits>;
using CppProxyCache = ProxyCache<CppProxyCacheTraits>;
template <typename ObjcType, typename CppType>
ObjcType * get_cpp_proxy(const std::shared_ptr<CppType> & cppRef) {
return CppProxyCache::get(
cppRef,
[] (const std::shared_ptr<void> & cppRef) -> std::pair<id, void *> {
return {
[[ObjcType alloc] initWithCpp:std::static_pointer_cast<CppType>(cppRef)],
cppRef.get()
};
private:
std::unordered_map<T*, __weak id> m_mapping;
std::mutex m_mutex;
DbxCppWrapperCache() {}
};
}
);
}
} // namespace djinni
......@@ -18,70 +18,38 @@
#import <Foundation/Foundation.h>
#include <memory>
#include <mutex>
#include <unordered_map>
namespace djinni {
template <class T>
class DbxObjcWrapperCache {
public:
static const std::shared_ptr<DbxObjcWrapperCache> & getInstance() {
static const std::shared_ptr<DbxObjcWrapperCache> instance(new DbxObjcWrapperCache);
// Return by const-ref. This is safe to call any time except during static destruction.
// Returning by reference lets us avoid touching the refcount unless needed.
return instance;
}
#include "../proxy_cache_interface.hpp"
std::shared_ptr<T> get(id objcRef) {
std::unique_lock<std::mutex> lock(m_mutex);
std::shared_ptr<T> ret;
auto it = m_mapping.find((__bridge void*)objcRef);
if (it != m_mapping.end()) {
ret = std::static_pointer_cast<T>(it->second.lock());
if (ret == nullptr) {
ret = new_wrapper(objcRef);
}
} else {
ret = new_wrapper(objcRef);
}
return ret;
}
namespace djinni {
void remove(id objcRef) {
std::unique_lock<std::mutex> lock(m_mutex);
m_mapping.erase((__bridge void*)objcRef);
}
struct unretained_id_hash { std::size_t operator()(__unsafe_unretained id ptr) const; };
class Handle {
public:
Handle(id obj) : _obj(obj) { }
Handle(const Handle &) = delete;
Handle & operator=(const Handle &) = delete;
~Handle() {
if (_obj) {
_cache->remove(_obj);
}
}
id get() const noexcept { return _obj; }
struct ObjcProxyCacheTraits {
using UnowningImplPointer = __unsafe_unretained id;
using OwningImplPointer = __strong id;
using OwningProxyPointer = std::shared_ptr<void>;
using WeakProxyPointer = std::weak_ptr<void>;
using UnowningImplPointerHash = unretained_id_hash;
using UnowningImplPointerEqual = std::equal_to<__unsafe_unretained id>;
};
private:
const std::shared_ptr<DbxObjcWrapperCache> _cache = getInstance();
const id _obj;
// This declares that GenericProxyCache will be instantiated separately. The actual
// explicit instantiations are in DJIProxyCaches.mm.
extern template class ProxyCache<ObjcProxyCacheTraits>;
using ObjcProxyCache = ProxyCache<ObjcProxyCacheTraits>;
template <typename CppType, typename ObjcType>
static std::shared_ptr<CppType> get_objc_proxy(ObjcType * objcRef) {
return std::static_pointer_cast<CppType>(ObjcProxyCache::get(
objcRef,
[] (const __strong id & objcRef) -> std::pair<std::shared_ptr<void>, __unsafe_unretained id> {
return {
std::make_shared<CppType>(objcRef),
objcRef
};
private:
std::unordered_map<void*, std::weak_ptr<void>> m_mapping;
std::mutex m_mutex;
std::shared_ptr<T> new_wrapper(id objcRef) {
std::shared_ptr<T> ret = std::make_shared<T>(objcRef);
std::weak_ptr<void> ptr(std::static_pointer_cast<void>(ret));
m_mapping[(__bridge void*)objcRef] = ptr;
return ret;
}
};
));
}
} // namespace djinni
//
// Copyright 2014 Dropbox, Inc.
// Copyright 2015 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
......@@ -14,16 +14,19 @@
// limitations under the License.
//
#import "DJIWeakPtrWrapper+Private.h"
static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file");
@implementation DBWeakPtrWrapper
#include "../proxy_cache_impl.hpp"
#include "DJIObjcWrapperCache+Private.h"
#include "DJICppWrapperCache+Private.h"
- (id)initWithWeakPtr:(std::weak_ptr<void>)ptr {
if (self = [super init]) {
_ptr = ptr;
}
return self;
namespace djinni {
std::size_t unretained_id_hash::operator()(__unsafe_unretained id ptr) const {
return std::hash<void*>()((__bridge void*)ptr);
}
@end
template class ProxyCache<ObjcProxyCacheTraits>;
template class ProxyCache<CppProxyCacheTraits>;
} // namespace djinni
//
// Copyright 2014 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import <Foundation/Foundation.h>
#include <memory>
/*
* Helper class for DbxObjcWrapperCache to store C++ weak_ptr in Objective-C NSMapTable.
*/
@interface DBWeakPtrWrapper : NSObject
@property (nonatomic, readonly) std::weak_ptr<void> ptr;
- (id)initWithWeakPtr:(std::weak_ptr<void>)ptr;
@end
//
// Copyright 2015 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#pragma once
#include "proxy_cache_interface.hpp"
#include <functional>
#include <mutex>
#include <unordered_map>
// """
// This place is not a place of honor.
// No highly esteemed deed is commemorated here.
// Nothing valued is here.
// This place is a message and part of a system of messages.
// Pay attention to it!
// Sending this message was important to us.
// We considered ourselves to be a powerful culture.
// """
//
// From "Expert Judgment on Markers to Deter Inadvertent Human Intrusion into the Waste
// Isolation Pilot Plant", Sandia National Laboratories report SAND92-1382 / UC-721, p. F-49
namespace djinni {
// See comment on `get_unowning()` in proxy_cache_interface.hpp.
template <typename T> static inline auto upgrade_weak(const T & ptr) { return ptr.lock(); }
template <typename T> static inline T * upgrade_weak(T* ptr) { return ptr; }
/*
* Generic proxy cache.
*
* This provides a general-purpose mechanism for proxies to be re-used. When we pass an object
* across the language boundary from A to B, we must create a proxy object within language B
* that passes calls back to language A. For example, if have a C++ object that is passed into
* Java, we would create a Java object that owns a `shared_ptr` and has a set of native methods
* that call in to C++.
*
* When we create such an object, we also want to cache a weak reference to it, so that if we
* later pass the *same* object across the boundary, the same proxy will be returned. This is
* necessary for correctness in some situations: for example, in the case of an `add_listener`
* and `remove_listener` pattern.
*
* To reduce code size, only one GenericProxyCache need be instantiated for each language
* boundary direction. The pointer types passed to this function can be generic, e.g. `id`,
* `shared_ptr<void>`, `jobject`, etc.
*
* In the types below, "Impl" refers to some interface that is being wrapped, and Proxy refers
* to the generated other-language object that wraps it.
*/
template <typename Traits>
class ProxyCache<Traits>::Pimpl {
public:
/*
* Look up an object in the proxy cache, and create a new one if not found.
*
* This takes a function pointer, not an arbitrary functor, because we want to minimize
* code size: this function should only be instantiated *once* per langauge direction.
*/
OwningProxyPointer get(const OwningImplPointer & impl, AllocatorFunction * alloc) {
std::unique_lock<std::mutex> lock(m_mutex);
UnowningImplPointer ptr = get_unowning(impl);
auto existing_proxy_iter = m_mapping.find(ptr);
if (existing_proxy_iter != m_mapping.end()) {
OwningProxyPointer existing_proxy = upgrade_weak(existing_proxy_iter->second);
if (existing_proxy) {
return existing_proxy;
} else {
// The weak reference is expired, so prune it from the map eagerly.
m_mapping.erase(existing_proxy_iter);
}
}
auto alloc_result = alloc(impl);
m_mapping.emplace(alloc_result.second, alloc_result.first);
return alloc_result.first;
}
/*
* Erase an object from the proxy cache.
*/
void remove(const UnowningImplPointer & impl_unowning) {
std::unique_lock<std::mutex> lock(m_mutex);
m_mapping.erase(impl_unowning);
}
private:
std::unordered_map<UnowningImplPointer,
WeakProxyPointer,
UnowningImplPointerHash,
UnowningImplPointerEqual> m_mapping;
std::mutex m_mutex;
// Only ProxyCache<Traits>::get_base() can allocate these objects.
Pimpl() = default;
friend class ProxyCache<Traits>;
};
template <typename Traits>
void ProxyCache<Traits>::cleanup(const std::shared_ptr<Pimpl> & base, UnowningImplPointer ptr) {
base->remove(ptr);
}
/*
* Magic-static singleton.
*
* It's possible for someone to hold Djinni-static objects in a global (like a shared_ptr
* at namespace scope), which can cause problems at static destruction time: if the proxy
* cache itself is destroyed before the other global, use-of-destroyed-object will result.
* To fix this, we make it possible to take a shared_ptr to the GenericProxyCache instance,
* so it will only be destroyed once all references are gone.
*/
template <typename Traits>
auto ProxyCache<Traits>::get_base() -> const std::shared_ptr<Pimpl> & {
static const std::shared_ptr<Pimpl> instance(new Pimpl);
// Return by const-ref. This is safe to call any time except during static destruction.
// Returning by reference lets us avoid touching the refcount unless needed.
return instance;
}
template <typename Traits>
auto ProxyCache<Traits>::get(const OwningImplPointer & impl, AllocatorFunction * alloc)
-> OwningProxyPointer {
return get_base()->get(impl, alloc);
}
} // namespace djinni
//
// Copyright 2015 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#pragma once
#include <functional>
namespace djinni {
/*
* The template parameters we receive here can be a number of different types: C++ smart
* pointers, custom wrappers, or language-specific types (like ObjC's `id` / `__weak id`).
* If custom wrapper types are used, like the `JavaWeakRef` type in the JNI library, then
* they must implement `.get()` or `.lock()` by analogy with C++'s smart pointers.
*
* We assume that built-in types are pointer-compatible. This is the case with ObjC: for
* example, __weak id pointers can be implicitly converted to __strong id, and so on.
*
* (The helper for .lock() is only used by proxy_cache_impl.hpp, so it's defined there.)
*/
template <typename T> static inline auto get_unowning(const T & ptr) { return ptr.get(); }
template <typename T> static inline T * get_unowning(T * ptr) { return ptr; }
/*
* ProxyCache provides a mechanism for re-using proxy objects generated in one language
* that wrap around implementations in a different language. This is for correctness, not
* just performance: when we pass the same object across a language boundary twice, we want
* to get the same proxy object on the other side each time, so that identity semantics
* behave as expected.
*
* ProxyCache is instantiated with a Traits class that must contain the following typedefs.
* Examples refer to the use of ProxyCache to cache C++ wrappers around ObjC objects.
* ProxyCache itself is generic (type-erased), though Handle is not, so we use e.g. `id`
* and `shared_ptr<void>` rather than any specific types.
*
* - UnowningImplPointer:
* a non-owning pointer to an object being wrapped, e.g. __unsafe_unretained id
* - OwningImplPointer:
* a strong owning pointer to an object being wrapped, e.g. __strong id
* - OwningProxyPointer:
* a strong owning pointer to a wrapper, e.g. std::shared_ptr<void>
* - WeakProxyPointer:
* a safe weak pointer to a wrapper, e.g. std::weak_ptr<void>
* - UnowningImplPointerHash:
* a hasher for UnowningImplPointer, usually std::hash<UnowningImplPointer>, unless
* std::hash doesn't work with UnowningImplPointer in which case a custom type can be
* provided.
* - UnowningImplPointerEqual:
* an equality predicate for UnowningImplPointer, like std::equal_to<UnowningImplPointer>.
* In some cases (e.g. Java) a custom equality predicate may be needed.
*
* Generally, ProxyCache will be explicitly instantiated in one source file with C++11's
* `extern template` mechanism. The WeakProxyPointer, UnowningImplPointerHash, and
* UnowningImplPointerEqual types can be incomplete except for where the explicit
* instantiation is actually defined.
*
* Here's an overview of the structure:
*
* ______________
* WeakProxyPonter | | UnowningImplPointer
* - - - - - - - -| ProxyCache:: |- - - - - - - - - -
* | | Handle<T> | |
* | |______________| |
* | |
* ____v____ ______________ ______________v__________
* | | | | | |
* | (Proxy | ===> | ProxyCache:: | =====> | (Impl object providing |
* | object) | ^ | Handle<T> | T | actual functionality) |
* |_________| . |______________| ^ |_________________________|
* . .
* ( can be member, base, ) ( T is a generally a specific )
* ( or cross-language ) ( owning type like id<Foo>, )
* ( reference like jlong ) ( shared_ptr<Foo>, or GlobalRef )
*/
template <typename Traits>
class ProxyCache {
public:
using UnowningImplPointer = typename Traits::UnowningImplPointer;
using OwningImplPointer = typename Traits::OwningImplPointer;
using OwningProxyPointer = typename Traits::OwningProxyPointer;
using WeakProxyPointer = typename Traits::WeakProxyPointer;
using UnowningImplPointerHash = typename Traits::UnowningImplPointerHash;
using UnowningImplPointerEqual = typename Traits::UnowningImplPointerEqual;
class Pimpl;
/*
* Each proxy object must own a Handle. The Handle carries a strong reference to whatever
* the proxy wraps. When `ProxyCache::get()` creates a proxy, it also adds the proxy to
* the global proxy cache; Handle::~Handle() removes the reference from the cache.
*
* The Handle can be held by the proxy in any of a number of ways: as a C++ member or
* base, as an ObjC instance variable, or across an FFI boundary (a Java object might
* contain the address of a Handle as a `long` and delete it in the destructor.)
*
* T is generally a more-specialized version of OwningImplPointer. For example, when
* managing C++ proxies for ObjC objects, OwningImplPointer would be `id`, and the C++
* proxy class `MyInterface` which wraps `@protocol DBMyInterface` would contain a
* `Handle<id<DBMyInterface>>`.
*/
template <class T>
class Handle {
public:
template <typename... Args> Handle(Args &&... args)
: m_cache(get_base()), m_obj(std::forward<Args>(args)...) {}
Handle(const Handle &) = delete;
Handle & operator=(const Handle &) = delete;
~Handle() { if (m_obj) cleanup(m_cache, get_unowning(m_obj)); }
void assign(const T & obj) { m_obj = obj; }
const T & get() const & noexcept { return m_obj; }
private:
const std::shared_ptr<Pimpl> m_cache;
T m_obj;
};
/*
* Function typedef for helpers passed in to allocate new objects.
* To reduce code size, the proxy cache type-erases the objects inside it.
*
* An allocator function takes an OwningImplPointer to the source language object,
* and returns a newly-created proxy.
*
* In Java, an OwningImplPointer does not provide the same identity semantics as the
* underlying object. (A JNI 'jobject' can be one of a few different types of reference,
* and JNI is structured to allow copying GCs, so an object's address might change over
* time.) This is why ProxyCache takes hasher and comparator paramters. In particular,
* the OwningImplPointer passed into the allocator might be a JNI local reference. The
* allocator will create a GlobalRef to the impl object and store it in the returned proxy.
*
* Because we don't constrain how Handle objects are held, there's no generic way for the
* proxy cache to get the GlobalRef out of the returned proxy object, so AllocatorFunction
* returns a pair: the first element is the newly created proxy, and the second is an
* UnowningImplPointer that will be used as a key in the map.
*/
using AllocatorFunction =
std::pair<OwningProxyPointer, UnowningImplPointer>(const OwningImplPointer &);
/*
* Return the existing proxy for `impl`, if any. If not, create one by calling `alloc`,
* store a weak reference to it in the proxy cache, and return it.
*/
static OwningProxyPointer get(const OwningImplPointer & impl, AllocatorFunction * alloc);
private:
static void cleanup(const std::shared_ptr<Pimpl> &, UnowningImplPointer);
static const std::shared_ptr<Pimpl> & get_base();
};
} // namespace djinni
......@@ -22,8 +22,14 @@
"CLANG_ENABLE_OBJC_ARC": "YES",
},
"sources": [
"objc/DJIWeakPtrWrapper.mm",
"objc/DJICppWrapperCache+Private.h",
"objc/DJIError.h",
"objc/DJIError.mm",
"objc/DJIMarshal+Private.h",
"objc/DJIObjcWrapperCache+Private.h",
"objc/DJIProxyCaches.mm",
"proxy_cache_impl.hpp",
"proxy_cache_interface.hpp",
],
"include_dirs": [
"objc",
......
......@@ -11,7 +11,7 @@ NativeClientInterface::NativeClientInterface() : ::djinni::JniInterface<::testsu
NativeClientInterface::~NativeClientInterface() = default;
NativeClientInterface::JavaProxy::JavaProxy(JniType j) : JavaProxyCacheEntry(j) { }
NativeClientInterface::JavaProxy::JavaProxy(JniType j) : Handle(::djinni::jniGetThreadEnv(), j) { }
NativeClientInterface::JavaProxy::~JavaProxy() = default;
......@@ -19,7 +19,7 @@ NativeClientInterface::JavaProxy::~JavaProxy() = default;
auto jniEnv = ::djinni::jniGetThreadEnv();
::djinni::JniLocalScope jscope(jniEnv, 10);
const auto& data = ::djinni::JniClass<::djinni_generated::NativeClientInterface>::get();
auto jret = jniEnv->CallObjectMethod(getGlobalRef(), data.method_getRecord,
auto jret = jniEnv->CallObjectMethod(Handle::get().get(), data.method_getRecord,
::djinni::get(::djinni::I64::fromCpp(jniEnv, c_record_id)),
::djinni::get(::djinni::String::fromCpp(jniEnv, c_utf8string)),
::djinni::get(::djinni::Optional<std::experimental::optional, ::djinni::String>::fromCpp(jniEnv, c_misc)));
......@@ -30,7 +30,7 @@ double NativeClientInterface::JavaProxy::identifier_check(const std::vector<uint
auto jniEnv = ::djinni::jniGetThreadEnv();
::djinni::JniLocalScope jscope(jniEnv, 10);
const auto& data = ::djinni::JniClass<::djinni_generated::NativeClientInterface>::get();
auto jret = jniEnv->CallDoubleMethod(getGlobalRef(), data.method_identifierCheck,
auto jret = jniEnv->CallDoubleMethod(Handle::get().get(), data.method_identifierCheck,
::djinni::get(::djinni::Binary::fromCpp(jniEnv, c_data)),
::djinni::get(::djinni::I32::fromCpp(jniEnv, c_r)),
::djinni::get(::djinni::I64::fromCpp(jniEnv, c_jret)));
......@@ -41,7 +41,7 @@ std::string NativeClientInterface::JavaProxy::return_str() {
auto jniEnv = ::djinni::jniGetThreadEnv();
::djinni::JniLocalScope jscope(jniEnv, 10);
const auto& data = ::djinni::JniClass<::djinni_generated::NativeClientInterface>::get();
auto jret = (jstring)jniEnv->CallObjectMethod(getGlobalRef(), data.method_returnStr);
auto jret = (jstring)jniEnv->CallObjectMethod(Handle::get().get(), data.method_returnStr);
::djinni::jniExceptionCheck(jniEnv);
return ::djinni::String::toCpp(jniEnv, jret);
}
......
......@@ -36,9 +36,7 @@ private:
std::string return_str() override;
private:
using ::djinni::JavaProxyCacheEntry::getGlobalRef;
friend ::djinni::JniInterface<::testsuite::ClientInterface, ::djinni_generated::NativeClientInterface>;
friend ::djinni::JavaProxyCache<JavaProxy>;
};
const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass("com/dropbox/djinni/test/ClientInterface") };
......
......@@ -23,7 +23,7 @@ CJNIEXPORT void JNICALL Java_com_dropbox_djinni_test_ConstantsInterface_00024Cpp
{
try {
DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);
const auto& ref = ::djinni::CppProxyHandle<::testsuite::ConstantsInterface>::get(nativeRef);
const auto& ref = ::djinni::objectFromHandleAddress<::testsuite::ConstantsInterface>(nativeRef);
ref->dummy();
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )
}
......
......@@ -24,7 +24,7 @@ CJNIEXPORT jint JNICALL Java_com_dropbox_djinni_test_CppException_00024CppProxy_
{
try {
DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);
const auto& ref = ::djinni::CppProxyHandle<::testsuite::CppException>::get(nativeRef);
const auto& ref = ::djinni::objectFromHandleAddress<::testsuite::CppException>(nativeRef);
auto r = ref->throw_an_exception();
return ::djinni::release(::djinni::I32::fromCpp(jniEnv, r));
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
......
......@@ -24,7 +24,7 @@ CJNIEXPORT ::djinni_generated::NativeClientReturnedRecord::JniType JNICALL Java_
{
try {
DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);
const auto& ref = ::djinni::CppProxyHandle<::ExternInterface1>::get(nativeRef);
const auto& ref = ::djinni::objectFromHandleAddress<::ExternInterface1>(nativeRef);
auto r = ref->foo(::djinni_generated::NativeClientInterface::toCpp(jniEnv, j_i));
return ::djinni::release(::djinni_generated::NativeClientReturnedRecord::fromCpp(jniEnv, r));
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
......
......@@ -11,7 +11,7 @@ NativeExternInterface2::NativeExternInterface2() : ::djinni::JniInterface<::Exte
NativeExternInterface2::~NativeExternInterface2() = default;
NativeExternInterface2::JavaProxy::JavaProxy(JniType j) : JavaProxyCacheEntry(j) { }
NativeExternInterface2::JavaProxy::JavaProxy(JniType j) : Handle(::djinni::jniGetThreadEnv(), j) { }
NativeExternInterface2::JavaProxy::~JavaProxy() = default;
......@@ -19,7 +19,7 @@ NativeExternInterface2::JavaProxy::~JavaProxy() = default;
auto jniEnv = ::djinni::jniGetThreadEnv();
::djinni::JniLocalScope jscope(jniEnv, 10);
const auto& data = ::djinni::JniClass<::djinni_generated::NativeExternInterface2>::get();
auto jret = jniEnv->CallObjectMethod(getGlobalRef(), data.method_foo,
auto jret = jniEnv->CallObjectMethod(Handle::get().get(), data.method_foo,
::djinni::get(::djinni_generated::NativeTestHelpers::fromCpp(jniEnv, c_i)));
::djinni::jniExceptionCheck(jniEnv);
return ::djinni_generated::NativeExternRecordWithDerivings::toCpp(jniEnv, jret);
......
......@@ -34,9 +34,7 @@ private:
::ExternRecordWithDerivings foo(const std::shared_ptr<::testsuite::TestHelpers> & i) override;
private:
using ::djinni::JavaProxyCacheEntry::getGlobalRef;
friend ::djinni::JniInterface<::ExternInterface2, ::djinni_generated::NativeExternInterface2>;
friend ::djinni::JavaProxyCache<JavaProxy>;
};
const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass("com/dropbox/djinni/test/ExternInterface2") };
......
......@@ -10,7 +10,7 @@ NativeUserToken::NativeUserToken() : ::djinni::JniInterface<::testsuite::UserTok
NativeUserToken::~NativeUserToken() = default;
NativeUserToken::JavaProxy::JavaProxy(JniType j) : JavaProxyCacheEntry(j) { }
NativeUserToken::JavaProxy::JavaProxy(JniType j) : Handle(::djinni::jniGetThreadEnv(), j) { }
NativeUserToken::JavaProxy::~JavaProxy() = default;
......@@ -18,7 +18,7 @@ std::string NativeUserToken::JavaProxy::whoami() {
auto jniEnv = ::djinni::jniGetThreadEnv();
::djinni::JniLocalScope jscope(jniEnv, 10);
const auto& data = ::djinni::JniClass<::djinni_generated::NativeUserToken>::get();
auto jret = (jstring)jniEnv->CallObjectMethod(getGlobalRef(), data.method_whoami);
auto jret = (jstring)jniEnv->CallObjectMethod(Handle::get().get(), data.method_whoami);
::djinni::jniExceptionCheck(jniEnv);
return ::djinni::String::toCpp(jniEnv, jret);
}
......@@ -35,7 +35,7 @@ CJNIEXPORT jstring JNICALL Java_com_dropbox_djinni_test_UserToken_00024CppProxy_
{
try {
DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);
const auto& ref = ::djinni::CppProxyHandle<::testsuite::UserToken>::get(nativeRef);
const auto& ref = ::djinni::objectFromHandleAddress<::testsuite::UserToken>(nativeRef);
auto r = ref->whoami();
return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
......
......@@ -34,9 +34,7 @@ private:
std::string whoami() override;
private:
using ::djinni::JavaProxyCacheEntry::getGlobalRef;
friend ::djinni::JniInterface<::testsuite::UserToken, ::djinni_generated::NativeUserToken>;
friend ::djinni::JavaProxyCache<JavaProxy>;
};
const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass("com/dropbox/djinni/test/UserToken") };
......
......@@ -13,14 +13,14 @@ namespace djinni_generated {
class ClientInterface::ObjcProxy final
: public ::testsuite::ClientInterface
, public ::djinni::DbxObjcWrapperCache<ObjcProxy>::Handle
, public ::djinni::ObjcProxyCache::Handle<ObjcType>
{
public:
using Handle::Handle;
::testsuite::ClientReturnedRecord get_record(int64_t c_record_id, const std::string & c_utf8string, const std::experimental::optional<std::string> & c_misc) override
{
@autoreleasepool {
auto r = [(ObjcType)Handle::get() getRecord:(::djinni::I64::fromCpp(c_record_id))
auto r = [Handle::get() getRecord:(::djinni::I64::fromCpp(c_record_id))
utf8string:(::djinni::String::fromCpp(c_utf8string))
misc:(::djinni::Optional<std::experimental::optional, ::djinni::String>::fromCpp(c_misc))];
return ::djinni_generated::ClientReturnedRecord::toCpp(r);
......@@ -29,7 +29,7 @@ public:
double identifier_check(const std::vector<uint8_t> & c_data, int32_t c_r, int64_t c_jret) override
{
@autoreleasepool {
auto r = [(ObjcType)Handle::get() identifierCheck:(::djinni::Binary::fromCpp(c_data))
auto r = [Handle::get() identifierCheck:(::djinni::Binary::fromCpp(c_data))
r:(::djinni::I32::fromCpp(c_r))
jret:(::djinni::I64::fromCpp(c_jret))];
return ::djinni::F64::toCpp(r);
......@@ -38,7 +38,7 @@ public:
std::string return_str() override
{
@autoreleasepool {
auto r = [(ObjcType)Handle::get() returnStr];
auto r = [Handle::get() returnStr];
return ::djinni::String::toCpp(r);
}
}
......@@ -53,7 +53,7 @@ auto ClientInterface::toCpp(ObjcType objc) -> CppType
if (!objc) {
return nullptr;
}
return ::djinni::DbxObjcWrapperCache<ObjcProxy>::getInstance()->get(objc);
return ::djinni::get_objc_proxy<ObjcProxy>(objc);
}
auto ClientInterface::fromCpp(const CppType& cpp) -> ObjcType
......
......@@ -18,7 +18,7 @@ static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for th
@end
@implementation DBConstantsInterface {
::djinni::DbxCppWrapperCache<::testsuite::ConstantsInterface>::Handle _cppRefHandle;
::djinni::CppProxyCache::Handle<std::shared_ptr<::testsuite::ConstantsInterface>> _cppRefHandle;
}
- (id)initWithCpp:(const std::shared_ptr<::testsuite::ConstantsInterface>&)cppRef
......@@ -50,9 +50,7 @@ auto ConstantsInterface::fromCpp(const CppType& cpp) -> ObjcType
if (!cpp) {
return nil;
}
return ::djinni::DbxCppWrapperCache<::testsuite::ConstantsInterface>::getInstance()->get(cpp, [] (const CppType& p) {
return [[DBConstantsInterface alloc] initWithCpp:p];
});
return ::djinni::get_cpp_proxy<DBConstantsInterface>(cpp);
}
} // namespace djinni_generated
......
......@@ -19,7 +19,7 @@ static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for th
@end
@implementation DBCppException {
::djinni::DbxCppWrapperCache<::testsuite::CppException>::Handle _cppRefHandle;
::djinni::CppProxyCache::Handle<std::shared_ptr<::testsuite::CppException>> _cppRefHandle;
}
- (id)initWithCpp:(const std::shared_ptr<::testsuite::CppException>&)cppRef
......@@ -59,9 +59,7 @@ auto CppException::fromCpp(const CppType& cpp) -> ObjcType
if (!cpp) {
return nil;
}
return ::djinni::DbxCppWrapperCache<::testsuite::CppException>::getInstance()->get(cpp, [] (const CppType& p) {
return [[DBCppException alloc] initWithCpp:p];
});
return ::djinni::get_cpp_proxy<DBCppException>(cpp);
}
} // namespace djinni_generated
......
......@@ -19,7 +19,7 @@ static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for th
@end
@implementation DBExternInterface1 {
::djinni::DbxCppWrapperCache<::ExternInterface1>::Handle _cppRefHandle;
::djinni::CppProxyCache::Handle<std::shared_ptr<::ExternInterface1>> _cppRefHandle;
}
- (id)initWithCpp:(const std::shared_ptr<::ExternInterface1>&)cppRef
......@@ -52,9 +52,7 @@ auto ExternInterface1::fromCpp(const CppType& cpp) -> ObjcType
if (!cpp) {
return nil;
}
return ::djinni::DbxCppWrapperCache<::ExternInterface1>::getInstance()->get(cpp, [] (const CppType& p) {
return [[DBExternInterface1 alloc] initWithCpp:p];
});
return ::djinni::get_cpp_proxy<DBExternInterface1>(cpp);
}
} // namespace djinni_generated
......
......@@ -13,14 +13,14 @@ namespace djinni_generated {
class ExternInterface2::ObjcProxy final
: public ::ExternInterface2
, public ::djinni::DbxObjcWrapperCache<ObjcProxy>::Handle
, public ::djinni::ObjcProxyCache::Handle<ObjcType>
{
public:
using Handle::Handle;
::ExternRecordWithDerivings foo(const std::shared_ptr<::testsuite::TestHelpers> & c_i) override
{
@autoreleasepool {
auto r = [(ObjcType)Handle::get() foo:(::djinni_generated::TestHelpers::fromCpp(c_i))];
auto r = [Handle::get() foo:(::djinni_generated::TestHelpers::fromCpp(c_i))];
return ::djinni_generated::ExternRecordWithDerivings::toCpp(r);
}
}
......@@ -35,7 +35,7 @@ auto ExternInterface2::toCpp(ObjcType objc) -> CppType
if (!objc) {
return nullptr;
}
return ::djinni::DbxObjcWrapperCache<ObjcProxy>::getInstance()->get(objc);
return ::djinni::get_objc_proxy<ObjcProxy>(objc);
}
auto ExternInterface2::fromCpp(const CppType& cpp) -> ObjcType
......
......@@ -19,7 +19,7 @@ static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for th
@end
@implementation DBTestDuration {
::djinni::DbxCppWrapperCache<::testsuite::TestDuration>::Handle _cppRefHandle;
::djinni::CppProxyCache::Handle<std::shared_ptr<::testsuite::TestDuration>> _cppRefHandle;
}
- (id)initWithCpp:(const std::shared_ptr<::testsuite::TestDuration>&)cppRef
......@@ -185,9 +185,7 @@ auto TestDuration::fromCpp(const CppType& cpp) -> ObjcType
if (!cpp) {
return nil;
}
return ::djinni::DbxCppWrapperCache<::testsuite::TestDuration>::getInstance()->get(cpp, [] (const CppType& p) {
return [[DBTestDuration alloc] initWithCpp:p];
});
return ::djinni::get_cpp_proxy<DBTestDuration>(cpp);
}
} // namespace djinni_generated
......
......@@ -25,7 +25,7 @@ static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for th
@end
@implementation DBTestHelpers {
::djinni::DbxCppWrapperCache<::testsuite::TestHelpers>::Handle _cppRefHandle;
::djinni::CppProxyCache::Handle<std::shared_ptr<::testsuite::TestHelpers>> _cppRefHandle;
}
- (id)initWithCpp:(const std::shared_ptr<::testsuite::TestHelpers>&)cppRef
......@@ -215,9 +215,7 @@ auto TestHelpers::fromCpp(const CppType& cpp) -> ObjcType
if (!cpp) {
return nil;
}
return ::djinni::DbxCppWrapperCache<::testsuite::TestHelpers>::getInstance()->get(cpp, [] (const CppType& p) {
return [[DBTestHelpers alloc] initWithCpp:p];
});
return ::djinni::get_cpp_proxy<DBTestHelpers>(cpp);
}
} // namespace djinni_generated
......
......@@ -19,7 +19,7 @@ static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for th
@end
@implementation DBUserTokenCppProxy {
::djinni::DbxCppWrapperCache<::testsuite::UserToken>::Handle _cppRefHandle;
::djinni::CppProxyCache::Handle<std::shared_ptr<::testsuite::UserToken>> _cppRefHandle;
}
- (id)initWithCpp:(const std::shared_ptr<::testsuite::UserToken>&)cppRef
......@@ -41,14 +41,14 @@ namespace djinni_generated {
class UserToken::ObjcProxy final
: public ::testsuite::UserToken
, public ::djinni::DbxObjcWrapperCache<ObjcProxy>::Handle
, public ::djinni::ObjcProxyCache::Handle<ObjcType>
{
public:
using Handle::Handle;
std::string whoami() override
{
@autoreleasepool {
auto r = [(ObjcType)Handle::get() whoami];
auto r = [Handle::get() whoami];
return ::djinni::String::toCpp(r);
}
}
......@@ -66,7 +66,7 @@ auto UserToken::toCpp(ObjcType objc) -> CppType
if ([(id)objc isKindOfClass:[DBUserTokenCppProxy class]]) {
return ((DBUserTokenCppProxy*)objc)->_cppRefHandle.get();
}
return ::djinni::DbxObjcWrapperCache<ObjcProxy>::getInstance()->get(objc);
return ::djinni::get_objc_proxy<ObjcProxy>(objc);
}
auto UserToken::fromCpp(const CppType& cpp) -> ObjcType
......@@ -77,9 +77,7 @@ auto UserToken::fromCpp(const CppType& cpp) -> ObjcType
if (auto cppPtr = dynamic_cast<ObjcProxy*>(cpp.get())) {
return cppPtr->Handle::get();
}
return ::djinni::DbxCppWrapperCache<::testsuite::UserToken>::getInstance()->get(cpp, [] (const CppType& p) {
return [[DBUserTokenCppProxy alloc] initWithCpp:p];
});
return ::djinni::get_cpp_proxy<DBUserTokenCppProxy>(cpp);
}
} // namespace djinni_generated
......
......@@ -7,7 +7,6 @@
objects = {
/* Begin PBXBuildFile section */
6536CD6F19A6C82200DD7715 /* DJIWeakPtrWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6536CD6C19A6C82200DD7715 /* DJIWeakPtrWrapper.mm */; };
6536CD7419A6C96C00DD7715 /* DBClientInterfaceImpl.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6536CD7219A6C96C00DD7715 /* DBClientInterfaceImpl.mm */; };
6536CD7819A6C98800DD7715 /* cpp_exception_impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6536CD7619A6C98800DD7715 /* cpp_exception_impl.cpp */; };
6536CD8D19A6C9A800DD7715 /* DBClientInterfaceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6536CD7A19A6C99800DD7715 /* DBClientInterfaceTests.mm */; };
......@@ -122,8 +121,7 @@
/* Begin PBXFileReference section */
6536CD6A19A6C82200DD7715 /* DJIError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DJIError.h; sourceTree = "<group>"; };
6536CD6B19A6C82200DD7715 /* DJIWeakPtrWrapper+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "DJIWeakPtrWrapper+Private.h"; sourceTree = "<group>"; };
6536CD6C19A6C82200DD7715 /* DJIWeakPtrWrapper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DJIWeakPtrWrapper.mm; sourceTree = "<group>"; };
6536CD6C19A6C82200DD7715 /* DJIProxyCaches.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DJIProxyCaches.mm; sourceTree = "<group>"; };
6536CD6D19A6C82200DD7715 /* DJICppWrapperCache+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "DJICppWrapperCache+Private.h"; sourceTree = "<group>"; };
6536CD6E19A6C82200DD7715 /* DJIObjcWrapperCache+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "DJIObjcWrapperCache+Private.h"; sourceTree = "<group>"; };
6536CD7119A6C96C00DD7715 /* DBClientInterfaceImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBClientInterfaceImpl.h; sourceTree = "<group>"; };
......@@ -305,8 +303,7 @@
A239F3791AF400C600DF27C8 /* DJIMarshal+Private.h */,
A2CB54B319BA6E6000A9E600 /* DJIError.mm */,
6536CD6A19A6C82200DD7715 /* DJIError.h */,
6536CD6B19A6C82200DD7715 /* DJIWeakPtrWrapper+Private.h */,
6536CD6C19A6C82200DD7715 /* DJIWeakPtrWrapper.mm */,
6536CD6C19A6C82200DD7715 /* DJIProxyCaches.mm */,
6536CD6D19A6C82200DD7715 /* DJICppWrapperCache+Private.h */,
6536CD6E19A6C82200DD7715 /* DJIObjcWrapperCache+Private.h */,
);
......@@ -613,7 +610,7 @@
CFC5D9E81B1513E800BF2DF8 /* DBExternInterface1+Private.mm in Sources */,
A24850311AF96EBC00AFE907 /* DBSetRecord.mm in Sources */,
CFAED8761B54291900E3B8A3 /* DBEmptyRecord+Private.mm in Sources */,
6536CD6F19A6C82200DD7715 /* DJIWeakPtrWrapper.mm in Sources */,
6536CD6F19A6C82200DD7715 /* DJIProxyCaches.mm in Sources */,
A24850271AF96EBC00AFE907 /* DBClientReturnedRecord.mm in Sources */,
CFC5D9D61B15106400BF2DF8 /* DBExternRecordWithDerivings.mm in Sources */,
CFC5DA0E1B15330000BF2DF8 /* record_with_duration_and_derivings.cpp in Sources */,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment