react-native-nitro-modules 0.0.2 → 0.0.4
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/NitroModules.podspec +49 -0
- package/android/CMakeLists.txt +44 -7
- package/android/build.gradle +28 -24
- package/cpp/core/AnyMap.cpp +181 -0
- package/cpp/core/AnyMap.hpp +191 -0
- package/cpp/core/HybridContext.hpp +51 -0
- package/cpp/core/HybridObject.cpp +220 -0
- package/cpp/core/HybridObject.hpp +241 -0
- package/cpp/core/PointerHolder.hpp +93 -0
- package/cpp/jsi/ArrayBuffer.hpp +79 -0
- package/cpp/jsi/JSICache.hpp +145 -0
- package/cpp/jsi/JSIConverter.hpp +610 -0
- package/cpp/jsi/Promise.cpp +54 -0
- package/cpp/jsi/Promise.hpp +54 -0
- package/cpp/platform/ThreadUtils.hpp +23 -0
- package/cpp/registry/HybridObjectRegistry.cpp +57 -0
- package/cpp/registry/HybridObjectRegistry.hpp +44 -0
- package/cpp/test-object/TestHybridObject.cpp +37 -0
- package/cpp/test-object/TestHybridObject.hpp +87 -0
- package/cpp/threading/CallInvokerDispatcher.hpp +33 -0
- package/cpp/threading/Dispatcher.cpp +56 -0
- package/cpp/threading/Dispatcher.hpp +82 -0
- package/cpp/turbomodule/NativeNitroModules.cpp +70 -0
- package/cpp/turbomodule/NativeNitroModules.h +7 -0
- package/cpp/turbomodule/NativeNitroModules.hpp +35 -0
- package/cpp/turbomodule/RegisterNativeNitroModules.cpp +33 -0
- package/cpp/turbomodule/RegisterNativeNitroModules.hpp +21 -0
- package/cpp/utils/BorrowingReference+Owning.hpp +34 -0
- package/cpp/utils/BorrowingReference.hpp +115 -0
- package/cpp/utils/DoesClassExist.hpp +23 -0
- package/cpp/utils/GetRuntimeID.hpp +28 -0
- package/cpp/utils/NitroDefines.hpp +32 -0
- package/cpp/utils/NitroHash.hpp +42 -0
- package/cpp/utils/NitroLogger.hpp +55 -0
- package/cpp/utils/OwningLock.hpp +54 -0
- package/cpp/utils/OwningReference.hpp +214 -0
- package/cpp/utils/TypeInfo.hpp +81 -0
- package/ios/core/HybridObjectSpec.swift +52 -0
- package/ios/core/RuntimeError.swift +17 -0
- package/ios/platform/ThreadUtils.cpp +28 -0
- package/ios/turbomodule/NitroModuleOnLoad.mm +31 -0
- package/lib/AnyMap.d.ts +16 -0
- package/lib/AnyMap.js +1 -0
- package/lib/HybridObject.d.ts +57 -0
- package/lib/HybridObject.js +1 -0
- package/lib/ModuleNotFoundError.d.ts +6 -0
- package/lib/ModuleNotFoundError.js +61 -0
- package/lib/NativeNitro.d.ts +8 -0
- package/lib/NativeNitro.js +3 -0
- package/lib/NativeNitroModules.d.ts +7 -0
- package/lib/NativeNitroModules.js +17 -0
- package/lib/NitroModules.d.ts +17 -0
- package/lib/NitroModules.js +21 -0
- package/lib/__tests__/index.test.d.ts +0 -0
- package/lib/__tests__/index.test.js +2 -0
- package/lib/commonjs/AnyMap.js +2 -0
- package/lib/commonjs/AnyMap.js.map +1 -0
- package/lib/commonjs/HybridObject.js +2 -0
- package/lib/commonjs/HybridObject.js.map +1 -0
- package/lib/commonjs/ModuleNotFoundError.js +72 -0
- package/lib/commonjs/ModuleNotFoundError.js.map +1 -0
- package/lib/commonjs/NativeNitroModules.js +24 -0
- package/lib/commonjs/NativeNitroModules.js.map +1 -0
- package/lib/commonjs/NitroModules.js +32 -0
- package/lib/commonjs/NitroModules.js.map +1 -0
- package/lib/commonjs/createTestObject.js +15 -0
- package/lib/commonjs/createTestObject.js.map +1 -0
- package/lib/commonjs/index.js +44 -5
- package/lib/commonjs/index.js.map +1 -1
- package/lib/createTestObject.d.ts +22 -0
- package/lib/createTestObject.js +7 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +4 -0
- package/lib/module/AnyMap.js +2 -0
- package/lib/module/AnyMap.js.map +1 -0
- package/lib/module/HybridObject.js +2 -0
- package/lib/module/HybridObject.js.map +1 -0
- package/lib/module/ModuleNotFoundError.js +65 -0
- package/lib/module/ModuleNotFoundError.js.map +1 -0
- package/lib/module/NativeNitroModules.js +18 -0
- package/lib/module/NativeNitroModules.js.map +1 -0
- package/lib/module/NitroModules.js +27 -0
- package/lib/module/NitroModules.js.map +1 -0
- package/lib/module/createTestObject.js +8 -0
- package/lib/module/createTestObject.js.map +1 -0
- package/lib/module/index.js +4 -4
- package/lib/module/index.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +76 -49
- package/react-native.config.js +16 -0
- package/src/AnyMap.ts +22 -0
- package/src/HybridObject.ts +58 -0
- package/src/ModuleNotFoundError.ts +90 -0
- package/src/NativeNitroModules.ts +26 -0
- package/src/NitroModules.ts +30 -0
- package/src/__tests__/index.test.tsx +1 -0
- package/src/createTestObject.ts +40 -0
- package/src/index.ts +4 -0
- package/LICENSE +0 -20
- package/README.md +0 -32
- package/android/cpp-adapter.cpp +0 -8
- package/android/src/main/AndroidManifest.xml +0 -3
- package/android/src/main/AndroidManifestNew.xml +0 -2
- package/android/src/main/java/com/nitro/NitroModule.java +0 -34
- package/android/src/main/java/com/nitro/NitroPackage.java +0 -44
- package/cpp/react-native-nitro.cpp +0 -7
- package/cpp/react-native-nitro.h +0 -8
- package/ios/Nitro.h +0 -15
- package/ios/Nitro.mm +0 -21
- package/lib/commonjs/NativeNitro.js +0 -9
- package/lib/commonjs/NativeNitro.js.map +0 -1
- package/lib/module/NativeNitro.js +0 -3
- package/lib/module/NativeNitro.js.map +0 -1
- package/lib/typescript/src/NativeNitro.d.ts +0 -7
- package/lib/typescript/src/NativeNitro.d.ts.map +0 -1
- package/lib/typescript/src/index.d.ts +0 -2
- package/lib/typescript/src/index.d.ts.map +0 -1
- package/react-native-nitro.podspec +0 -41
- package/src/NativeNitro.ts +0 -8
- package/src/index.tsx +0 -5
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
//
|
|
2
|
+
// BorrowingReference.hpp
|
|
3
|
+
// NitroModules
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 21.06.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <cstddef>
|
|
11
|
+
#include <mutex>
|
|
12
|
+
#include <atomic>
|
|
13
|
+
|
|
14
|
+
namespace margelo::nitro {
|
|
15
|
+
|
|
16
|
+
// forward-declaration to avoid duplicate symbols
|
|
17
|
+
template <typename T> class OwningReference;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
A `BorrowingReference<T>` is a weak reference to a pointer created by `OwningReference<T>`.
|
|
21
|
+
It can be locked to gain a strong `OwningReference<T>` again if it has not been deleted yet.
|
|
22
|
+
*/
|
|
23
|
+
template <typename T> class BorrowingReference final {
|
|
24
|
+
private:
|
|
25
|
+
explicit BorrowingReference(const OwningReference<T>& ref);
|
|
26
|
+
|
|
27
|
+
public:
|
|
28
|
+
BorrowingReference() : _value(nullptr), _isDeleted(nullptr), _strongRefCount(nullptr), _weakRefCount(nullptr), _mutex(nullptr) {}
|
|
29
|
+
|
|
30
|
+
BorrowingReference(const BorrowingReference& ref)
|
|
31
|
+
: _value(ref._value), _isDeleted(ref._isDeleted), _strongRefCount(ref._strongRefCount), _weakRefCount(ref._weakRefCount),
|
|
32
|
+
_mutex(ref._mutex) {
|
|
33
|
+
// increment ref count after copy
|
|
34
|
+
(*_weakRefCount)++;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
BorrowingReference(BorrowingReference&& ref)
|
|
38
|
+
: _value(ref._value), _isDeleted(ref._isDeleted), _strongRefCount(ref._strongRefCount), _weakRefCount(ref._weakRefCount),
|
|
39
|
+
_mutex(ref._mutex) {
|
|
40
|
+
ref._value = nullptr;
|
|
41
|
+
ref._isDeleted = nullptr;
|
|
42
|
+
ref._strongRefCount = nullptr;
|
|
43
|
+
ref._weakRefCount = nullptr;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
BorrowingReference& operator=(const BorrowingReference& ref) {
|
|
47
|
+
if (this == &ref)
|
|
48
|
+
return *this;
|
|
49
|
+
|
|
50
|
+
if (_weakRefCount != nullptr) {
|
|
51
|
+
// destroy previous pointer
|
|
52
|
+
(*_weakRefCount)--;
|
|
53
|
+
maybeDestroy();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
_value = ref._value;
|
|
57
|
+
_isDeleted = ref._isDeleted;
|
|
58
|
+
_strongRefCount = ref._strongRefCount;
|
|
59
|
+
_weakRefCount = ref._weakRefCount;
|
|
60
|
+
_mutex = ref._mutex;
|
|
61
|
+
if (_weakRefCount != nullptr) {
|
|
62
|
+
// increment new pointer
|
|
63
|
+
(*_weakRefCount)++;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return *this;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
~BorrowingReference() {
|
|
70
|
+
if (_weakRefCount == nullptr) {
|
|
71
|
+
// we are just a dangling nullptr.
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
(*_weakRefCount)--;
|
|
76
|
+
maybeDestroy();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
Try to lock the borrowing reference to an owning reference, or `nullptr` if it has already been deleted.
|
|
81
|
+
*/
|
|
82
|
+
[[nodiscard]]
|
|
83
|
+
OwningReference<T> lock();
|
|
84
|
+
|
|
85
|
+
public:
|
|
86
|
+
friend class OwningReference<T>;
|
|
87
|
+
|
|
88
|
+
private:
|
|
89
|
+
void maybeDestroy() {
|
|
90
|
+
_mutex->lock();
|
|
91
|
+
|
|
92
|
+
if (*_strongRefCount == 0 && *_weakRefCount == 0) {
|
|
93
|
+
// free the full memory if there are no more references at all
|
|
94
|
+
if (!(*_isDeleted)) {
|
|
95
|
+
delete _value;
|
|
96
|
+
}
|
|
97
|
+
delete _isDeleted;
|
|
98
|
+
delete _strongRefCount;
|
|
99
|
+
delete _weakRefCount;
|
|
100
|
+
_mutex->unlock();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
_mutex->unlock();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private:
|
|
108
|
+
T* _value;
|
|
109
|
+
bool* _isDeleted;
|
|
110
|
+
std::atomic_size_t* _strongRefCount;
|
|
111
|
+
std::atomic_size_t* _weakRefCount;
|
|
112
|
+
std::mutex* _mutex;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
} // namespace margelo::nitro
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//
|
|
2
|
+
// DoesClassExist.hpp
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 17.07.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <type_traits>
|
|
11
|
+
|
|
12
|
+
namespace margelo::nitro {
|
|
13
|
+
|
|
14
|
+
// By default, it is false (class does not exist)
|
|
15
|
+
template <typename T, typename = std::void_t<>> struct does_class_exist : std::false_type {};
|
|
16
|
+
|
|
17
|
+
// If sizeof(T) can be a type (number), the type exists - so it is true
|
|
18
|
+
template <typename T> struct does_class_exist<T, std::void_t<decltype(sizeof(T))>> : std::true_type {};
|
|
19
|
+
|
|
20
|
+
// Direct value accessor for does_class_exist
|
|
21
|
+
template <typename T> inline constexpr bool does_class_exist_v = does_class_exist<T>::value;
|
|
22
|
+
|
|
23
|
+
} // namespace margelo::nitro
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//
|
|
2
|
+
// GetRuntimeID.hpp
|
|
3
|
+
// NitroModules
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 20.06.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include "ThreadUtils.hpp"
|
|
11
|
+
#include <jsi/jsi.h>
|
|
12
|
+
|
|
13
|
+
namespace margelo::nitro {
|
|
14
|
+
|
|
15
|
+
using namespace facebook;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get an ID for the given Runtime.
|
|
19
|
+
*
|
|
20
|
+
* The ID usually consists of a Runtime description (e.g. "HermesRuntime"),
|
|
21
|
+
* and it's Thread (e.g. "com.facebook.react.runtime.JavaScript")
|
|
22
|
+
*/
|
|
23
|
+
static inline std::string getRuntimeId(jsi::Runtime& runtime) {
|
|
24
|
+
std::string threadName = ThreadUtils::getThreadName();
|
|
25
|
+
return runtime.description() + std::string(" (") + threadName + std::string(")");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
} // namespace margelo::nitro
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//
|
|
2
|
+
// NitroDefines.hpp
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 29.07.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#ifndef NitroDefines_h
|
|
9
|
+
#define NitroDefines_h
|
|
10
|
+
|
|
11
|
+
// Helper to find out if a C++ compiler attribute is available
|
|
12
|
+
#ifdef __has_attribute
|
|
13
|
+
#define _CXX_INTEROP_HAS_ATTRIBUTE(x) __has_attribute(x)
|
|
14
|
+
#else
|
|
15
|
+
#define _CXX_INTEROP_HAS_ATTRIBUTE(x) 0
|
|
16
|
+
#endif
|
|
17
|
+
|
|
18
|
+
#if _CXX_INTEROP_HAS_ATTRIBUTE(swift_attr)
|
|
19
|
+
// Rename Type for Swift
|
|
20
|
+
#define SWIFT_NAME(_name) __attribute__((swift_name(#_name)))
|
|
21
|
+
#else
|
|
22
|
+
#define SWIFT_NAME(_name)
|
|
23
|
+
#endif
|
|
24
|
+
|
|
25
|
+
#if _CXX_INTEROP_HAS_ATTRIBUTE(enum_extensibility)
|
|
26
|
+
// Enum is marked as closed/not extensible
|
|
27
|
+
#define CLOSED_ENUM __attribute__((enum_extensibility(closed)))
|
|
28
|
+
#else
|
|
29
|
+
#define CLOSED_ENUM
|
|
30
|
+
#endif
|
|
31
|
+
|
|
32
|
+
#endif /* NitroDefines_h */
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//
|
|
2
|
+
// NitroHash.hpp
|
|
3
|
+
// react-native-nitro
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 14.07.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <cstddef>
|
|
11
|
+
#include <cstdint>
|
|
12
|
+
|
|
13
|
+
namespace margelo::nitro {
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Hashes the given C-String using the FNV-1a hashing algorithm.
|
|
17
|
+
*
|
|
18
|
+
* This function can be used at compile time as a constexpr to build
|
|
19
|
+
* statically optimized switch statements.
|
|
20
|
+
*/
|
|
21
|
+
constexpr uint64_t hashString(const char* str, size_t length) {
|
|
22
|
+
uint64_t hash = 14695981039346656037ull; // FNV offset basis
|
|
23
|
+
const uint64_t fnv_prime = 1099511628211ull;
|
|
24
|
+
|
|
25
|
+
for (size_t i = 0; i < length; ++i) {
|
|
26
|
+
hash ^= static_cast<uint64_t>(str[i]);
|
|
27
|
+
hash *= fnv_prime;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return hash;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Hashes the given constant C-String using the FNV-1a hashing algorithm.
|
|
35
|
+
*
|
|
36
|
+
* String length is known at compile time.
|
|
37
|
+
*/
|
|
38
|
+
template <size_t N> constexpr uint64_t hashString(const char (&str)[N]) {
|
|
39
|
+
return hashString(str, N - 1); // N includes the null terminator, so subtract 1
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
} // namespace margelo::nitro
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Created by Marc Rousavy on 05.03.24.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
#pragma once
|
|
6
|
+
|
|
7
|
+
#include <cstdarg>
|
|
8
|
+
#include <cstdio>
|
|
9
|
+
#include <iostream>
|
|
10
|
+
#include <string>
|
|
11
|
+
#include <vector>
|
|
12
|
+
|
|
13
|
+
namespace margelo::nitro {
|
|
14
|
+
|
|
15
|
+
class Logger final {
|
|
16
|
+
private:
|
|
17
|
+
Logger() = delete;
|
|
18
|
+
|
|
19
|
+
public:
|
|
20
|
+
template <typename... Args> static void log(const char* tag, const char* message, Args&&... args) {
|
|
21
|
+
std::string formattedMessage = format(message, std::forward<Args>(args)...);
|
|
22
|
+
std::cout << "[Nitro." << tag << "] " << formattedMessage << std::endl;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private:
|
|
26
|
+
template <typename... Args> static inline std::string format(const char* formatString, Args&&... args) {
|
|
27
|
+
#pragma clang diagnostic push
|
|
28
|
+
#pragma clang diagnostic ignored "-Wformat-security"
|
|
29
|
+
int size_s = std::snprintf(nullptr, 0, formatString, toCString(args)...) + 1; // Extra space for '\0'
|
|
30
|
+
if (size_s <= 0) [[unlikely]] {
|
|
31
|
+
throw std::runtime_error("Failed to format log message \"" + std::string(formatString) + "\"!");
|
|
32
|
+
}
|
|
33
|
+
auto size = static_cast<size_t>(size_s);
|
|
34
|
+
std::vector<char> buf(size);
|
|
35
|
+
std::snprintf(buf.data(), size, formatString, toCString(args)...);
|
|
36
|
+
return std::string(buf.data(), buf.data() + size - 1); // We don't want the '\0' inside
|
|
37
|
+
#pragma clang diagnostic pop
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private:
|
|
41
|
+
// When the user passes an `std::string`, it will automatically be converted to a `const char*`
|
|
42
|
+
static inline const char* toCString(const std::string& s) {
|
|
43
|
+
return s.c_str();
|
|
44
|
+
}
|
|
45
|
+
// When the user passes a `const char*`, we don't want to implicitly convert to `std::string`, so block that
|
|
46
|
+
static inline const char* toCString(const char* s) {
|
|
47
|
+
return s;
|
|
48
|
+
}
|
|
49
|
+
// When the user passes any other type, just return that directly.
|
|
50
|
+
template <typename T> static inline T toCString(T value) {
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
} // namespace margelo::nitro
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
//
|
|
2
|
+
// OwningLock.hpp
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 30.07.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
namespace margelo::nitro {
|
|
11
|
+
template <typename T> class OwningReference;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
#include "OwningReference.hpp"
|
|
15
|
+
#include <cstddef>
|
|
16
|
+
#include <mutex>
|
|
17
|
+
|
|
18
|
+
namespace margelo::nitro {
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* An `OwningLock<T>` is a RAII instance that locks the given caller thread guaranteed safe access
|
|
22
|
+
* to a `OwningReference<T>`.
|
|
23
|
+
* The `OwningReference<T>` cannot be deleted while an `OwningLock<T>` of it is alive.
|
|
24
|
+
*
|
|
25
|
+
* This is useful in JSI, because Hermes runs garbage collection on a separate Thread,
|
|
26
|
+
* and the separate Thread can delete an `OwningReference<T>` while it's still in use.
|
|
27
|
+
* The `OwningLock<T>` prevents exactly this problem by blocking the GC destructor until
|
|
28
|
+
* the `OwningLock<T>` is released.
|
|
29
|
+
*
|
|
30
|
+
* To create an `OwningLock<T>`, simply call `lock()` on an `OwningReference<T>`.
|
|
31
|
+
*/
|
|
32
|
+
template <typename T> class OwningLock final {
|
|
33
|
+
public:
|
|
34
|
+
~OwningLock() {
|
|
35
|
+
_reference._mutex->unlock();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
OwningLock() = delete;
|
|
39
|
+
OwningLock(const OwningLock&) = delete;
|
|
40
|
+
OwningLock(OwningLock&&) = delete;
|
|
41
|
+
|
|
42
|
+
private:
|
|
43
|
+
explicit OwningLock(const OwningReference<T>& reference) : _reference(reference) {
|
|
44
|
+
_reference._mutex->lock();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private:
|
|
48
|
+
OwningReference<T> _reference;
|
|
49
|
+
|
|
50
|
+
private:
|
|
51
|
+
friend class OwningReference<T>;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
} // namespace margelo::nitro
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
//
|
|
2
|
+
// OwningReference.hpp
|
|
3
|
+
// react-native-nitro
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 23.06.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include "BorrowingReference.hpp"
|
|
11
|
+
#include "OwningLock.hpp"
|
|
12
|
+
#include <cstddef>
|
|
13
|
+
#include <mutex>
|
|
14
|
+
#include <atomic>
|
|
15
|
+
|
|
16
|
+
namespace margelo::nitro {
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
An `OwningReference<T>` is a smart-pointer that holds a strong reference to a pointer.
|
|
20
|
+
You can have multiple `OwningReference<T>` instances point to the same pointer, as they internally keep a ref-count.
|
|
21
|
+
As opposed to a `shared_ptr<T>`, an `OwningReference<T>` can also be imperatively manually deleted, even if there
|
|
22
|
+
are multiple strong references still holding onto the pointer.
|
|
23
|
+
|
|
24
|
+
An `OwningReference<T>` can be weakified, which gives the user a `BorrowingReference<T>`.
|
|
25
|
+
A `BorrowingReference<T>` can be locked to get an `OwningReference<T>` again, assuming it has not been deleted yet.
|
|
26
|
+
*/
|
|
27
|
+
template <typename T> class OwningReference final {
|
|
28
|
+
public:
|
|
29
|
+
using Pointee = T;
|
|
30
|
+
|
|
31
|
+
public:
|
|
32
|
+
OwningReference() : _value(nullptr), _isDeleted(nullptr), _strongRefCount(nullptr), _weakRefCount(nullptr), _mutex(nullptr) {}
|
|
33
|
+
|
|
34
|
+
explicit OwningReference(T* value)
|
|
35
|
+
: _value(value), _isDeleted(new bool(false)), _strongRefCount(new std::atomic_size_t(1)), _weakRefCount(new std::atomic_size_t(0)), _mutex(new std::mutex()) {
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
OwningReference(const OwningReference& ref)
|
|
39
|
+
: _value(ref._value), _isDeleted(ref._isDeleted), _strongRefCount(ref._strongRefCount), _weakRefCount(ref._weakRefCount),
|
|
40
|
+
_mutex(ref._mutex) {
|
|
41
|
+
// increment ref count after copy
|
|
42
|
+
(*_strongRefCount)++;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
OwningReference(OwningReference&& ref)
|
|
46
|
+
: _value(ref._value), _isDeleted(ref._isDeleted), _strongRefCount(ref._strongRefCount), _weakRefCount(ref._weakRefCount),
|
|
47
|
+
_mutex(ref._mutex) {
|
|
48
|
+
ref._value = nullptr;
|
|
49
|
+
ref._isDeleted = nullptr;
|
|
50
|
+
ref._strongRefCount = nullptr;
|
|
51
|
+
ref._weakRefCount = nullptr;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
OwningReference& operator=(const OwningReference& ref) {
|
|
55
|
+
if (this == &ref)
|
|
56
|
+
return *this;
|
|
57
|
+
|
|
58
|
+
if (_strongRefCount != nullptr) {
|
|
59
|
+
// destroy previous pointer
|
|
60
|
+
(*_strongRefCount)--;
|
|
61
|
+
maybeDestroy();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
_value = ref._value;
|
|
65
|
+
_isDeleted = ref._isDeleted;
|
|
66
|
+
_strongRefCount = ref._strongRefCount;
|
|
67
|
+
_weakRefCount = ref._weakRefCount;
|
|
68
|
+
_mutex = ref._mutex;
|
|
69
|
+
if (_strongRefCount != nullptr) {
|
|
70
|
+
// increment new pointer
|
|
71
|
+
(*_strongRefCount)++;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return *this;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private:
|
|
78
|
+
OwningReference(const BorrowingReference<T>& ref)
|
|
79
|
+
: _value(ref._value), _isDeleted(ref._isDeleted), _strongRefCount(ref._strongRefCount), _weakRefCount(ref._weakRefCount),
|
|
80
|
+
_mutex(ref._mutex) {
|
|
81
|
+
(*_strongRefCount)++;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public:
|
|
85
|
+
~OwningReference() {
|
|
86
|
+
if (_strongRefCount == nullptr) {
|
|
87
|
+
// we are just a dangling nullptr.
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// decrement strong ref count on destroy
|
|
92
|
+
--(*_strongRefCount);
|
|
93
|
+
maybeDestroy();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public:
|
|
97
|
+
/**
|
|
98
|
+
Creates an `OwningLock<T>` for the given `OwningReference<T>` to guarantee safe
|
|
99
|
+
safe access to `OwningReference<T>`.
|
|
100
|
+
Other threads (e.g. the Hermes garbage collector) cannot delete the `OwningReference<T>`
|
|
101
|
+
as long as the `OwningLock<T>` is still alive.
|
|
102
|
+
*/
|
|
103
|
+
[[nodiscard]]
|
|
104
|
+
OwningLock<T> lock() const {
|
|
105
|
+
return OwningLock<T>(*this);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
Get whether the `OwningReference<T>` is still pointing to a valid value, or not.
|
|
110
|
+
*/
|
|
111
|
+
inline bool hasValue() const {
|
|
112
|
+
return _value != nullptr && !(*_isDeleted);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
Get a borrowing (or "weak") reference to this owning reference
|
|
117
|
+
*/
|
|
118
|
+
[[nodiscard]]
|
|
119
|
+
BorrowingReference<T> weak() const {
|
|
120
|
+
return BorrowingReference(*this);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
Delete and destroy the value this OwningReference is pointing to.
|
|
125
|
+
This can even be called if there are still multiple strong references to the value.
|
|
126
|
+
|
|
127
|
+
This will block as long as one or more `OwningLock<T>`s of this `OwningReference<T>` are still alive.
|
|
128
|
+
*/
|
|
129
|
+
void destroy() {
|
|
130
|
+
std::unique_lock lock(*_mutex);
|
|
131
|
+
|
|
132
|
+
forceDestroy();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public:
|
|
136
|
+
explicit inline operator bool() const {
|
|
137
|
+
return hasValue();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
inline T& operator*() const {
|
|
141
|
+
return *_value;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
inline T* operator->() const {
|
|
145
|
+
return _value;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
inline bool operator==(T* other) const {
|
|
149
|
+
std::unique_lock lock(*_mutex);
|
|
150
|
+
|
|
151
|
+
if (*_isDeleted) {
|
|
152
|
+
return other == nullptr;
|
|
153
|
+
} else {
|
|
154
|
+
return other == _value;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
inline bool operator!=(T* other) const {
|
|
159
|
+
return !(this == other);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
inline bool operator==(const OwningReference<T>& other) const {
|
|
163
|
+
return _value == other._value;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
inline bool operator!=(const OwningReference<T>& other) const {
|
|
167
|
+
return !(this == other);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
private:
|
|
171
|
+
void maybeDestroy() {
|
|
172
|
+
_mutex->lock();
|
|
173
|
+
|
|
174
|
+
if (*_strongRefCount == 0) {
|
|
175
|
+
// after no strong references exist anymore
|
|
176
|
+
forceDestroy();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (*_strongRefCount == 0 && *_weakRefCount == 0) {
|
|
180
|
+
// free the full memory if there are no more references at all
|
|
181
|
+
delete _isDeleted;
|
|
182
|
+
delete _strongRefCount;
|
|
183
|
+
delete _weakRefCount;
|
|
184
|
+
_mutex->unlock();
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
_mutex->unlock();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
void forceDestroy() {
|
|
192
|
+
if (*_isDeleted) {
|
|
193
|
+
// it has already been destroyed.
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
delete _value;
|
|
197
|
+
*_isDeleted = true;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
public:
|
|
201
|
+
friend class BorrowingReference<T>;
|
|
202
|
+
friend class OwningLock<T>;
|
|
203
|
+
|
|
204
|
+
private:
|
|
205
|
+
T* _value;
|
|
206
|
+
bool* _isDeleted;
|
|
207
|
+
std::atomic_size_t* _strongRefCount;
|
|
208
|
+
std::atomic_size_t* _weakRefCount;
|
|
209
|
+
std::mutex* _mutex;
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
} // namespace margelo::nitro
|
|
213
|
+
|
|
214
|
+
#include "BorrowingReference+Owning.hpp"
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
//
|
|
2
|
+
// TypeInfo.hpp
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 17.07.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <regex>
|
|
11
|
+
#include <sstream>
|
|
12
|
+
#include <string>
|
|
13
|
+
#include <type_traits>
|
|
14
|
+
|
|
15
|
+
#if __has_include(<cxxabi.h>)
|
|
16
|
+
#include <cxxabi.h>
|
|
17
|
+
#endif
|
|
18
|
+
|
|
19
|
+
namespace margelo::nitro {
|
|
20
|
+
|
|
21
|
+
struct TypeInfo final {
|
|
22
|
+
public:
|
|
23
|
+
TypeInfo() = delete;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get the name of the currently thrown exception
|
|
27
|
+
*/
|
|
28
|
+
static inline const char* getCurrentExceptionName() {
|
|
29
|
+
#if __has_include(<cxxabi.h>)
|
|
30
|
+
return __cxxabiv1::__cxa_current_exception_type()->name();
|
|
31
|
+
#else
|
|
32
|
+
return "<unknown>";
|
|
33
|
+
#endif
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static inline std::string replaceRegex(const std::string& original, const std::string& pattern, const std::string& replacement) {
|
|
37
|
+
std::regex re(pattern);
|
|
38
|
+
return std::regex_replace(original, re, replacement);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get a friendly name of the type `T` (if possible, demangled)
|
|
43
|
+
*/
|
|
44
|
+
template <typename T> static inline std::string getFriendlyTypename() {
|
|
45
|
+
std::string name = typeid(T).name();
|
|
46
|
+
#if __has_include(<cxxabi.h>)
|
|
47
|
+
int status = 0;
|
|
48
|
+
char* demangled_name = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);
|
|
49
|
+
if (demangled_name != nullptr) {
|
|
50
|
+
name = demangled_name;
|
|
51
|
+
std::free(demangled_name);
|
|
52
|
+
}
|
|
53
|
+
#endif
|
|
54
|
+
|
|
55
|
+
// Make a few edge-cases nicer.
|
|
56
|
+
name = replaceRegex(name, R"(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>)", "std::string");
|
|
57
|
+
name = replaceRegex(name, R"(std::__1::vector<([^>]+), std::__1::allocator<\1>>)", "std::vector<$1>");
|
|
58
|
+
name = replaceRegex(name, R"(std::__1::map<([^,]+), ([^>]+), std::__1::less<\1>, std::__1::allocator<std::__1::pair<const \1, \2>>>)",
|
|
59
|
+
"std::map<$1, $2>");
|
|
60
|
+
name = replaceRegex(name, R"(std::__1::shared_ptr<([^>]+)>)", "std::shared_ptr<$1>");
|
|
61
|
+
name = replaceRegex(name, R"(std::__1::unique_ptr<([^>]+), std::__1::default_delete<\1>>)", "std::unique_ptr<$1>");
|
|
62
|
+
name = replaceRegex(
|
|
63
|
+
name,
|
|
64
|
+
R"(std::__1::unordered_map<([^,]+), ([^>]+), std::__1::hash<\1>, std::__1::equal_to<\1>, std::__1::allocator<std::__1::pair<const \1, \2>>>)",
|
|
65
|
+
"std::unordered_map<$1, $2>");
|
|
66
|
+
name = replaceRegex(name, R"(std::__1::unordered_set<([^>]+), std::__1::hash<\1>, std::__1::equal_to<\1>, std::__1::allocator<\1>>)",
|
|
67
|
+
"std::unordered_set<$1>");
|
|
68
|
+
name = replaceRegex(name, R"(std::__1::list<([^>]+), std::__1::allocator<\1>>)", "std::list<$1>");
|
|
69
|
+
|
|
70
|
+
return name;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
template <typename... Types> static inline std::string getFriendlyTypenames() {
|
|
74
|
+
std::ostringstream stream;
|
|
75
|
+
((stream << TypeInfo::getFriendlyTypename<Types>() << ", "), ...);
|
|
76
|
+
std::string string = stream.str();
|
|
77
|
+
return string.substr(0, string.length() - 2);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
} // namespace margelo::nitro
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//
|
|
2
|
+
// HybridObjectSpec.swift
|
|
3
|
+
// NitroModules
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 23.07.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A base protocol for all Swift-based Hybrid Objects.
|
|
12
|
+
*/
|
|
13
|
+
public protocol HybridObjectSpec {
|
|
14
|
+
/**
|
|
15
|
+
* Holds the C++ HybridObject and it's context.
|
|
16
|
+
* Use the default initializer in your implementation, C++ will set and get this value.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```swift
|
|
20
|
+
* var hybridContext = margelo.nitro.HybridContext()
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
var hybridContext: margelo.nitro.HybridContext { get set }
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get the memory size of the Swift instance (plus any external heap allocations),
|
|
27
|
+
* in bytes.
|
|
28
|
+
*
|
|
29
|
+
* Override this to allow tracking heap allocations such as buffers or images,
|
|
30
|
+
* which will help the JS GC be more efficient in deleting large unused objects.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```swift
|
|
34
|
+
* var memorySize: Int {
|
|
35
|
+
* let imageSize = self.uiImage.bytesPerRow * self.uiImage.height
|
|
36
|
+
* return getSizeOf(self) + imageSize
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
var memorySize: Int { get }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public extension HybridObjectSpec {
|
|
44
|
+
/**
|
|
45
|
+
* Get the memory size of the given instance.
|
|
46
|
+
* This only accounts for stack allocated member variables,
|
|
47
|
+
* not for externally allocated heap allocations like images or buffers.
|
|
48
|
+
*/
|
|
49
|
+
func getSizeOf<T: AnyObject>(_ instance: T) -> Int {
|
|
50
|
+
return malloc_size(Unmanaged.passUnretained(instance).toOpaque())
|
|
51
|
+
}
|
|
52
|
+
}
|