Commit 28d70153 authored by Jacob Potter's avatar Jacob Potter

Fix wrapper cache interaction with static destruction

parent 762a27b3
......@@ -16,26 +16,30 @@
static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file");
@interface TXSSortItemsCppProxy ()
@property (nonatomic, readonly) std::shared_ptr<djinni::DbxCppWrapperCache<::textsort::SortItems>> cache;
@end
@implementation TXSSortItemsCppProxy
- (id)initWithCpp:(const std::shared_ptr<::textsort::SortItems> &)cppRef
- (id)initWithCpp:(const std::shared_ptr<::textsort::SortItems> &)cppRef cache:(const std::shared_ptr<djinni::DbxCppWrapperCache<::textsort::SortItems>> &)cache
{
if (self = [super init]) {
_cppRef = cppRef;
_cache = cache;
}
return self;
}
- (void)dealloc
{
djinni::DbxCppWrapperCache<::textsort::SortItems> & cache = djinni::DbxCppWrapperCache<::textsort::SortItems>::getInstance();
cache.remove(_cppRef);
_cache->remove(_cppRef);
}
+ (id)sortItemsWithCpp:(const std::shared_ptr<::textsort::SortItems> &)cppRef
{
djinni::DbxCppWrapperCache<::textsort::SortItems> & cache = djinni::DbxCppWrapperCache<::textsort::SortItems>::getInstance();
return cache.get(cppRef, [] (const std::shared_ptr<::textsort::SortItems> & p) { return [[TXSSortItemsCppProxy alloc] initWithCpp:p]; });
const auto & cache = djinni::DbxCppWrapperCache<::textsort::SortItems>::getInstance();
return cache->get(cppRef, [&] (const std::shared_ptr<::textsort::SortItems> & p) { return [[TXSSortItemsCppProxy alloc] initWithCpp:p cache:cache]; });
}
- (void)sort:(TXSSortOrder)order items:(TXSItemList *)items {
......
......@@ -12,7 +12,9 @@ namespace djinni_generated {
class TextboxListenerObjcProxy final : public ::textsort::TextboxListener
{
public:
id <TXSTextboxListener> objcRef;
const id <TXSTextboxListener> _objcRef;
const std::shared_ptr<djinni::DbxObjcWrapperCache<TextboxListenerObjcProxy>> _cache;
explicit TextboxListenerObjcProxy (id objcRef);
virtual ~TextboxListenerObjcProxy () override;
static std::shared_ptr<::textsort::TextboxListener> textbox_listener_with_objc (id objcRef);
......
......@@ -9,28 +9,25 @@
namespace djinni_generated {
TextboxListenerObjcProxy::TextboxListenerObjcProxy (id objcRef)
{
assert([[objcRef class] conformsToProtocol:@protocol(TXSTextboxListener)]);
this->objcRef = objcRef;
}
: _objcRef((assert([[objcRef class] conformsToProtocol:@protocol(TXSTextboxListener)]), objcRef)),
_cache(djinni::DbxObjcWrapperCache<TextboxListenerObjcProxy>::getInstance())
{}
TextboxListenerObjcProxy::~TextboxListenerObjcProxy ()
{
djinni::DbxObjcWrapperCache<TextboxListenerObjcProxy> & cache = djinni::DbxObjcWrapperCache<TextboxListenerObjcProxy>::getInstance();
cache.remove(objcRef);
_cache->remove(_objcRef);
}
std::shared_ptr<::textsort::TextboxListener> TextboxListenerObjcProxy::textbox_listener_with_objc (id objcRef)
{
djinni::DbxObjcWrapperCache<TextboxListenerObjcProxy> & cache = djinni::DbxObjcWrapperCache<TextboxListenerObjcProxy>::getInstance();
return static_cast<std::shared_ptr<::textsort::TextboxListener>>(cache.get(objcRef));
return djinni::DbxObjcWrapperCache<TextboxListenerObjcProxy>::getInstance()->get(objcRef);
}
void TextboxListenerObjcProxy::update (const ::textsort::ItemList & items)
{
@autoreleasepool {
TXSItemList *cpp_items = [[TXSItemList alloc] initWithCppItemList:items];
[objcRef update:cpp_items];
[_objcRef update:cpp_items];
}
}
......
......@@ -264,26 +264,30 @@ class ObjcGenerator(spec: Spec) extends Generator(spec) {
writeObjcFile(bodyName(cppExtName), origin, refs.body, w => {
w.wl(s"static_assert(__has_feature(objc_arc), " + q("Djinni requires ARC to be enabled for this file") + ");" )
w.wl
w.wl(s"@interface $cppExtSelf ()")
w.wl(s"@property (nonatomic, readonly) std::shared_ptr<djinni::DbxCppWrapperCache<$cppName>> cache;")
w.wl("@end")
w.wl
w.wl(s"@implementation $cppExtSelf")
w.wl
w.wl(s"- (id)initWithCpp:(const std::shared_ptr<$cppName> &)cppRef")
w.wl(s"- (id)initWithCpp:(const std::shared_ptr<$cppName> &)cppRef cache:(const std::shared_ptr<djinni::DbxCppWrapperCache<$cppName>> &)cache")
w.braced {
w.w("if (self = [super init])").braced {
w.wl("_cppRef = cppRef;")
w.wl("_cache = cache;")
}
w.wl("return self;")
}
w.wl
w.wl(s"- (void)dealloc")
w.braced {
w.wl(s"djinni::DbxCppWrapperCache<$cppName> & cache = djinni::DbxCppWrapperCache<$cppName>::getInstance();")
w.wl("cache.remove(_cppRef);")
w.wl("_cache->remove(_cppRef);")
}
w.wl
w.wl(s"+ (id)${idObjc.method(ident.name + "_with_cpp")}:(const std::shared_ptr<$cppName> &)cppRef")
w.braced {
w.wl(s"djinni::DbxCppWrapperCache<$cppName> & cache = djinni::DbxCppWrapperCache<$cppName>::getInstance();")
w.wl(s"return cache.get(cppRef, [] (const std::shared_ptr<$cppName> & p) { return [[$cppExtSelf alloc] initWithCpp:p]; });")
w.wl(s"const auto & cache = djinni::DbxCppWrapperCache<$cppName>::getInstance();")
w.wl(s"return cache->get(cppRef, [&] (const std::shared_ptr<$cppName> & p) { return [[$cppExtSelf alloc] initWithCpp:p cache:cache]; });")
}
for (m <- i.methods) {
w.wl
......@@ -321,7 +325,9 @@ class ObjcGenerator(spec: Spec) extends Generator(spec) {
wrapNamespace(w, Some(spec.objcppNamespace), (w: IndentWriter) => {
w.wl(s"class $objcExtSelf final : public ${withNs(spec.cppNamespace, idCpp.ty(ident))}").bracedSemi {
w.wl("public:")
w.wl(s"id <$self> objcRef;")
w.wl(s"const id <$self> _objcRef;")
w.wl(s"const std::shared_ptr<djinni::DbxObjcWrapperCache<$objcExtSelf>> _cache;")
w.wl
w.wl(s"explicit $objcExtSelf (id objcRef);")
w.wl(s"virtual ~$objcExtSelf () override;")
w.wl(s"static std::shared_ptr<${withNs(spec.cppNamespace, idCpp.ty(ident.name))}> ${idCpp.method(ident.name + "_with_objc")} (id objcRef);")
......@@ -336,19 +342,17 @@ class ObjcGenerator(spec: Spec) extends Generator(spec) {
writeObjcFile(bodyName(objcExtName), origin, refs.body, w => {
wrapNamespace(w, Some(spec.objcppNamespace), (w: IndentWriter) => {
w.wl(s"$objcExtSelf::$objcExtSelf (id objcRef)").braced {
w.wl(s"assert([[objcRef class] conformsToProtocol:@protocol($self)]);")
w.wl("this->objcRef = objcRef;")
}
w.wl(s"$objcExtSelf::$objcExtSelf (id objcRef)")
w.wl(s" : _objcRef((assert([[objcRef class] conformsToProtocol:@protocol($self)]), objcRef)),")
w.wl(s" _cache(djinni::DbxObjcWrapperCache<$objcExtSelf>::getInstance())")
w.wl(s" {}")
w.wl
w.wl(s"$objcExtSelf::~$objcExtSelf ()").braced {
w.wl(s"djinni::DbxObjcWrapperCache<$objcExtSelf> & cache = djinni::DbxObjcWrapperCache<$objcExtSelf>::getInstance();")
w.wl(s"cache.remove(objcRef);")
w.wl(s"_cache->remove(_objcRef);")
}
w.wl
w.wl(s"std::shared_ptr<${withNs(spec.cppNamespace, idCpp.ty(ident))}> $objcExtSelf::${idCpp.method(ident.name + "_with_objc")} (id objcRef)").braced {
w.wl(s"djinni::DbxObjcWrapperCache<$objcExtSelf> & cache = djinni::DbxObjcWrapperCache<$objcExtSelf>::getInstance();")
w.wl(s"return static_cast<std::shared_ptr<${withNs(spec.cppNamespace, idCpp.ty(ident.name))}>>(cache.get(objcRef));")
w.wl(s"return djinni::DbxObjcWrapperCache<$objcExtSelf>::getInstance()->get(objcRef);")
}
for (m <- i.methods) {
w.wl
......@@ -359,7 +363,7 @@ class ObjcGenerator(spec: Spec) extends Generator(spec) {
m.params.foreach(p =>
translateCppTypeToObjc(idCpp.local("cpp_" + p.ident.name), idCpp.local(p.ident), p.ty, true, w))
m.ret.fold()(r => w.w(toObjcTypeDef(r) + "objcRet = "))
w.w("[objcRef " + idObjc.method(m.ident))
w.w("[_objcRef " + idObjc.method(m.ident))
val skipFirst = SkipFirst()
for (p <- m.params) {
skipFirst { w.w(" " + idObjc.local(p.ident)) }
......
......@@ -26,8 +26,10 @@ namespace djinni {
template <class T>
class DbxCppWrapperCache {
public:
static DbxCppWrapperCache & getInstance() {
static DbxCppWrapperCache instance;
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;
}
......
......@@ -27,8 +27,10 @@ namespace djinni {
template <class T>
class DbxObjcWrapperCache {
public:
static DbxObjcWrapperCache & getInstance() {
static DbxObjcWrapperCache instance;
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;
}
......
......@@ -12,7 +12,9 @@ namespace djinni_generated {
class ClientInterfaceObjcProxy final : public ClientInterface
{
public:
id <DBClientInterface> objcRef;
const id <DBClientInterface> _objcRef;
const std::shared_ptr<djinni::DbxObjcWrapperCache<ClientInterfaceObjcProxy>> _cache;
explicit ClientInterfaceObjcProxy (id objcRef);
virtual ~ClientInterfaceObjcProxy () override;
static std::shared_ptr<ClientInterface> client_interface_with_objc (id objcRef);
......
......@@ -9,21 +9,18 @@
namespace djinni_generated {
ClientInterfaceObjcProxy::ClientInterfaceObjcProxy (id objcRef)
{
assert([[objcRef class] conformsToProtocol:@protocol(DBClientInterface)]);
this->objcRef = objcRef;
}
: _objcRef((assert([[objcRef class] conformsToProtocol:@protocol(DBClientInterface)]), objcRef)),
_cache(djinni::DbxObjcWrapperCache<ClientInterfaceObjcProxy>::getInstance())
{}
ClientInterfaceObjcProxy::~ClientInterfaceObjcProxy ()
{
djinni::DbxObjcWrapperCache<ClientInterfaceObjcProxy> & cache = djinni::DbxObjcWrapperCache<ClientInterfaceObjcProxy>::getInstance();
cache.remove(objcRef);
_cache->remove(_objcRef);
}
std::shared_ptr<ClientInterface> ClientInterfaceObjcProxy::client_interface_with_objc (id objcRef)
{
djinni::DbxObjcWrapperCache<ClientInterfaceObjcProxy> & cache = djinni::DbxObjcWrapperCache<ClientInterfaceObjcProxy>::getInstance();
return static_cast<std::shared_ptr<ClientInterface>>(cache.get(objcRef));
return djinni::DbxObjcWrapperCache<ClientInterfaceObjcProxy>::getInstance()->get(objcRef);
}
ClientReturnedRecord ClientInterfaceObjcProxy::get_record (int64_t record_id, const std::string & utf8string)
......@@ -33,7 +30,7 @@ ClientReturnedRecord ClientInterfaceObjcProxy::get_record (int64_t record_id, co
NSString *cpp_utf8string = [[NSString alloc] initWithBytes:utf8string.data()
length:utf8string.length()
encoding:NSUTF8StringEncoding];
DBClientReturnedRecord *objcRet = [objcRef getRecord:cpp_record_id utf8string:cpp_utf8string];
DBClientReturnedRecord *objcRet = [_objcRef getRecord:cpp_record_id utf8string:cpp_utf8string];
ClientReturnedRecord cppRet = std::move([objcRet cppClientReturnedRecord]);
return cppRet;
}
......
......@@ -12,26 +12,30 @@
static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file");
@interface DBCppExceptionCppProxy ()
@property (nonatomic, readonly) std::shared_ptr<djinni::DbxCppWrapperCache<CppException>> cache;
@end
@implementation DBCppExceptionCppProxy
- (id)initWithCpp:(const std::shared_ptr<CppException> &)cppRef
- (id)initWithCpp:(const std::shared_ptr<CppException> &)cppRef cache:(const std::shared_ptr<djinni::DbxCppWrapperCache<CppException>> &)cache
{
if (self = [super init]) {
_cppRef = cppRef;
_cache = cache;
}
return self;
}
- (void)dealloc
{
djinni::DbxCppWrapperCache<CppException> & cache = djinni::DbxCppWrapperCache<CppException>::getInstance();
cache.remove(_cppRef);
_cache->remove(_cppRef);
}
+ (id)cppExceptionWithCpp:(const std::shared_ptr<CppException> &)cppRef
{
djinni::DbxCppWrapperCache<CppException> & cache = djinni::DbxCppWrapperCache<CppException>::getInstance();
return cache.get(cppRef, [] (const std::shared_ptr<CppException> & p) { return [[DBCppExceptionCppProxy alloc] initWithCpp:p]; });
const auto & cache = djinni::DbxCppWrapperCache<CppException>::getInstance();
return cache->get(cppRef, [&] (const std::shared_ptr<CppException> & p) { return [[DBCppExceptionCppProxy alloc] initWithCpp:p cache:cache]; });
}
- (int32_t)throwAnException {
......
......@@ -20,26 +20,30 @@
static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file");
@interface DBTestHelpersCppProxy ()
@property (nonatomic, readonly) std::shared_ptr<djinni::DbxCppWrapperCache<TestHelpers>> cache;
@end
@implementation DBTestHelpersCppProxy
- (id)initWithCpp:(const std::shared_ptr<TestHelpers> &)cppRef
- (id)initWithCpp:(const std::shared_ptr<TestHelpers> &)cppRef cache:(const std::shared_ptr<djinni::DbxCppWrapperCache<TestHelpers>> &)cache
{
if (self = [super init]) {
_cppRef = cppRef;
_cache = cache;
}
return self;
}
- (void)dealloc
{
djinni::DbxCppWrapperCache<TestHelpers> & cache = djinni::DbxCppWrapperCache<TestHelpers>::getInstance();
cache.remove(_cppRef);
_cache->remove(_cppRef);
}
+ (id)testHelpersWithCpp:(const std::shared_ptr<TestHelpers> &)cppRef
{
djinni::DbxCppWrapperCache<TestHelpers> & cache = djinni::DbxCppWrapperCache<TestHelpers>::getInstance();
return cache.get(cppRef, [] (const std::shared_ptr<TestHelpers> & p) { return [[DBTestHelpersCppProxy alloc] initWithCpp:p]; });
const auto & cache = djinni::DbxCppWrapperCache<TestHelpers>::getInstance();
return cache->get(cppRef, [&] (const std::shared_ptr<TestHelpers> & p) { return [[DBTestHelpersCppProxy alloc] initWithCpp:p cache:cache]; });
}
+ (DBSetRecord *)getSetRecord {
......
......@@ -11,26 +11,30 @@
static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file");
@interface DBTokenCppProxy ()
@property (nonatomic, readonly) std::shared_ptr<djinni::DbxCppWrapperCache<Token>> cache;
@end
@implementation DBTokenCppProxy
- (id)initWithCpp:(const std::shared_ptr<Token> &)cppRef
- (id)initWithCpp:(const std::shared_ptr<Token> &)cppRef cache:(const std::shared_ptr<djinni::DbxCppWrapperCache<Token>> &)cache
{
if (self = [super init]) {
_cppRef = cppRef;
_cache = cache;
}
return self;
}
- (void)dealloc
{
djinni::DbxCppWrapperCache<Token> & cache = djinni::DbxCppWrapperCache<Token>::getInstance();
cache.remove(_cppRef);
_cache->remove(_cppRef);
}
+ (id)tokenWithCpp:(const std::shared_ptr<Token> &)cppRef
{
djinni::DbxCppWrapperCache<Token> & cache = djinni::DbxCppWrapperCache<Token>::getInstance();
return cache.get(cppRef, [] (const std::shared_ptr<Token> & p) { return [[DBTokenCppProxy alloc] initWithCpp:p]; });
const auto & cache = djinni::DbxCppWrapperCache<Token>::getInstance();
return cache->get(cppRef, [&] (const std::shared_ptr<Token> & p) { return [[DBTokenCppProxy alloc] initWithCpp:p cache:cache]; });
}
@end
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