react-native-nitro-modules 0.22.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +1 -1
- package/android/gradle.properties +1 -1
- package/android/src/main/java/com/margelo/nitro/views/HybridView.kt +11 -0
- package/cpp/core/ArrayBuffer.cpp +2 -2
- package/cpp/core/ArrayBuffer.hpp +3 -3
- package/cpp/core/HybridFunction.hpp +3 -0
- package/cpp/core/HybridObject.hpp +1 -1
- package/cpp/core/Promise.hpp +3 -3
- package/cpp/jsi/JSICache.cpp +4 -4
- package/cpp/jsi/JSICache.hpp +18 -18
- package/cpp/jsi/JSIConverter+Function.hpp +3 -2
- package/cpp/prototype/HybridObjectPrototype.cpp +2 -2
- package/cpp/prototype/HybridObjectPrototype.hpp +2 -2
- package/cpp/registry/HybridObjectRegistry.cpp +3 -0
- package/cpp/utils/BorrowingReference.hpp +161 -54
- package/cpp/utils/NitroDefines.hpp +1 -11
- package/cpp/utils/OwningLock.hpp +14 -14
- package/cpp/utils/ReferenceState.hpp +40 -0
- package/cpp/utils/WeakReference+Owning.hpp +33 -0
- package/cpp/utils/WeakReference.hpp +102 -0
- package/cpp/views/CachedProp.hpp +3 -3
- package/ios/core/AnyMapHolder.swift +8 -8
- package/ios/turbomodule/NativeNitroModules+NewArch.mm +1 -1
- package/lib/commonjs/index.js +11 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/views/HybridView.js +0 -11
- package/lib/commonjs/views/HybridView.js.map +1 -1
- package/lib/commonjs/views/getHostComponent.js +20 -1
- package/lib/commonjs/views/getHostComponent.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/views/HybridView.js +0 -26
- package/lib/module/views/HybridView.js.map +1 -1
- package/lib/module/views/getHostComponent.js +21 -1
- package/lib/module/views/getHostComponent.js.map +1 -1
- package/lib/tsconfig.build.tsbuildinfo +1 -1
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/views/HybridView.d.ts +89 -16
- package/lib/typescript/views/HybridView.d.ts.map +1 -1
- package/lib/typescript/views/getHostComponent.d.ts +46 -3
- package/lib/typescript/views/getHostComponent.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/index.ts +2 -0
- package/src/views/HybridView.ts +96 -18
- package/src/views/getHostComponent.ts +67 -5
- package/cpp/utils/BorrowingReference+Owning.hpp +0 -36
- package/cpp/utils/OwningReference.hpp +0 -250
package/android/build.gradle
CHANGED
|
@@ -20,4 +20,15 @@ abstract class HybridView: HybridObject() {
|
|
|
20
20
|
@get:DoNotStrip
|
|
21
21
|
@get:Keep
|
|
22
22
|
abstract val view: View
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Called right before updating props.
|
|
26
|
+
* React props are updated in a single batch/transaction.
|
|
27
|
+
*/
|
|
28
|
+
open fun beforeUpdate() { /* noop */ }
|
|
29
|
+
/**
|
|
30
|
+
* Called right after updating props.
|
|
31
|
+
* React props are updated in a single batch/transaction.
|
|
32
|
+
*/
|
|
33
|
+
open fun afterUpdate() { /* noop */ }
|
|
23
34
|
}
|
package/cpp/core/ArrayBuffer.cpp
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
//
|
|
7
7
|
|
|
8
8
|
#include "ArrayBuffer.hpp"
|
|
9
|
-
#include "
|
|
9
|
+
#include "BorrowingReference.hpp"
|
|
10
10
|
#include <functional>
|
|
11
11
|
#include <jsi/jsi.h>
|
|
12
12
|
#include <thread>
|
|
@@ -61,7 +61,7 @@ bool NativeArrayBuffer::isOwner() const noexcept {
|
|
|
61
61
|
|
|
62
62
|
// 3. JSArrayBuffer
|
|
63
63
|
|
|
64
|
-
JSArrayBuffer::JSArrayBuffer(jsi::Runtime* runtime,
|
|
64
|
+
JSArrayBuffer::JSArrayBuffer(jsi::Runtime* runtime, BorrowingReference<jsi::ArrayBuffer> jsReference)
|
|
65
65
|
: ArrayBuffer(), _runtime(runtime), _jsReference(jsReference), _initialThreadId(std::this_thread::get_id()) {}
|
|
66
66
|
|
|
67
67
|
JSArrayBuffer::~JSArrayBuffer() {}
|
package/cpp/core/ArrayBuffer.hpp
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
#pragma once
|
|
9
9
|
|
|
10
|
-
#include "
|
|
10
|
+
#include "BorrowingReference.hpp"
|
|
11
11
|
#include <jsi/jsi.h>
|
|
12
12
|
#include <thread>
|
|
13
13
|
#include <vector>
|
|
@@ -122,7 +122,7 @@ private:
|
|
|
122
122
|
*/
|
|
123
123
|
class JSArrayBuffer final : public ArrayBuffer {
|
|
124
124
|
public:
|
|
125
|
-
explicit JSArrayBuffer(jsi::Runtime* runtime,
|
|
125
|
+
explicit JSArrayBuffer(jsi::Runtime* runtime, BorrowingReference<jsi::ArrayBuffer> jsReference);
|
|
126
126
|
~JSArrayBuffer();
|
|
127
127
|
|
|
128
128
|
public:
|
|
@@ -141,7 +141,7 @@ public:
|
|
|
141
141
|
|
|
142
142
|
private:
|
|
143
143
|
jsi::Runtime* _runtime;
|
|
144
|
-
|
|
144
|
+
BorrowingReference<jsi::ArrayBuffer> _jsReference;
|
|
145
145
|
std::thread::id _initialThreadId;
|
|
146
146
|
};
|
|
147
147
|
|
|
@@ -109,12 +109,15 @@ public:
|
|
|
109
109
|
std::string message = exception.what();
|
|
110
110
|
throw jsi::JSError(runtime, funcName + ": " + message);
|
|
111
111
|
#ifdef ANDROID
|
|
112
|
+
#pragma clang diagnostic push
|
|
113
|
+
#pragma clang diagnostic ignored "-Wexceptions"
|
|
112
114
|
// Workaround for https://github.com/mrousavy/nitro/issues/382
|
|
113
115
|
} catch (const std::runtime_error& exception) {
|
|
114
116
|
// Some exception was thrown - add method name information and re-throw as `JSError`.
|
|
115
117
|
std::string funcName = getHybridFuncFullName<THybrid>(kind, name, hybridInstance.get());
|
|
116
118
|
std::string message = exception.what();
|
|
117
119
|
throw jsi::JSError(runtime, funcName + ": " + message);
|
|
120
|
+
#pragma clang diagnostic pop
|
|
118
121
|
#endif
|
|
119
122
|
} catch (...) {
|
|
120
123
|
// Some unknown exception was thrown - add method name information and re-throw as `JSError`.
|
|
@@ -136,7 +136,7 @@ protected:
|
|
|
136
136
|
private:
|
|
137
137
|
static constexpr auto TAG = "HybridObject";
|
|
138
138
|
const char* _name = TAG;
|
|
139
|
-
std::unordered_map<jsi::Runtime*,
|
|
139
|
+
std::unordered_map<jsi::Runtime*, BorrowingReference<jsi::WeakObject>> _objectCache;
|
|
140
140
|
};
|
|
141
141
|
|
|
142
142
|
} // namespace margelo::nitro
|
package/cpp/core/Promise.hpp
CHANGED
|
@@ -30,7 +30,7 @@ public:
|
|
|
30
30
|
Promise(const Promise&) = delete;
|
|
31
31
|
|
|
32
32
|
private:
|
|
33
|
-
Promise()
|
|
33
|
+
Promise() = default;
|
|
34
34
|
|
|
35
35
|
public:
|
|
36
36
|
~Promise() {
|
|
@@ -264,13 +264,13 @@ public:
|
|
|
264
264
|
Promise(const Promise&) = delete;
|
|
265
265
|
|
|
266
266
|
private:
|
|
267
|
-
Promise()
|
|
267
|
+
Promise() = default;
|
|
268
268
|
|
|
269
269
|
public:
|
|
270
270
|
~Promise() {
|
|
271
271
|
if (isPending()) [[unlikely]] {
|
|
272
272
|
std::runtime_error error("Timeouted: Promise<void> was destroyed!");
|
|
273
|
-
reject(std::make_exception_ptr(
|
|
273
|
+
reject(std::make_exception_ptr(error));
|
|
274
274
|
}
|
|
275
275
|
}
|
|
276
276
|
|
package/cpp/jsi/JSICache.cpp
CHANGED
|
@@ -14,12 +14,12 @@ namespace margelo::nitro {
|
|
|
14
14
|
static constexpr auto CACHE_PROP_NAME = "__nitroModulesJSICache";
|
|
15
15
|
|
|
16
16
|
template <typename T>
|
|
17
|
-
inline void destroyReferences(const std::vector<
|
|
17
|
+
inline void destroyReferences(const std::vector<WeakReference<T>>& references) {
|
|
18
18
|
for (auto& func : references) {
|
|
19
|
-
|
|
20
|
-
if (
|
|
19
|
+
BorrowingReference<T> reference = func.lock();
|
|
20
|
+
if (reference) {
|
|
21
21
|
// Destroy all functions that we might still have in cache, some callbacks and Promises may now become invalid.
|
|
22
|
-
|
|
22
|
+
reference.destroy();
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
}
|
package/cpp/jsi/JSICache.hpp
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
#include "BorrowingReference.hpp"
|
|
11
11
|
#include "NitroLogger.hpp"
|
|
12
|
-
#include "
|
|
12
|
+
#include "WeakReference.hpp"
|
|
13
13
|
#include <jsi/jsi.h>
|
|
14
14
|
#include <memory>
|
|
15
15
|
#include <mutex>
|
|
@@ -24,12 +24,12 @@ class JSICacheReference;
|
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* A `JSICache` can safely store `jsi::Value` instances (e.g. `jsi::Object` or
|
|
27
|
-
* `jsi::Function`) inside `
|
|
27
|
+
* `jsi::Function`) inside `BorrowingReference<T>`.
|
|
28
28
|
*
|
|
29
29
|
* `jsi::Value`s are managed by a `jsi::Runtime`, and will be deleted if the `jsi::Runtime`
|
|
30
30
|
* is deleted - even if there are still strong references to the `jsi::Value`.
|
|
31
31
|
*
|
|
32
|
-
* To access a `
|
|
32
|
+
* To access a `BorrowingReference<jsi::Value>` safely, use `lock()` to get an `OwningLock<jsi::Value>`.
|
|
33
33
|
* This will allow you to access the `jsi::Value` as long as the `OwningLock` is alive,
|
|
34
34
|
* and `JSICache` will hold any garbage collection calls until the `OwningLock` is destroyed.
|
|
35
35
|
*/
|
|
@@ -59,11 +59,11 @@ private:
|
|
|
59
59
|
|
|
60
60
|
private:
|
|
61
61
|
std::mutex _mutex;
|
|
62
|
-
std::vector<
|
|
63
|
-
std::vector<
|
|
64
|
-
std::vector<
|
|
65
|
-
std::vector<
|
|
66
|
-
std::vector<
|
|
62
|
+
std::vector<WeakReference<jsi::Value>> _valueCache;
|
|
63
|
+
std::vector<WeakReference<jsi::Object>> _objectCache;
|
|
64
|
+
std::vector<WeakReference<jsi::Function>> _functionCache;
|
|
65
|
+
std::vector<WeakReference<jsi::WeakObject>> _weakObjectCache;
|
|
66
|
+
std::vector<WeakReference<jsi::ArrayBuffer>> _arrayBufferCache;
|
|
67
67
|
|
|
68
68
|
private:
|
|
69
69
|
static inline std::unordered_map<jsi::Runtime*, std::weak_ptr<JSICache>> _globalCache;
|
|
@@ -83,28 +83,28 @@ public:
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
public:
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
BorrowingReference<jsi::Value> makeShared(jsi::Value&& value) {
|
|
87
|
+
BorrowingReference<jsi::Value> owning(new jsi::Value(std::move(value)));
|
|
88
88
|
_strongCache->_valueCache.push_back(owning.weak());
|
|
89
89
|
return owning;
|
|
90
90
|
}
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
BorrowingReference<jsi::Object> makeShared(jsi::Object&& value) {
|
|
92
|
+
BorrowingReference<jsi::Object> owning(new jsi::Object(std::move(value)));
|
|
93
93
|
_strongCache->_objectCache.push_back(owning.weak());
|
|
94
94
|
return owning;
|
|
95
95
|
}
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
BorrowingReference<jsi::Function> makeShared(jsi::Function&& value) {
|
|
97
|
+
BorrowingReference<jsi::Function> owning(new jsi::Function(std::move(value)));
|
|
98
98
|
_strongCache->_functionCache.push_back(owning.weak());
|
|
99
99
|
return owning;
|
|
100
100
|
}
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
BorrowingReference<jsi::WeakObject> makeShared(jsi::WeakObject&& value) {
|
|
102
|
+
BorrowingReference<jsi::WeakObject> owning(new jsi::WeakObject(std::move(value)));
|
|
103
103
|
_strongCache->_weakObjectCache.push_back(owning.weak());
|
|
104
104
|
return owning;
|
|
105
105
|
}
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
BorrowingReference<jsi::ArrayBuffer> makeShared(jsi::ArrayBuffer&& value) {
|
|
107
|
+
BorrowingReference<jsi::ArrayBuffer> owning(new jsi::ArrayBuffer(std::move(value)));
|
|
108
108
|
_strongCache->_arrayBufferCache.push_back(owning.weak());
|
|
109
109
|
return owning;
|
|
110
110
|
}
|
|
@@ -34,7 +34,7 @@ struct JSIConverter<std::function<ReturnType(Args...)>> final {
|
|
|
34
34
|
// Make function global - it'll be managed by the Runtime's memory, and we only have a weak_ref to it.
|
|
35
35
|
auto cache = JSICache::getOrCreateCache(runtime);
|
|
36
36
|
jsi::Function function = arg.asObject(runtime).asFunction(runtime);
|
|
37
|
-
|
|
37
|
+
BorrowingReference<jsi::Function> sharedFunction = cache.makeShared(std::move(function));
|
|
38
38
|
|
|
39
39
|
std::shared_ptr<Dispatcher> strongDispatcher = Dispatcher::getRuntimeGlobalDispatcher(runtime);
|
|
40
40
|
std::weak_ptr<Dispatcher> weakDispatcher = strongDispatcher;
|
|
@@ -94,7 +94,8 @@ struct JSIConverter<std::function<ReturnType(Args...)>> final {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
private:
|
|
97
|
-
static inline ResultingType callJSFunction(jsi::Runtime& runtime, const
|
|
97
|
+
static inline ResultingType callJSFunction(jsi::Runtime& runtime, const BorrowingReference<jsi::Function>& function,
|
|
98
|
+
const Args&... args) {
|
|
98
99
|
if (!function) {
|
|
99
100
|
if constexpr (std::is_void_v<ResultingType>) {
|
|
100
101
|
// runtime has already been deleted. since this returns void, we can just ignore it being deleted.
|
|
@@ -26,7 +26,7 @@ jsi::Value HybridObjectPrototype::createPrototype(jsi::Runtime& runtime, const s
|
|
|
26
26
|
auto& prototypeCache = _prototypeCache[&runtime];
|
|
27
27
|
auto cachedPrototype = prototypeCache.find(prototype->getNativeInstanceId());
|
|
28
28
|
if (cachedPrototype != prototypeCache.end()) {
|
|
29
|
-
const
|
|
29
|
+
const BorrowingReference<jsi::Object>& cachedObject = cachedPrototype->second;
|
|
30
30
|
return jsi::Value(runtime, *cachedObject).getObject(runtime);
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -68,7 +68,7 @@ jsi::Value HybridObjectPrototype::createPrototype(jsi::Runtime& runtime, const s
|
|
|
68
68
|
|
|
69
69
|
// 6. Throw it into our cache so the next lookup can be cached and therefore faster
|
|
70
70
|
JSICacheReference jsiCache = JSICache::getOrCreateCache(runtime);
|
|
71
|
-
|
|
71
|
+
BorrowingReference<jsi::Object> cachedObject = jsiCache.makeShared(std::move(object));
|
|
72
72
|
prototypeCache.emplace(prototype->getNativeInstanceId(), cachedObject);
|
|
73
73
|
|
|
74
74
|
// 7. In DEBUG, add a __type info to the prototype object.
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
#pragma once
|
|
9
9
|
|
|
10
|
+
#include "BorrowingReference.hpp"
|
|
10
11
|
#include "HybridFunction.hpp"
|
|
11
|
-
#include "OwningReference.hpp"
|
|
12
12
|
#include "Prototype.hpp"
|
|
13
13
|
#include "PrototypeChain.hpp"
|
|
14
14
|
#include <functional>
|
|
@@ -46,7 +46,7 @@ public:
|
|
|
46
46
|
|
|
47
47
|
private:
|
|
48
48
|
static jsi::Value createPrototype(jsi::Runtime& runtime, const std::shared_ptr<Prototype>& prototype);
|
|
49
|
-
using PrototypeCache = std::unordered_map<NativeInstanceId,
|
|
49
|
+
using PrototypeCache = std::unordered_map<NativeInstanceId, BorrowingReference<jsi::Object>>;
|
|
50
50
|
static std::unordered_map<jsi::Runtime*, PrototypeCache> _prototypeCache;
|
|
51
51
|
|
|
52
52
|
protected:
|
|
@@ -32,6 +32,9 @@ std::vector<std::string> HybridObjectRegistry::getAllHybridObjectNames() {
|
|
|
32
32
|
|
|
33
33
|
std::string HybridObjectRegistry::getAllRegisteredHybridObjectNamesToString() {
|
|
34
34
|
std::vector<std::string> names = getAllHybridObjectNames();
|
|
35
|
+
if (names.empty()) {
|
|
36
|
+
return "";
|
|
37
|
+
}
|
|
35
38
|
return std::accumulate(std::next(names.begin()), names.end(), names[0], [](std::string a, std::string b) { return a + ", " + b; });
|
|
36
39
|
}
|
|
37
40
|
|
|
@@ -1,119 +1,226 @@
|
|
|
1
1
|
//
|
|
2
2
|
// BorrowingReference.hpp
|
|
3
|
-
//
|
|
3
|
+
// react-native-nitro
|
|
4
4
|
//
|
|
5
|
-
// Created by Marc Rousavy on
|
|
5
|
+
// Created by Marc Rousavy on 23.06.24.
|
|
6
6
|
//
|
|
7
7
|
|
|
8
8
|
#pragma once
|
|
9
9
|
|
|
10
|
+
#include "NitroDefines.hpp"
|
|
11
|
+
#include "OwningLock.hpp"
|
|
12
|
+
#include "ReferenceState.hpp"
|
|
13
|
+
#include "WeakReference.hpp"
|
|
10
14
|
#include <atomic>
|
|
11
15
|
#include <cstddef>
|
|
12
16
|
#include <mutex>
|
|
13
17
|
|
|
14
18
|
namespace margelo::nitro {
|
|
15
19
|
|
|
16
|
-
// forward-declaration to avoid duplicate symbols
|
|
17
|
-
template <typename T>
|
|
18
|
-
class OwningReference;
|
|
19
|
-
|
|
20
20
|
/**
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
An `BorrowingReference<T>` is a smart-pointer that holds a strong reference to a pointer.
|
|
22
|
+
You can have multiple `BorrowingReference<T>` instances point to the same pointer, as they internally keep a ref-count.
|
|
23
|
+
As opposed to a `shared_ptr<T>`, an `BorrowingReference<T>` can also be imperatively manually deleted, even if there
|
|
24
|
+
are multiple strong references still holding onto the pointer.
|
|
25
|
+
This is useful in cases where the `BorrowingReference` might keep a reference alive, but an external value holder
|
|
26
|
+
is actually responsible for truly deleting the underlying value - like a `jsi::Runtime` for a `jsi::Value`.
|
|
27
|
+
|
|
28
|
+
An `BorrowingReference<T>` can be weakified, which gives the user a `WeakReference<T>`.
|
|
29
|
+
A `WeakReference<T>` can be locked to get an `BorrowingReference<T>` again, assuming it has not been deleted yet.
|
|
30
|
+
|
|
31
|
+
A `BorrowingReference<T>` can also be locked using `lock()`, which gives the user an `OwningLock<T>`.
|
|
32
|
+
Only an `OwningLock<T>` guarantees safe access to the underlying value reference, as any external value holders
|
|
33
|
+
that might try to delete the value will have to wait until the lock is freed again.
|
|
23
34
|
*/
|
|
24
35
|
template <typename T>
|
|
25
36
|
class BorrowingReference final {
|
|
26
|
-
private:
|
|
27
|
-
explicit BorrowingReference(const OwningReference<T>& ref);
|
|
28
|
-
|
|
29
37
|
public:
|
|
30
|
-
BorrowingReference() : _value(nullptr),
|
|
38
|
+
BorrowingReference() : _value(nullptr), _state(nullptr) {}
|
|
31
39
|
|
|
32
|
-
BorrowingReference(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (
|
|
40
|
+
explicit BorrowingReference(T* value) : _value(value), _state(new ReferenceState()) {}
|
|
41
|
+
|
|
42
|
+
BorrowingReference(const BorrowingReference& ref) : _value(ref._value), _state(ref._state) {
|
|
43
|
+
if (_state != nullptr) {
|
|
36
44
|
// increment ref count after copy
|
|
37
|
-
|
|
45
|
+
_state->strongRefCount++;
|
|
38
46
|
}
|
|
39
47
|
}
|
|
40
48
|
|
|
41
|
-
BorrowingReference(BorrowingReference&& ref)
|
|
42
|
-
: _value(ref._value), _isDeleted(ref._isDeleted), _strongRefCount(ref._strongRefCount), _weakRefCount(ref._weakRefCount),
|
|
43
|
-
_mutex(ref._mutex) {
|
|
49
|
+
BorrowingReference(BorrowingReference&& ref) : _value(ref._value), _state(ref._state) {
|
|
44
50
|
ref._value = nullptr;
|
|
45
|
-
ref.
|
|
46
|
-
ref._strongRefCount = nullptr;
|
|
47
|
-
ref._weakRefCount = nullptr;
|
|
51
|
+
ref._state = nullptr;
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
BorrowingReference& operator=(const BorrowingReference& ref) {
|
|
51
55
|
if (this == &ref)
|
|
52
56
|
return *this;
|
|
53
57
|
|
|
54
|
-
if (
|
|
58
|
+
if (_state != nullptr) {
|
|
55
59
|
// destroy previous pointer
|
|
56
|
-
(
|
|
57
|
-
|
|
60
|
+
bool shouldDestroy = _state->decrementStrongRefCount();
|
|
61
|
+
if (shouldDestroy) {
|
|
62
|
+
forceDestroyValue();
|
|
63
|
+
}
|
|
64
|
+
maybeDestroyState();
|
|
58
65
|
}
|
|
59
66
|
|
|
60
67
|
_value = ref._value;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
_weakRefCount = ref._weakRefCount;
|
|
64
|
-
_mutex = ref._mutex;
|
|
65
|
-
if (_weakRefCount != nullptr) {
|
|
68
|
+
_state = ref._state;
|
|
69
|
+
if (_state != nullptr) {
|
|
66
70
|
// increment new pointer
|
|
67
|
-
|
|
71
|
+
_state->strongRefCount++;
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
return *this;
|
|
71
75
|
}
|
|
72
76
|
|
|
77
|
+
private:
|
|
78
|
+
// WeakReference<T> -> BorrowingReference<T> Lock-constructor
|
|
79
|
+
BorrowingReference(const WeakReference<T>& ref) : _value(ref._value), _state(ref._state) {
|
|
80
|
+
_state->strongRefCount++;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private:
|
|
84
|
+
// BorrowingReference<C> -> BorrowingReference<T> Cast-constructor
|
|
85
|
+
template <typename OldT>
|
|
86
|
+
BorrowingReference(T* value, const BorrowingReference<OldT>& originalRef) : _value(value), _state(originalRef._state) {
|
|
87
|
+
_state->strongRefCount++;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
template <typename C>
|
|
91
|
+
friend class BorrowingReference;
|
|
92
|
+
|
|
93
|
+
public:
|
|
73
94
|
~BorrowingReference() {
|
|
74
|
-
if (
|
|
95
|
+
if (_state == nullptr) {
|
|
75
96
|
// we are just a dangling nullptr.
|
|
76
97
|
return;
|
|
77
98
|
}
|
|
78
99
|
|
|
79
|
-
|
|
80
|
-
|
|
100
|
+
// decrement strong ref count on destroy
|
|
101
|
+
bool shouldDestroy = _state->decrementStrongRefCount();
|
|
102
|
+
if (shouldDestroy) {
|
|
103
|
+
forceDestroyValue();
|
|
104
|
+
}
|
|
105
|
+
maybeDestroyState();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public:
|
|
109
|
+
/**
|
|
110
|
+
Casts this `BorrowingReference<T>` to a `BorrowingReference<C>`.
|
|
111
|
+
*/
|
|
112
|
+
template <typename C>
|
|
113
|
+
BorrowingReference<C> as() {
|
|
114
|
+
return BorrowingReference<C>(static_cast<C*>(_value), *this);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
public:
|
|
118
|
+
/**
|
|
119
|
+
Creates an `OwningLock<T>` for the given `BorrowingReference<T>` to guarantee safe
|
|
120
|
+
safe access to `BorrowingReference<T>`.
|
|
121
|
+
Other threads (e.g. the Hermes garbage collector) cannot delete the `BorrowingReference<T>`
|
|
122
|
+
as long as the `OwningLock<T>` is still alive.
|
|
123
|
+
*/
|
|
124
|
+
[[nodiscard]]
|
|
125
|
+
OwningLock<T> lock() const {
|
|
126
|
+
return OwningLock<T>(*this);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
Get whether the `BorrowingReference<T>` is still pointing to a valid value, or not.
|
|
131
|
+
*/
|
|
132
|
+
inline bool hasValue() const {
|
|
133
|
+
return _value != nullptr && !_state->isDeleted;
|
|
81
134
|
}
|
|
82
135
|
|
|
83
136
|
/**
|
|
84
|
-
|
|
137
|
+
Get a borrowing (or "weak") reference to this owning reference
|
|
85
138
|
*/
|
|
86
139
|
[[nodiscard]]
|
|
87
|
-
|
|
140
|
+
WeakReference<T> weak() const {
|
|
141
|
+
return WeakReference(*this);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
Delete and destroy the value this BorrowingReference is pointing to.
|
|
146
|
+
This can even be called if there are still multiple strong references to the value.
|
|
147
|
+
|
|
148
|
+
This will block as long as one or more `OwningLock<T>`s of this `BorrowingReference<T>` are still alive.
|
|
149
|
+
*/
|
|
150
|
+
void destroy() {
|
|
151
|
+
std::unique_lock lock(_state->mutex);
|
|
152
|
+
|
|
153
|
+
forceDestroyValue();
|
|
154
|
+
}
|
|
88
155
|
|
|
89
156
|
public:
|
|
90
|
-
|
|
157
|
+
explicit inline operator bool() const {
|
|
158
|
+
return hasValue();
|
|
159
|
+
}
|
|
91
160
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
161
|
+
inline T& operator*() const {
|
|
162
|
+
#ifdef NITRO_DEBUG
|
|
163
|
+
if (!hasValue()) [[unlikely]] {
|
|
164
|
+
throw std::runtime_error("Tried to dereference (*) nullptr BorrowingReference<T>!");
|
|
165
|
+
}
|
|
166
|
+
#endif
|
|
167
|
+
return *_value;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
inline T* operator->() const {
|
|
171
|
+
#ifdef NITRO_DEBUG
|
|
172
|
+
if (!hasValue()) [[unlikely]] {
|
|
173
|
+
throw std::runtime_error("Tried to dereference (->) nullptr BorrowingReference<T>!");
|
|
174
|
+
}
|
|
175
|
+
#endif
|
|
176
|
+
return _value;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
inline bool operator==(T* other) const {
|
|
180
|
+
return _value == other;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
inline bool operator!=(T* other) const {
|
|
184
|
+
return _value != other;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
inline bool operator==(const BorrowingReference<T>& other) const {
|
|
188
|
+
return _value == other._value;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
inline bool operator!=(const BorrowingReference<T>& other) const {
|
|
192
|
+
return _value != other._value;
|
|
193
|
+
}
|
|
95
194
|
|
|
96
|
-
|
|
195
|
+
private:
|
|
196
|
+
void maybeDestroyState() {
|
|
197
|
+
if (_state->strongRefCount == 0 && _state->weakRefCount == 0) {
|
|
97
198
|
// free the full memory if there are no more references at all
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
delete _isDeleted;
|
|
102
|
-
delete _strongRefCount;
|
|
103
|
-
delete _weakRefCount;
|
|
104
|
-
_mutex->unlock();
|
|
199
|
+
delete _state;
|
|
200
|
+
_state = nullptr;
|
|
105
201
|
return;
|
|
106
202
|
}
|
|
203
|
+
}
|
|
107
204
|
|
|
108
|
-
|
|
205
|
+
void forceDestroyValue() {
|
|
206
|
+
if (_state->isDeleted) [[unlikely]] {
|
|
207
|
+
// it has already been destroyed.
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
delete _value;
|
|
211
|
+
_value = nullptr;
|
|
212
|
+
_state->isDeleted = true;
|
|
109
213
|
}
|
|
110
214
|
|
|
215
|
+
public:
|
|
216
|
+
friend class WeakReference<T>;
|
|
217
|
+
friend class OwningLock<T>;
|
|
218
|
+
|
|
111
219
|
private:
|
|
112
220
|
T* _value;
|
|
113
|
-
|
|
114
|
-
std::atomic_size_t* _strongRefCount;
|
|
115
|
-
std::atomic_size_t* _weakRefCount;
|
|
116
|
-
std::recursive_mutex* _mutex;
|
|
221
|
+
ReferenceState* _state;
|
|
117
222
|
};
|
|
118
223
|
|
|
119
224
|
} // namespace margelo::nitro
|
|
225
|
+
|
|
226
|
+
#include "WeakReference+Owning.hpp"
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
#define NitroDefines_h
|
|
10
10
|
|
|
11
11
|
// Sets the version of the native Nitro core library
|
|
12
|
-
#define NITRO_VERSION "0.
|
|
12
|
+
#define NITRO_VERSION "0.23.0"
|
|
13
13
|
|
|
14
14
|
// Sets whether to use debug or optimized production build flags
|
|
15
15
|
#ifdef DEBUG
|
|
@@ -52,14 +52,4 @@
|
|
|
52
52
|
#define SWIFT_NONCOPYABLE
|
|
53
53
|
#endif
|
|
54
54
|
|
|
55
|
-
// React Native Support
|
|
56
|
-
#if __has_include(<cxxreact/ReactNativeVersion.h>)
|
|
57
|
-
#include <cxxreact/ReactNativeVersion.h>
|
|
58
|
-
#endif
|
|
59
|
-
#ifndef REACT_NATIVE_VERSION_MINOR
|
|
60
|
-
#define REACT_NATIVE_VERSION_MAJOR 0
|
|
61
|
-
#define REACT_NATIVE_VERSION_MINOR 0
|
|
62
|
-
#define REACT_NATIVE_VERSION_PATCH 0
|
|
63
|
-
#endif
|
|
64
|
-
|
|
65
55
|
#endif /* NitroDefines_h */
|
package/cpp/utils/OwningLock.hpp
CHANGED
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
namespace margelo::nitro {
|
|
11
11
|
template <typename T>
|
|
12
|
-
class
|
|
12
|
+
class BorrowingReference;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
#include "
|
|
15
|
+
#include "BorrowingReference.hpp"
|
|
16
16
|
#include <cstddef>
|
|
17
17
|
#include <mutex>
|
|
18
18
|
|
|
@@ -20,21 +20,26 @@ namespace margelo::nitro {
|
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* An `OwningLock<T>` is a RAII instance that locks the given caller thread guaranteed safe access
|
|
23
|
-
* to a `
|
|
24
|
-
* The `
|
|
23
|
+
* to a `BorrowingReference<T>`.
|
|
24
|
+
* The `BorrowingReference<T>` cannot be deleted while an `OwningLock<T>` of it is alive.
|
|
25
25
|
*
|
|
26
26
|
* This is useful in JSI, because Hermes runs garbage collection on a separate Thread,
|
|
27
|
-
* and the separate Thread can delete an `
|
|
27
|
+
* and the separate Thread can delete an `BorrowingReference<T>` while it's still in use.
|
|
28
28
|
* The `OwningLock<T>` prevents exactly this problem by blocking the GC destructor until
|
|
29
29
|
* the `OwningLock<T>` is released.
|
|
30
30
|
*
|
|
31
|
-
* To create an `OwningLock<T>`, simply call `lock()` on an `
|
|
31
|
+
* To create an `OwningLock<T>`, simply call `lock()` on an `BorrowingReference<T>`.
|
|
32
32
|
*/
|
|
33
33
|
template <typename T>
|
|
34
34
|
class OwningLock final {
|
|
35
|
+
private:
|
|
36
|
+
explicit OwningLock(const BorrowingReference<T>& reference) : _reference(reference) {
|
|
37
|
+
_reference._state->mutex.lock();
|
|
38
|
+
}
|
|
39
|
+
|
|
35
40
|
public:
|
|
36
41
|
~OwningLock() {
|
|
37
|
-
_reference.
|
|
42
|
+
_reference._state->mutex.unlock();
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
OwningLock() = delete;
|
|
@@ -42,15 +47,10 @@ public:
|
|
|
42
47
|
OwningLock(OwningLock&&) = delete;
|
|
43
48
|
|
|
44
49
|
private:
|
|
45
|
-
|
|
46
|
-
_reference._mutex->lock();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
private:
|
|
50
|
-
OwningReference<T> _reference;
|
|
50
|
+
BorrowingReference<T> _reference;
|
|
51
51
|
|
|
52
52
|
private:
|
|
53
|
-
friend class
|
|
53
|
+
friend class BorrowingReference<T>;
|
|
54
54
|
};
|
|
55
55
|
|
|
56
56
|
} // namespace margelo::nitro
|