Skip to content

Commit

Permalink
Create test object
Browse files Browse the repository at this point in the history
  • Loading branch information
mrousavy committed Jun 20, 2024
1 parent 2bc02c0 commit 166feb4
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 34 deletions.
2 changes: 2 additions & 0 deletions packages/react-native-nitro-modules/NitroModules.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Pod::Spec.new do |s|
]

s.pod_target_xcconfig = {
# Use C++ 17
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17",
# Enables C++ <-> Swift interop (by default it's only C)
"SWIFT_OBJC_INTEROP_MODE" => "objcxx",
}
Expand Down
19 changes: 7 additions & 12 deletions packages/react-native-nitro-modules/cpp/core/HybridObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,19 @@ jsi::Value HybridObject::get(facebook::jsi::Runtime& runtime, const facebook::js

std::string name = propName.utf8(runtime);
auto& functionCache = _functionCache[&runtime];

if (_getters.count(name) > 0) {
// it's a property getter
return _getters[name](runtime, jsi::Value::undefined(), nullptr, 0);
}



if (functionCache.count(name) > 0) {
[[likely]];
// cache hit
return jsi::Value(runtime, *functionCache[name]);
}

if (_getters.count(name) > 0) {
// it's a property getter
return _getters[name](runtime, jsi::Value::undefined(), nullptr, 0);
}

if (_methods.count(name) > 0) {
// cache miss - create jsi::Function and cache it.
HybridFunction& hybridFunction = _methods.at(name);
Expand Down Expand Up @@ -124,16 +125,10 @@ void HybridObject::set(facebook::jsi::Runtime& runtime, const facebook::jsi::Pro
void HybridObject::ensureInitialized(facebook::jsi::Runtime& runtime) {
if (!_didLoadMethods) {
[[unlikely]];
_creationRuntime = &runtime;
// lazy-load all exposed methods
loadHybridMethods();
_didLoadMethods = true;
}
}

bool HybridObject::isRuntimeAlive() {
// TODO: Fix this. We shouldn't do this. This is a bad idea.
return true;
}

} // namespace margelo
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,7 @@ class HybridObject : public jsi::HostObject, public std::enable_shared_from_this
std::unordered_map<std::string, HybridFunction> _methods;
std::unordered_map<std::string, jsi::HostFunctionType> _getters;
std::unordered_map<std::string, jsi::HostFunctionType> _setters;
std::unordered_map<jsi::Runtime*, std::unordered_map<std::string, std::shared_ptr<jsi::Function>>> _functionCache;
// Store a pointer to the runtime. Needed for checking if the runtime is still active, see WorkletRuntimeRegistry.
jsi::Runtime* _creationRuntime = nullptr;
std::unordered_map<jsi::Runtime*, std::unordered_map<std::string, std::weak_ptr<jsi::Function>>> _functionCache;

private:
inline void ensureInitialized(facebook::jsi::Runtime& runtime);
Expand Down Expand Up @@ -149,8 +147,6 @@ class HybridObject : public jsi::HostObject, public std::enable_shared_from_this

_setters[name] = createHybridMethod(method, derivedInstance);
}

bool isRuntimeAlive();
};

} // namespace margelo
19 changes: 11 additions & 8 deletions packages/react-native-nitro-modules/cpp/jsi/FunctionCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,24 @@ static constexpr auto CACHE_PROP_NAME = "__nitroModulesFunctionCache";
FunctionCache::FunctionCache(jsi::Runtime* runtime): _runtime(runtime) {}

std::weak_ptr<FunctionCache> FunctionCache::getOrCreateCache(jsi::Runtime &runtime) {
if (runtime.global().hasProperty(runtime, CACHE_PROP_NAME)) {
// A cache already exists for the given runtime - get it and return a weak ref to it.
Logger::log(TAG, "Runtime %i already has a cache, getting it..", getRuntimeId(runtime));
auto cache = runtime.global().getPropertyAsObject(runtime, CACHE_PROP_NAME);
auto nativeState = cache.getNativeState<FunctionCache>(runtime);
return std::weak_ptr(nativeState);
if (_globalCache.contains(&runtime)) {
// Fast path: get weak_ptr to FunctionCache from our global list.
return _globalCache[&runtime];
}

// Cache doesn't exist yet - create one, inject it into global, and return a weak ref.
// Cache doesn't exist yet.
Logger::log(TAG, "Creating new FunctionCache for runtime %i..", getRuntimeId(runtime));
// Create new cache
auto nativeState = std::make_shared<FunctionCache>(&runtime);
// Wrap it in a jsi::Value using NativeState
jsi::Object cache(runtime);
cache.setNativeState(runtime, nativeState);
// Inject it into the jsi::Runtime's global so it's memory is managed by it
runtime.global().setProperty(runtime, CACHE_PROP_NAME, std::move(cache));
return std::weak_ptr(nativeState);
// Add it to our map of caches
_globalCache[&runtime] = nativeState;
// Return it
return nativeState;
}

std::weak_ptr<jsi::Function> FunctionCache::makeGlobal(jsi::Function&& function) {
Expand Down
6 changes: 6 additions & 0 deletions packages/react-native-nitro-modules/cpp/jsi/FunctionCache.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <jsi/jsi.h>
#include <memory>
#include <vector>
#include <unordered_map>

namespace margelo {

Expand Down Expand Up @@ -47,6 +48,11 @@ class FunctionCache: public jsi::NativeState {
private:
jsi::Runtime* _runtime;
std::vector<std::shared_ptr<jsi::Function>> _cache;

private:
static std::unordered_map<jsi::Runtime*, std::weak_ptr<FunctionCache>> _globalCache;

private:
static constexpr auto TAG = "FunctionCache";
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#include "EnumMapper.hpp"
#include "HybridObject.hpp"
#include "Promise.hpp"
#include "PromiseFactory.hpp"
#include "Dispatcher.hpp"
#include "FunctionCache.hpp"
#include <array>
Expand Down
11 changes: 4 additions & 7 deletions packages/react-native-nitro-modules/cpp/react-native-nitro.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
#include "react-native-nitro.hpp"

#include <swift/bridging>
#include "NitroModules-Swift.h"

namespace nitro {
double multiply(double a, double b) {
auto exampleClass = NitroModules::HybridObject::init("Heyo!");

return a * b;
}
std::shared_ptr<margelo::TestHybridObject> createTestHybridObject() {
return std::make_shared<margelo::TestHybridObject>();
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
#ifndef NITRO_H
#define NITRO_H

#include "test-object/TestHybridObject.hpp"

namespace nitro {
double multiply(double a, double b);

std::shared_ptr<margelo::TestHybridObject> createTestHybridObject();
}

#endif /* NITRO_H */
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// Created by Marc Rousavy on 20.02.24.
//

#include "TestHybridObject.hpp"

namespace margelo {

void TestHybridObject::loadHybridMethods() {
// this.int get & set
registerHybridGetter("int", &TestHybridObject::getInt, this);
registerHybridSetter("int", &TestHybridObject::setInt, this);
// this.string get & set
registerHybridGetter("string", &TestHybridObject::getString, this);
registerHybridSetter("string", &TestHybridObject::setString, this);
// this.nullableString get & set
registerHybridGetter("nullableString", &TestHybridObject::getNullableString, this);
registerHybridSetter("nullableString", &TestHybridObject::setNullableString, this);
// this.enum
registerHybridGetter("enum", &TestHybridObject::getEnum, this);
registerHybridSetter("enum", &TestHybridObject::setEnum, this);
// methods
registerHybridMethod("multipleArguments", &TestHybridObject::multipleArguments, this);
// callbacks
registerHybridMethod("getIntGetter", &TestHybridObject::getIntGetter, this);
registerHybridMethod("sayHelloCallback", &TestHybridObject::sayHelloCallback, this);
// custom types
registerHybridMethod("createNewHybridObject", &TestHybridObject::createNewHybridObject, this);
// Promises
registerHybridMethod("calculateFibonacci", &TestHybridObject::calculateFibonacci, this);
registerHybridMethod("calculateFibonacciAsync", &TestHybridObject::calculateFibonacciAsync, this);
}

} // namespace margelo
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//
// Created by Marc Rousavy on 22.02.24.
//

#pragma once

#include "HybridObject.hpp"
#include <optional>
#include <string>
#include <vector>

namespace margelo {

class TestHybridObject : public HybridObject {
public:
explicit TestHybridObject() : HybridObject("TestHybridObject") {}

public:
int getInt() {
return _int;
}
void setInt(int newValue) {
_int = newValue;
}
std::string getString() {
return _string;
}
void setString(const std::string& newValue) {
_string = newValue;
}
void setEnum(TestEnum testEnum) {
_enum = testEnum;
}
TestEnum getEnum() {
return _enum;
}
std::optional<std::string> getNullableString() {
return _nullableString;
}
void setNullableString(std::optional<std::string> string) {
_nullableString = string;
}

std::unordered_map<std::string, double> multipleArguments(int first, bool second, std::string third) {
return std::unordered_map<std::string, double>{{"first", 5312}, {"second", 532233}, {"third", 2786}};
}

std::function<int()> getIntGetter() {
return [this]() -> int { return this->_int; };
}
void sayHelloCallback(std::function<void(std::string)> callback) {
callback("Test Hybrid");
}
std::shared_ptr<TestHybridObject> createNewHybridObject() {
return std::make_shared<TestHybridObject>();
}

uint64_t calculateFibonacci(int count) {
if (count < 0)
throw std::invalid_argument("Cannot calculate fibonacci for " + std::to_string(count) + " - it needs to be at least 0!");
if (count == 0)
return 0;
if (count == 1)
return 1;
if (count >= 94)
throw std::invalid_argument("Cannot calculate fibonacci for " + std::to_string(count) +
" - it needs to be 94 at max, the number will overflow!");

uint64_t prev = 0;
uint64_t current = 1;
for (unsigned int i = 2; i <= count; ++i) {
uint64_t next = prev + current;
prev = current;
current = next;
}
return current;
}

std::future<uint64_t> calculateFibonacciAsync(int count) {
return std::async(std::launch::async, [count, this]() { return this->calculateFibonacci(count); });
}

private:
int _int;
std::string _string;
TestEnum _enum;
std::optional<std::string> _nullableString;

void loadHybridMethods() override;
};

} // namespace margelo

0 comments on commit 166feb4

Please sign in to comment.