To pass typed array from emscripten'ed C++ to javascript I came up with this code
#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);
}
(build with em++ test.cpp -o test.html --bind)
In this case there are two extra copies:
- the copy from input array to wasm memory, as far as I understand it's unavoidable;
const auto data = emscripten::convertJSArrayToNumberVector<float>(input); - the copy from wasm memory to javascript object:
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;
Is there a way to avoid extra copy from generated output to javascript object in the second case?
I'm aware of the possibility to return memory view like this:
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);
}
But in this case the returned object refers to the underlying memory owned by output static object with all the consequences, like modifying the memory on the C++ side, or even deallocating it.