javascript - 有没有更有效的方法将数组从 C++ 返回到 javascript?
问题描述
要将类型化数组从 emscripten'ed C++ 传递给 javascript,我想出了这段代码
#include <emscripten/bind.h>
#include <emscripten/val.h>
auto test(const emscripten::val &input) {
const auto data = emscripten::convertJSArrayToNumberVector<float>(input); // copies data
// generate output in some form
std::vector<float> output = { 1, 2, 3 };
// make a typed array view of the output
emscripten::val view{ emscripten::typed_memory_view(output.size(), output.data()) };
// create new typed array to return
auto result = emscripten::val::global("Float32Array").new_(output.size());
// copy data from generated output to return object
result.call<void>("set", view);
return result;
}
EMSCRIPTEN_BINDINGS(KissFft) {
emscripten::function("test", &test);
}
(用 构建em++ test.cpp -o test.html --bind
)
在这种情况下,有两个额外的副本:
- 据我所知,从输入数组到 wasm 内存的复制是不可避免的;
const auto data = emscripten::convertJSArrayToNumberVector<float>(input);
- 从 wasm 内存复制到 javascript 对象:
emscripten::val view{ emscripten::typed_memory_view(output.size(), output.data()) }; auto result = emscripten::val::global("Float32Array").new_(output.size()); result.call<void>("set", view); return result;
在第二种情况下,有没有办法避免从生成的输出到 javascript 对象的额外复制?
我知道像这样返回内存视图的可能性:
std::vector<float> output;
auto test(const emscripten::val &input) {
const auto data = emscripten::convertJSArrayToNumberVector<float>(input);
//generate output
return emscripten::val{ emscripten::typed_memory_view(output.size(), output.data()) };
}
EMSCRIPTEN_BINDINGS(KissFft) {
emscripten::function("test", &test);
}
但在这种情况下,返回的对象指的是output
静态对象拥有的底层内存,并会产生所有后果,比如在 C++ 端修改内存,甚至释放它。
解决方案
我想再低一点。放在这里(而不是评论)粘贴片段(取自 emscripten 的 embind 示例,在 C 中,但你可以用 C++ 做同样的事情)。
// quick_example.cpp
#include <emscripten/bind.h>
#include <stdio.h>
using namespace emscripten;
struct buffer {
unsigned int pointer;
unsigned int size;
};
buffer lerp() {
buffer myBuffer;
unsigned int size = 10;
float * myTab = (float*)malloc(size * sizeof(float));
for (int i = 0; i < size; i++) {
myTab[i] = 2.5 * i;
printf(" Native side index: %d value: %f address: %p\n", i, myTab[i], &myTab[i]);
}
myBuffer.pointer = (unsigned int) myTab;
myBuffer.size = size;
printf(" Native side pointer: %p size: %d\n", myTab, size);
return myBuffer;
}
EMSCRIPTEN_BINDINGS(my_module) {
value_array<buffer>("buffer")
.element(&buffer::pointer)
.element(&buffer::size)
;
function("lerp", &lerp);
}
index.html - 在 js 中,您可以复制、制作视图并最终释放内存(据我所知,这是上面的问题之一?)
<!doctype html>
<html>
<script>
var Module = {
onRuntimeInitialized: function() {
var result = Module.lerp();
console.log(" JS side pointer: " + result[0] + " size: " + result[1]);
for (var i = 0; i < result[1]; i++) {
console.log("index: " + i + " value: " + Module.HEAPF32[(result[0] + i * 4) / 4] + " pointerInc: " + (result[0] + i * 4));
}
Module._free(result[0]);
}
};
</script>
<script src="lerp.js"></script>
</html>
构建命令
emcc --bind -o lerp.js lerp.cpp
推荐阅读
- oracle - 我可以在更改之前检查表或列是否存在吗?
- ruby-on-rails - 如何使用占位符天数和实际报告绘制一个月的所有天数
- arrays - 这个数组初始化是什么意思?CPLEX
- php - 每次启动 PHP 前更改 cainfo 和 cafile
- google-cloud-run - Cloud Run (GCR) 可以覆盖容器的 CMD 吗?
- javascript - enable() 和 disable() emojionearea
- python - 有没有一种有效的方法可以用另一个字符串覆盖索引处的字符串?
- typescript - Heroku 找不到 ts 节点
- java - for循环中的.Array索引越界异常
- java - 如何在 Java 中动态指定对象的 Class?