Skip to content

Commit

Permalink
Add C++20 std::span-based APIs for function arguments
Browse files Browse the repository at this point in the history
Summary:
Changelog: [General][Changed] - Add `std::span` methods to `jsi::Function` when compiled as C++20

Adds `std::span<const jsi::Value>` overloads to public JSI methods that currently accept (or are designed to emit) `const jsi::Value* args, size_t count` for a dynamically-sized span of function arguments.

These are:
* `Function::call`
* `Function::callWithThis`
* `Function::callAsConstructor`
* `Function::createFromHostFunction`

We also add a `HostFunctionTypeWithSpanArgs` typedef (naming feedback welcome!) to serve a similar purpose to the existing `HostFunctionType`.

## Backwards compatibility

* The new APIs are compiled conditionally to support pre-C++20 compilers.
* No overloads are removed.
* The new overloads are implemented as `inline` wrappers over the pointer+size versions. No change is made to the JSI contract for implementers (i.e. no new overloads, virtual or otherwise, are added to `Runtime`).

Differential Revision: D54901847
  • Loading branch information
motiz88 authored and facebook-github-bot committed Mar 14, 2024
1 parent 0d7a92b commit 7cbce63
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 0 deletions.
39 changes: 39 additions & 0 deletions packages/react-native/ReactCommon/jsi/jsi/jsi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,45 @@ inline Value Function::callAsConstructor(Runtime& runtime, Args&&... args)
runtime, {detail::toValue(runtime, std::forward<Args>(args))...});
}

#if __cplusplus >= 202002L

// std::span-based APIs for Function

inline Function Function::createFromHostFunction(
Runtime& runtime,
const jsi::PropNameID& name,
unsigned int paramCount,
jsi::HostFunctionTypeWithSpanArgs func) {
return createFromHostFunction(
runtime,
name,
paramCount,
[func = std::move(func)](
Runtime& rt, const Value& thisVal, const Value* args, size_t count)
-> Value {
return func(rt, thisVal, {args, count});
});
}

inline Value Function::call(Runtime& runtime, std::span<const Value> args)
const {
return call(runtime, args.data(), args.size());
}

inline Value Function::callWithThis(
Runtime& runtime,
const Object& jsThis,
std::span<const Value> args) const {
return callWithThis(runtime, jsThis, args.data(), args.size());
}

Value Function::callAsConstructor(Runtime& runtime, std::span<const Value> args)
const {
return callAsConstructor(runtime, args.data(), args.size());
}

#endif // __cplusplus >= 202002L

String BigInt::toString(Runtime& runtime, int radix) const {
return runtime.bigintToString(*this, radix);
}
Expand Down
51 changes: 51 additions & 0 deletions packages/react-native/ReactCommon/jsi/jsi/jsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
#include <string>
#include <vector>

#if __cplusplus >= 202002L
#include <span>
#endif

#ifndef JSI_EXPORT
#ifdef _MSC_VER
#ifdef CREATE_SHARED_LIBRARY
Expand Down Expand Up @@ -111,6 +115,15 @@ class JSError;
using HostFunctionType = std::function<
Value(Runtime& rt, const Value& thisVal, const Value* args, size_t count)>;

#if __cplusplus >= 202002L

/// The equivalent of HostFunctionType, but with the arguments passed as a
/// std::span.
using HostFunctionTypeWithSpanArgs = std::function<
Value(Runtime& rt, const Value& thisVal, std::span<const Value> args)>;

#endif // __cplusplus >= 202002L

/// An object which implements this interface can be registered as an
/// Object with the JS runtime.
class JSI_EXPORT HostObject {
Expand Down Expand Up @@ -1089,6 +1102,44 @@ class JSI_EXPORT Function : public Object {
return runtime.getHostFunction(*this);
}

#if __cplusplus >= 202002L

// std::span-based APIs

/// Create a function which, when invoked, calls C++ code. If the
/// function throws an exception, a JS Error will be created and
/// thrown.
/// \param name the name property for the function.
/// \param paramCount the length property for the function, which
/// may not be the number of arguments the function is passed.
static inline Function createFromHostFunction(
Runtime& runtime,
const jsi::PropNameID& name,
unsigned int paramCount,
jsi::HostFunctionTypeWithSpanArgs func);

/// Calls the function with a \c std::span of Value arguments. The \c this
/// value of the JS function will not be set by the C++ caller, similar to
/// calling Function.prototype.apply(undefined, args) in JS.
/// \b Note: as with Function.prototype.apply, \c this may not always be
/// \c undefined in the function itself. If the function is non-strict,
/// \c this will be set to the global object.
inline Value call(Runtime& runtime, std::span<const Value> args) const;

/// Calls the function with a \c std::span of Value arguments and \c jsThis
/// passed as the \c this value.
inline Value callWithThis(
Runtime& runtime,
const Object& jsThis,
std::span<const Value> args) const;

/// Same as above `callAsConstructor`, except use a std::span to
/// supply the arguments.
inline Value callAsConstructor(Runtime& runtime, std::span<const Value> args)
const;

#endif // __cplusplus >= 202002L

private:
friend class Object;
friend class Value;
Expand Down

0 comments on commit 7cbce63

Please sign in to comment.