Skip to content

Commit fd0d825

Browse files
authored
Optimize val::array() iterator version for numeric types. (#17351)
Again numeric contiguous array-like can be optimized same as #17292. But this needs c++20 and later. Also updated the test cases and benchmark tests.
1 parent 9585abd commit fd0d825

File tree

4 files changed

+45
-4
lines changed

4 files changed

+45
-4
lines changed

system/include/emscripten/val.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,17 @@ class val {
327327

328328
template<typename Iter>
329329
static val array(Iter begin, Iter end) {
330+
#if _LIBCPP_STD_VER >= 20
331+
if constexpr (std::contiguous_iterator<Iter> &&
332+
internal::typeSupportsMemoryView<
333+
typename std::iterator_traits<Iter>::value_type>()) {
334+
val view{ typed_memory_view(std::distance(begin, end), std::to_address(begin)) };
335+
return val(internal::_emval_new_array_from_memory_view(view.as_handle()));
336+
}
337+
// For numeric arrays, following codes are unreachable and the compiler
338+
// will do 'dead code elimination'.
339+
// Others fallback old way.
340+
#endif
330341
val new_array = array();
331342
for (auto it = begin; it != end; ++it) {
332343
new_array.call<void>("push", *it);

tests/embind/embind_benchmark.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -476,17 +476,21 @@ void __attribute__((noinline)) numeric_val_array_benchmark() {
476476
for (int i = 0; i < kLoopTimes; i++) {
477477
val v = val::array(vec.begin(), vec.end());
478478
}
479-
printf("val::array: %lf\n", emscripten_get_now() - t);
479+
printf("\nval::array(Iter begin, Iter end): %lf msecs.\n", emscripten_get_now() - t);
480480

481481
t = emscripten_get_now();
482482
for (int i = 0; i < kLoopTimes; i++) {
483483
val v = val::array(vec);
484484
}
485-
printf("val::array opt numeric types: %lf\n", emscripten_get_now() - t);
485+
printf("val::array(const std::vector<T>& vec) with opt numeric types: %lf msecs.\n", emscripten_get_now() - t);
486486

487487
// It's about 20x times faster.
488-
// val::array: 1021.525756
489-
// val::array opt numeric types: 50.600682
488+
// val::array(Iter begin, Iter end): 727.300000 msecs.
489+
// val::array(const std::vector<T>& vec) with opt numeric types: 29.700000 msecs.
490+
491+
// If compile with `--std=c++20`, the result is very close.
492+
// val::array(Iter begin, Iter end): 30.400000 msecs.
493+
// val::array(const std::vector<T>& vec) with opt numeric types: 27.500000 msecs.
490494
}
491495

492496
int EMSCRIPTEN_KEEPALIVE main()

tests/embind/test_val.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,31 @@ int main() {
7474
ensure_js("a[2] == 3");
7575
ensure_js_not("a[2] == 2");
7676

77+
test("template<typename Iter> val array(Iter begin, Iter end)");
78+
val::global().set("a", val::array(vec1.begin(), vec1.end()));
79+
ensure_js("a instanceof Array");
80+
ensure_js_not("a instanceof Boolean");
81+
ensure_js_not("a instanceof Number");
82+
ensure_js("a[0] == 11");
83+
ensure_js_not("a[0] == 12");
84+
ensure_js("a[1] == 'a'");
85+
ensure_js("a[2] instanceof Array");
86+
val::global().set("a", val::array(vec2.begin(), vec2.end()));
87+
ensure_js("a instanceof Array");
88+
ensure_js_not("a instanceof Number");
89+
ensure_js("a[0] == 0");
90+
ensure_js_not("a[0] == 1");
91+
ensure_js("a[1] == 1");
92+
ensure_js("a[2] == 3");
93+
ensure_js_not("a[2] == 2");
94+
int arr[] = {1, 2, 3};
95+
val::global().set("a", val::array(arr, arr + 3));
96+
ensure_js("a instanceof Array");
97+
ensure_js_not("a instanceof Number");
98+
ensure_js("a[0] == 1");
99+
ensure_js("a[1] == 2");
100+
ensure_js("a[2] == 3");
101+
77102
test("val object()");
78103
val::global().set("a", val::object());
79104
ensure_js("a instanceof Object");

tests/embind/test_val.out

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
test: val array()...
22
test: template<typename T> val array(const std::vector<T> vec)...
3+
test: template<typename Iter> val array(Iter begin, Iter end)...
34
test: val object()...
45
test: val undefined()...
56
test: val null()...

0 commit comments

Comments
 (0)