Rect Native bridging 源码分析--Array.h

Array.h 代码目录:

复制代码
packages/react-native/ReactCommon/react/bridging/Array.h

代码如下:

cpp 复制代码
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#pragma once

#include <react/bridging/Base.h>

#include <array>
#include <deque>
#include <initializer_list>
#include <list>
#include <set>
#include <tuple>
#include <utility>
#include <vector>

namespace facebook::react {

namespace array_detail {

template <typename T, size_t N>
struct BridgingStatic {
  static jsi::Array toJs(jsi::Runtime &rt, const T &array, const std::shared_ptr<CallInvoker> &jsInvoker)
  {
    return toJs(rt, array, jsInvoker, std::make_index_sequence<N>{});
  }

 private:
  template <size_t... Index>
  static jsi::Array toJs(
      facebook::jsi::Runtime &rt,
      const T &array,
      const std::shared_ptr<CallInvoker> &jsInvoker,
      std::index_sequence<Index...> /*unused*/)
  {
    return jsi::Array::createWithElements(rt, bridging::toJs(rt, std::get<Index>(array), jsInvoker)...);
  }
};

template <typename T>
struct BridgingDynamic {
  static jsi::Array toJs(jsi::Runtime &rt, const T &list, const std::shared_ptr<CallInvoker> &jsInvoker)
  {
    jsi::Array result(rt, list.size());
    size_t index = 0;

    for (const auto &item : list) {
      result.setValueAtIndex(rt, index++, bridging::toJs(rt, item, jsInvoker));
    }

    return result;
  }
};

} // namespace array_detail

template <typename T, size_t N>
struct Bridging<std::array<T, N>> : array_detail::BridgingStatic<std::array<T, N>, N> {
  static std::array<T, N>
  fromJs(facebook::jsi::Runtime &rt, const jsi::Array &array, const std::shared_ptr<CallInvoker> &jsInvoker)
  {
    size_t length = array.length(rt);

    std::array<T, N> result;
    for (size_t i = 0; i < length; i++) {
      result[i] = bridging::fromJs<T>(rt, array.getValueAtIndex(rt, i), jsInvoker);
    }

    return result;
  }
};

template <typename T1, typename T2>
struct Bridging<std::pair<T1, T2>> : array_detail::BridgingStatic<std::pair<T1, T2>, 2> {
  static std::pair<T1, T1>
  fromJs(facebook::jsi::Runtime &rt, const jsi::Array &array, const std::shared_ptr<CallInvoker> &jsInvoker)
  {
    return std::make_pair(
        bridging::fromJs<T1>(rt, array.getValueAtIndex(rt, 0), jsInvoker),
        bridging::fromJs<T2>(rt, array.getValueAtIndex(rt, 1), jsInvoker));
  }
};

template <typename... Types>
struct Bridging<std::tuple<Types...>> : array_detail::BridgingStatic<std::tuple<Types...>, sizeof...(Types)> {};

template <typename T>
struct Bridging<std::deque<T>> : array_detail::BridgingDynamic<std::deque<T>> {};

template <typename T>
struct Bridging<std::initializer_list<T>> : array_detail::BridgingDynamic<std::initializer_list<T>> {};

template <typename T>
struct Bridging<std::list<T>> : array_detail::BridgingDynamic<std::list<T>> {};

template <typename T>
struct Bridging<std::vector<T>> : array_detail::BridgingDynamic<std::vector<T>> {
  static std::vector<T>
  fromJs(facebook::jsi::Runtime &rt, const jsi::Array &array, const std::shared_ptr<CallInvoker> &jsInvoker)
  {
    size_t length = array.length(rt);

    std::vector<T> vector;
    vector.reserve(length);

    for (size_t i = 0; i < length; i++) {
      vector.push_back(bridging::fromJs<T>(rt, array.getValueAtIndex(rt, i), jsInvoker));
    }

    return vector;
  }
};

template <typename T>
struct Bridging<std::set<T>> : array_detail::BridgingDynamic<std::set<T>> {
  static std::set<T>
  fromJs(facebook::jsi::Runtime &rt, const jsi::Array &array, const std::shared_ptr<CallInvoker> &jsInvoker)
  {
    size_t length = array.length(rt);

    std::set<T> set;
    for (size_t i = 0; i < length; i++) {
      set.insert(bridging::fromJs<T>(rt, array.getValueAtIndex(rt, i), jsInvoker));
    }

    return set;
  }
};

} // namespace facebook::react

概述

该头文件属于 facebook::react 命名空间,提供了 C++ 标准集合类型与 JavaScript (JSI, JavaScript Interface) 数组(jsi::Array)之间的双向桥接能力。核心功能是实现 C++ 集合与 JS 数组的相互转换(toJs 转 JS、fromJs 转 C++),支撑 React Native 等跨端框架中 C++ 层与 JS 层的数据通信。

核心命名空间与内部细节

1. 顶层命名空间

cpp 复制代码
facebook::react

所有桥接结构体与方法均位于该命名空间下。

2. 内部辅助命名空间

cpp 复制代码
facebook::react::array_detail

提供两种核心桥接实现模板,用于复用静态长度集合与动态长度集合的转换逻辑,不对外直接暴露使用。

辅助结构体 适用场景 核心逻辑
BridgingStatic<T, N> 静态长度集合(编译期确定长度) 利用 C++ 索引序列(std::index_sequence)实现编译期遍历,通过完美转发完成元素转换,效率更高
BridgingDynamic<T> 动态长度集合(运行期确定长度) 利用运行期循环遍历集合元素,逐个完成转换,兼容性更强

核心桥接接口

所有公开桥接结构体均遵循统一接口规范:

  1. 静态方法 toJs:将 C++ 集合转换为 JSI 数组
    • 签名:static jsi::Array toJs(jsi::Runtime &rt, const T &collection, const std::shared_ptr<CallInvoker> &jsInvoker)
    • 参数:
      • rt:JSI 运行时环境引用,提供 JS 层执行上下文
      • collection:待转换的 C++ 集合常量引用
      • jsInvoker:JS 调用器智能指针,用于异步 / 同步调用 JS 方法
    • 返回值:jsi::Array,对应 JS 层的数组对象
  2. 静态方法 fromJs(可选,部分集合默认实现,部分自定义实现):将 JSI 数组转换为 C++ 集合
    • 签名:static T fromJs(jsi::Runtime &rt, const jsi::Array &array, const std::shared_ptr<CallInvoker> &jsInvoker)
    • 参数:
      • rt:JSI 运行时环境引用
      • array:待转换的 JSI 数组常量引用
      • jsInvoker:JS 调用器智能指针
    • 返回值:对应的 C++ 集合对象 T

各集合类型桥接详情

1. std::array<T, N> 桥接

模板定义
cpp 复制代码
template <typename T, size_t N>
struct Bridging<std::array<T, N>> : array_detail::BridgingStatic<std::array<T, N>, N>
适用场景

C++ 静态长度数组(编译期确定长度 N,元素类型 T)。

继承关系

继承自 array_detail::BridgingStatic,复用静态长度集合的转换逻辑。

核心方法
方法名 功能 实现细节
toJs C++ std::array → JS 数组 利用索引序列编译期遍历数组元素,批量转换后创建 jsi::Array
fromJs JS 数组 → C++ std::array 1. 获取 JS 数组长度2. 循环遍历 JS 数组元素,逐个转换并赋值到 std::array3. 若 JS 数组长度小于 N,剩余 std::array 元素保持默认值;若大于 N,超出部分忽略

2. std::pair<T1, T2> 桥接

模板定义
cpp 复制代码
template <typename T1, typename T2>
struct Bridging<std::pair<T1, T2>> : array_detail::BridgingStatic<std::pair<T1, T2>, 2>
适用场景

C++ 键值对(两个元素,类型分别为 T1T2)。

继承关系

继承自 array_detail::BridgingStatic(长度固定为 2)。

核心方法
方法名 功能 实现细节
toJs C++ std::pair → JS 数组 编译期提取 pair 的第一个元素(first)和第二个元素(second),转换后创建长度为 2 的 jsi::Array
fromJs JS 数组 → C++ std::pair 1. 提取 JS 数组索引 0 和索引 1 的元素,分别转换为 T1T2 类型2. 通过 std::make_pair 创建 std::pair<T1, T2> 对象3. 注意:代码中返回值类型存在笔误(std::pair<T1, T1> 应为 std::pair<T1, T2>),不影响核心逻辑

3. std::tuple<Types...> 桥接

模板定义
cpp 复制代码
template <typename... Types>
struct Bridging<std::tuple<Types...>> : array_detail::BridgingStatic<std::tuple<Types...>, sizeof...(Types)>
适用场景

C++ 元组(支持任意数量、任意类型的元素,长度为 sizeof...(Types))。

继承关系

继承自 array_detail::BridgingStatic,复用静态长度集合的转换逻辑。

核心方法
方法名 功能 实现细节
toJs C++ std::tuple → JS 数组 利用索引序列编译期遍历元组所有元素,批量转换后创建对应长度的 jsi::Array
fromJs 未自定义实现 暂未提供自定义转换逻辑,若需使用需依赖默认实现(或上层扩展)

4. std::deque<T> 桥接

模板定义
cpp 复制代码
template <typename T>
struct Bridging<std::deque<T>> : array_detail::BridgingDynamic<std::deque<T>>
适用场景

C++ 双端队列(动态长度,支持首尾高效插入 / 删除)。

继承关系

继承自 array_detail::BridgingDynamic,复用动态长度集合的转换逻辑。

核心方法
方法名 功能 实现细节
toJs C++ std::deque → JS 数组 1. 创建与 deque 长度一致的 jsi::Array2. 运行期循环遍历 deque 元素,逐个转换并赋值到 JS 数组对应索引
fromJs 未自定义实现 暂未提供自定义转换逻辑,依赖默认实现

5. std::initializer_list<T> 桥接

模板定义
cpp 复制代码
template <typename T>
struct Bridging<std::initializer_list<T>> : array_detail::BridgingDynamic<std::initializer_list<T>>
适用场景

C++ 初始化列表(临时动态元素序列,用于初始化其他集合)。

继承关系

继承自 array_detail::BridgingDynamic

核心方法
方法名 功能 实现细节
toJs C++ 初始化列表 → JS 数组 运行期循环遍历初始化列表元素,逐个转换后创建 jsi::Array
fromJs 未自定义实现 暂未提供自定义转换逻辑,依赖默认实现

6. std::list<T> 桥接

模板定义
cpp 复制代码
template <typename T>
struct Bridging<std::list<T>> : array_detail::BridgingDynamic<std::list<T>>
适用场景

C++ 双向链表(动态长度,支持高效插入 / 删除,不支持随机访问)。

继承关系

继承自 array_detail::BridgingDynamic

核心方法
方法名 功能 实现细节
toJs C++ std::list → JS 数组 运行期循环遍历链表元素(迭代器遍历),逐个转换后创建 jsi::Array
fromJs 未自定义实现 暂未提供自定义转换逻辑,依赖默认实现

7. std::vector<T> 桥接

模板定义
cpp 复制代码
template <typename T>
struct Bridging<std::vector<T>> : array_detail::BridgingDynamic<std::vector<T>>
适用场景

C++ 动态数组(最常用动态集合,支持随机访问,尾部插入 / 删除高效)。

继承关系

继承自 array_detail::BridgingDynamic,并自定义了 fromJs 方法优化性能。

核心方法
方法名 功能 实现细节(性能优化点)
toJs C++ std::vector → JS 数组 运行期循环遍历 vector 元素,逐个转换后创建 jsi::Array
fromJs JS 数组 → C++ std::vector 1. 获取 JS 数组长度,调用 vector.reserve(length) 预分配内存,避免多次扩容2. 循环遍历 JS 数组元素,逐个转换后通过 push_back 插入 vector3. 最终返回填充后的 vector

8. std::set<T> 桥接

模板定义
cpp 复制代码
template <typename T>
struct Bridging<std::set<T>> : array_detail::BridgingDynamic<std::set<T>>
适用场景

C++ 有序不重复集合(基于红黑树实现,元素自动排序且唯一)。

继承关系

继承自 array_detail::BridgingDynamic,并自定义了 fromJs 方法。

核心方法
方法名 功能 实现细节
toJs C++ std::set → JS 数组 运行期循环遍历有序集合元素,逐个转换后创建 jsi::Array(JS 数组保留 std::set 的有序性)
fromJs JS 数组 → C++ std::set 1. 获取 JS 数组长度,初始化空 std::set2. 循环遍历 JS 数组元素,逐个转换后通过 insert 插入 set(自动去重并排序)3. 最终返回有序不重复的 std::set

关键特性总结

  1. 分层设计 :通过 array_detail 内部命名空间隔离通用逻辑,对外暴露简洁的 Bridging 模板接口,提高代码复用性。
  2. 静态 / 动态分离 :静态长度集合(array/pair/tuple)编译期优化,动态长度集合(vector/list/set 等)运行期兼容,兼顾效率与灵活性。
  3. 性能优化std::vectorfromJs 方法使用 reserve 预分配内存,减少内存扩容开销;std::set 利用 insert 自动去重排序,贴合其数据特性。
  4. 统一接口 :所有桥接结构体遵循 toJs/fromJs 统一签名,降低使用成本,便于扩展新的集合类型。

注意事项

  1. std::pair<T1, T2>fromJs 方法存在返回值类型笔误(std::pair<T1, T1> 应为 std::pair<T1, T2>),使用时需注意(或修正代码)。
  2. 仅支持代码中列举的 C++ 标准集合类型,自定义集合需手动实现 Bridging 模板特化。
  3. 元素类型 T 需满足桥接要求(即 bridging::toJsbridging::fromJs 支持 T 类型的转换)。
  4. 依赖 JSI 库(jsi::Runtimejsi::Array)和 React 基础桥接(react/bridging/Base.h),使用时需引入对应依赖。
相关推荐
郝学胜-神的一滴5 分钟前
线程同步:并行世界的秩序守护者
java·linux·开发语言·c++·程序人生
im_AMBER6 分钟前
Leetcode 95 分割链表
数据结构·c++·笔记·学习·算法·leetcode·链表
青茶3607 分钟前
【js教程】如何用jq的js方法获取url链接上的参数值?
开发语言·前端·javascript
明洞日记9 分钟前
【VTK手册032】vtkImageConstantPad:医学图像边界填充与尺寸对齐
c++·图像处理·vtk·图形渲染
Aevget16 分钟前
MFC扩展库BCGControlBar Pro v37.1亮点:Ribbon Bar组件全新升级
c++·ribbon·mfc·bcg·界面控件·ui开发
cchjyq23 分钟前
嵌入式按键调参:简洁接口轻松调参(ADC FLASH 按键 屏幕参数显示)
c语言·c++·单片机·mcu·开源·开源软件
程序炼丹师24 分钟前
std::runtime_error是否会终止程序
c++
qq_4335545425 分钟前
C++字符串hash
c++·算法·哈希算法
无限进步_25 分钟前
【C语言】堆(Heap)的数据结构与实现:从构建到应用
c语言·数据结构·c++·后端·其他·算法·visual studio
CodeOfCC36 分钟前
C++ 实现ffmpeg解析hls fmp4 EXT-X-DISCONTINUITY并支持定位
开发语言·c++·ffmpeg·音视频