koffi 2.1.0-beta.3 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ChangeLog.md +2 -1
- package/build/qemu/2.1.0/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/2.1.0/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/2.1.0/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/2.1.0/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/2.1.0/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/2.1.0/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/2.1.0/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0/koffi_win32_x64.tar.gz +0 -0
- package/doc/benchmarks.md +14 -14
- package/doc/benchmarks.xlsx +0 -0
- package/doc/index.rst +2 -2
- package/doc/static/perf_linux_20220812.png +0 -0
- package/doc/static/perf_windows_20220812.png +0 -0
- package/doc/types.md +10 -12
- package/package.json +2 -2
- package/qemu/registry/machines.json +2 -2
- package/qemu/registry/sha256sum.txt +2 -2
- package/src/abi_arm32.cc +23 -55
- package/src/abi_arm64.cc +22 -54
- package/src/abi_riscv64.cc +20 -52
- package/src/abi_x64_sysv.cc +20 -52
- package/src/abi_x64_win.cc +20 -52
- package/src/abi_x86.cc +24 -56
- package/src/call.cc +117 -143
- package/src/call.hh +4 -4
- package/src/ffi.cc +16 -4
- package/src/util.hh +0 -20
- package/test/callbacks.js +3 -3
- package/test/misc.c +2 -2
- package/test/sync.js +2 -2
- package/vendor/libcc/libcc.cc +75 -55
- package/vendor/libcc/libcc.hh +306 -255
- package/vendor/raylib/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/raylib_android.NativeActivity.vcxproj +226 -0
- package/vendor/raylib/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/raylib_android.NativeActivity.vcxproj.filters +10 -0
- package/vendor/raylib/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/raylib_android.NativeActivity.vcxproj.user +4 -0
- package/vendor/raylib/projects/VS2019-Android/raylib_android.sln +75 -0
- package/vendor/raylib/projects/VS2022/examples/audio_module_playing.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/audio_multichannel_sound.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/audio_music_stream.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/audio_raw_stream.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/audio_sound_loading.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/audio_stream_effects.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/core_2d_camera.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/core_2d_camera_mouse_zoom.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/core_2d_camera_platformer.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/core_3d_camera_first_person.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/core_3d_camera_free.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/core_3d_camera_mode.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/core_3d_picking.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/core_basic_screen_manager.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/core_basic_window.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/core_custom_frame_control.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/core_custom_logging.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/core_drop_files.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/core_input_gamepad.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/core_input_gestures.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/core_input_keys.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/core_input_mouse.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/core_input_mouse_wheel.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/core_input_multitouch.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/core_loading_thread.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/core_random_values.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/core_scissor_test.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/core_split_screen.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/core_storage_values.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/core_vr_simulator.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/core_window_flags.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/core_window_letterbox.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/core_window_should_close.vcxproj +390 -0
- package/vendor/raylib/projects/VS2022/examples/core_world_screen.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/easings_testbed.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/embedded_files_loading.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_animation.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_billboard.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_box_collisions.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_cubicmap.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_first_person_maze.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_geometric_shapes.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_heightmap.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_loading.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_loading_gltf.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_loading_vox.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_mesh_generation.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_mesh_picking.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_orthographic_projection.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_rlgl_solar_system.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_skybox.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_waving_cubes.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/models_yaw_pitch_roll.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/rlgl_compute_shaders.vcxproj +391 -0
- package/vendor/raylib/projects/VS2022/examples/rlgl_standalone.vcxproj +391 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_basic_lighting.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_custom_uniform.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_eratosthenes.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_fog.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_hot_reloading.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_julia_set.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_mesh_instancing.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_model_shader.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_multi_sample2d.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_palette_switch.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_postprocessing.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_raymarching.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_shapes_textures.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_simple_mask.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_spotlight.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_texture_drawing.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shaders_texture_waves.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shapes_basic_shapes.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shapes_bouncing_ball.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shapes_collision_area.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shapes_colors_palette.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shapes_draw_circle_sector.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shapes_draw_rectangle_rounded.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shapes_draw_ring.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shapes_easings_ball_anim.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shapes_easings_box_anim.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shapes_easings_rectangle_array.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shapes_following_eyes.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shapes_lines_bezier.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shapes_logo_raylib.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shapes_logo_raylib_anim.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/shapes_rectangle_scaling.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/text_codepoints_loading.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/text_draw_3d.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/text_font_filters.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/text_font_loading.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/text_font_sdf.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/text_font_spritefont.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/text_format_text.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/text_input_box.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/text_raylib_fonts.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/text_rectangle_bounds.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/text_unicode.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/text_writing_anim.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_background_scrolling.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_blend_modes.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_bunnymark.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_draw_tiled.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_fog_of_war.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_gif_player.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_image_drawing.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_image_generation.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_image_loading.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_image_processing.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_image_text.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_logo_raylib.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_mouse_painting.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_npatch_drawing.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_particles_blending.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_polygon.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_raw_data.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_sprite_anim.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_sprite_button.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_sprite_explosion.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_srcrec_dstrec.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/examples/textures_to_image.vcxproj +387 -0
- package/vendor/raylib/projects/VS2022/raylib/raylib.vcxproj +340 -0
- package/vendor/raylib/projects/VS2022/raylib.sln +2347 -0
- package/build/qemu/2.1.0-beta.3/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_win32_x64.tar.gz +0 -0
- package/doc/dist/doctrees/benchmarks.doctree +0 -0
- package/doc/dist/doctrees/changes.doctree +0 -0
- package/doc/dist/doctrees/contribute.doctree +0 -0
- package/doc/dist/doctrees/environment.pickle +0 -0
- package/doc/dist/doctrees/functions.doctree +0 -0
- package/doc/dist/doctrees/index.doctree +0 -0
- package/doc/dist/doctrees/memory.doctree +0 -0
- package/doc/dist/doctrees/platforms.doctree +0 -0
- package/doc/dist/doctrees/start.doctree +0 -0
- package/doc/dist/doctrees/types.doctree +0 -0
- package/doc/dist/html/.buildinfo +0 -4
- package/doc/dist/html/_sources/benchmarks.md.txt +0 -137
- package/doc/dist/html/_sources/changes.md.txt +0 -161
- package/doc/dist/html/_sources/contribute.md.txt +0 -127
- package/doc/dist/html/_sources/functions.md.txt +0 -421
- package/doc/dist/html/_sources/index.rst.txt +0 -39
- package/doc/dist/html/_sources/memory.md.txt +0 -32
- package/doc/dist/html/_sources/platforms.md.txt +0 -31
- package/doc/dist/html/_sources/start.md.txt +0 -100
- package/doc/dist/html/_sources/types.md.txt +0 -541
- package/doc/dist/html/_static/_sphinx_javascript_frameworks_compat.js +0 -134
- package/doc/dist/html/_static/basic.css +0 -932
- package/doc/dist/html/_static/bench_linux.png +0 -0
- package/doc/dist/html/_static/bench_windows.png +0 -0
- package/doc/dist/html/_static/custom.css +0 -22
- package/doc/dist/html/_static/debug.css +0 -69
- package/doc/dist/html/_static/doctools.js +0 -264
- package/doc/dist/html/_static/documentation_options.js +0 -14
- package/doc/dist/html/_static/file.png +0 -0
- package/doc/dist/html/_static/jquery-3.6.0.js +0 -10881
- package/doc/dist/html/_static/jquery.js +0 -2
- package/doc/dist/html/_static/language_data.js +0 -199
- package/doc/dist/html/_static/minus.png +0 -0
- package/doc/dist/html/_static/perf_linux_20220623.png +0 -0
- package/doc/dist/html/_static/perf_linux_20220623_2.png +0 -0
- package/doc/dist/html/_static/perf_linux_20220627.png +0 -0
- package/doc/dist/html/_static/perf_linux_20220628.png +0 -0
- package/doc/dist/html/_static/perf_windows_20220623.png +0 -0
- package/doc/dist/html/_static/perf_windows_20220623_2.png +0 -0
- package/doc/dist/html/_static/perf_windows_20220627.png +0 -0
- package/doc/dist/html/_static/perf_windows_20220628.png +0 -0
- package/doc/dist/html/_static/plus.png +0 -0
- package/doc/dist/html/_static/pygments.css +0 -252
- package/doc/dist/html/_static/scripts/furo-extensions.js +0 -0
- package/doc/dist/html/_static/scripts/furo.js +0 -3
- package/doc/dist/html/_static/scripts/furo.js.LICENSE.txt +0 -7
- package/doc/dist/html/_static/scripts/furo.js.map +0 -1
- package/doc/dist/html/_static/searchtools.js +0 -531
- package/doc/dist/html/_static/skeleton.css +0 -296
- package/doc/dist/html/_static/styles/furo-extensions.css +0 -2
- package/doc/dist/html/_static/styles/furo-extensions.css.map +0 -1
- package/doc/dist/html/_static/styles/furo.css +0 -2
- package/doc/dist/html/_static/styles/furo.css.map +0 -1
- package/doc/dist/html/_static/underscore-1.13.1.js +0 -2042
- package/doc/dist/html/_static/underscore.js +0 -6
- package/doc/dist/html/benchmarks.html +0 -571
- package/doc/dist/html/changes.html +0 -686
- package/doc/dist/html/contribute.html +0 -403
- package/doc/dist/html/functions.html +0 -718
- package/doc/dist/html/genindex.html +0 -253
- package/doc/dist/html/index.html +0 -359
- package/doc/dist/html/memory.html +0 -346
- package/doc/dist/html/objects.inv +0 -0
- package/doc/dist/html/platforms.html +0 -371
- package/doc/dist/html/search.html +0 -261
- package/doc/dist/html/searchindex.js +0 -1
- package/doc/dist/html/start.html +0 -384
- package/doc/dist/html/types.html +0 -1061
package/ChangeLog.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## History
|
|
4
4
|
|
|
5
|
-
### Koffi 2.1.0
|
|
5
|
+
### Koffi 2.1.0
|
|
6
6
|
|
|
7
7
|
**Main changes:**
|
|
8
8
|
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
- Add [endian-sensitive integer types](types.md#endian-sensitive-types): `intX_le_t`, `intX_be_t`
|
|
11
11
|
- Accept typed arrays for `void *` parameters
|
|
12
12
|
- Introduce `koffi.opaque()` to replace `koffi.handle()` (which remains supported until Koffi 3.0)
|
|
13
|
+
- Support JS Array and TypedArray to fill struct and array pointer members
|
|
13
14
|
|
|
14
15
|
**Other changes:**
|
|
15
16
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/doc/benchmarks.md
CHANGED
|
@@ -10,8 +10,8 @@ Here is a quick overview of the execution time of Koffi calls on three benchmark
|
|
|
10
10
|
|
|
11
11
|
<table style="margin: 0 auto;">
|
|
12
12
|
<tr>
|
|
13
|
-
<td><a href="_static/
|
|
14
|
-
<td><a href="_static/
|
|
13
|
+
<td><a href="_static/perf_linux_20220812.png" target="_blank"><img src="_static/perf_linux_20220812.png" alt="Linux x86_64 performance" style="width: 350px;"/></a></td>
|
|
14
|
+
<td><a href="_static/perf_windows_20220812.png" target="_blank"><img src="_static/perf_windows_20220812.png" alt="Windows x86_64 performance" style="width: 350px;"/></a></td>
|
|
15
15
|
</tr>
|
|
16
16
|
</table>
|
|
17
17
|
|
|
@@ -31,9 +31,9 @@ This test is based around repeated calls to a simple standard C function atoi, a
|
|
|
31
31
|
|
|
32
32
|
Benchmark | Iteration time | Relative performance | Overhead
|
|
33
33
|
------------- | -------------- | -------------------- | --------
|
|
34
|
-
rand_napi |
|
|
35
|
-
rand_koffi |
|
|
36
|
-
rand_node_ffi |
|
|
34
|
+
rand_napi | 842 ns | x1.00 | (ref)
|
|
35
|
+
rand_koffi | 1114 ns | x0.76 | +32%
|
|
36
|
+
rand_node_ffi | 44845 ns | x0.02 | +5224%
|
|
37
37
|
|
|
38
38
|
Because rand is a pretty small function, the FFI overhead is clearly visible.
|
|
39
39
|
|
|
@@ -43,9 +43,9 @@ This test is similar to the rand one, but it is based on atoi, which takes a str
|
|
|
43
43
|
|
|
44
44
|
Benchmark | Iteration time | Relative performance | Overhead
|
|
45
45
|
------------- | -------------- | -------------------- | --------
|
|
46
|
-
atoi_napi |
|
|
47
|
-
atoi_koffi |
|
|
48
|
-
atoi_node_ffi |
|
|
46
|
+
atoi_napi | 921 ns | x1.00 | (ref)
|
|
47
|
+
atoi_koffi | 1357 ns | x0.68 | +47%
|
|
48
|
+
atoi_node_ffi | 152550 ns | x0.006 | +16472%
|
|
49
49
|
|
|
50
50
|
Because atoi is a pretty small function, the FFI overhead is clearly visible.
|
|
51
51
|
|
|
@@ -77,9 +77,9 @@ This test is based around repeated calls to a simple standard C function atoi, a
|
|
|
77
77
|
|
|
78
78
|
Benchmark | Iteration time | Relative performance | Overhead
|
|
79
79
|
------------- | -------------- | -------------------- | --------
|
|
80
|
-
rand_napi |
|
|
81
|
-
rand_koffi |
|
|
82
|
-
rand_node_ffi |
|
|
80
|
+
rand_napi | 964 ns | x1.00 | (ref)
|
|
81
|
+
rand_koffi | 1274 ns | x0.76 | +32%
|
|
82
|
+
rand_node_ffi | 42300 ns | x0.02 | +4289%
|
|
83
83
|
|
|
84
84
|
Because rand is a pretty small function, the FFI overhead is clearly visible.
|
|
85
85
|
|
|
@@ -91,9 +91,9 @@ The results below were measured on my x86_64 Windows machine (Intel® Core™ i5
|
|
|
91
91
|
|
|
92
92
|
Benchmark | Iteration time | Relative performance | Overhead
|
|
93
93
|
------------- | -------------- | -------------------- | --------
|
|
94
|
-
atoi_napi |
|
|
95
|
-
atoi_koffi |
|
|
96
|
-
atoi_node_ffi |
|
|
94
|
+
atoi_napi | 1415 ns | x1.00 | (ref)
|
|
95
|
+
atoi_koffi | 2193 ns | x0.65 | +55%
|
|
96
|
+
atoi_node_ffi | 168300 ns | x0.008 | +11792%
|
|
97
97
|
|
|
98
98
|
Because atoi is a pretty small function, the FFI overhead is clearly visible.
|
|
99
99
|
|
package/doc/benchmarks.xlsx
CHANGED
|
Binary file
|
package/doc/index.rst
CHANGED
|
Binary file
|
|
Binary file
|
package/doc/types.md
CHANGED
|
@@ -111,16 +111,6 @@ const A = koffi.struct('A', {
|
|
|
111
111
|
});
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
Koffi follows the C and ABI rules regarding struct alignment and padding.
|
|
115
|
-
|
|
116
|
-
Once a struct is declared, you can use it by name (with a string, like you can do for primitive types) or through the value returned by the call to `koffi.struct()`. Only the latter is possible when declaring an anonymous struct.
|
|
117
|
-
|
|
118
|
-
```js
|
|
119
|
-
// The following two function declarations are equivalent, and declare a function taking an A value and returning A
|
|
120
|
-
const Function1 = lib.func('A Function(A value)');
|
|
121
|
-
const Function2 = lib.func('Function', A, [A]);
|
|
122
|
-
```
|
|
123
|
-
|
|
124
114
|
Koffi automatically follows the platform C ABI regarding alignment and padding. However, you can override these rules if needed with:
|
|
125
115
|
|
|
126
116
|
- Pack all members without padding with `koffi.pack()` (instead of `koffi.struct()`)
|
|
@@ -133,13 +123,21 @@ const PackedStruct = koffi.pack('PackedStruct', {
|
|
|
133
123
|
b: 'int16_t'
|
|
134
124
|
});
|
|
135
125
|
|
|
136
|
-
// This one is
|
|
126
|
+
// This one is 10 bytes long, the second member has an alignment requirement of 8 bytes
|
|
137
127
|
const BigStruct = koffi.struct('BigStruct', {
|
|
138
128
|
a: 'int8_t',
|
|
139
|
-
b: [
|
|
129
|
+
b: [8, 'int16_t']
|
|
140
130
|
})
|
|
141
131
|
```
|
|
142
132
|
|
|
133
|
+
Once a struct is declared, you can use it by name (with a string, like you can do for primitive types) or through the value returned by the call to `koffi.struct()`. Only the latter is possible when declaring an anonymous struct.
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
// The following two function declarations are equivalent, and declare a function taking an A value and returning A
|
|
137
|
+
const Function1 = lib.func('A Function(A value)');
|
|
138
|
+
const Function2 = lib.func('Function', A, [A]);
|
|
139
|
+
```
|
|
140
|
+
|
|
143
141
|
### Opaque types
|
|
144
142
|
|
|
145
143
|
Many C libraries use some kind of object-oriented API, with a pair of functions dedicated to create and delete objects. An obvious example of this can be found in stdio.h, with the opaque `FILE *` pointer. You can open and close files with `fopen()` and `fclose()`, and manipule the opaque pointer with other functions such as `fread()` or `ftell()`.
|
package/package.json
CHANGED
|
@@ -178,7 +178,7 @@
|
|
|
178
178
|
"qemu": {
|
|
179
179
|
"binary": "qemu-system-x86_64",
|
|
180
180
|
"arguments": ["-m", "3G", "-smp", 4, "-rtc", "clock=host,base=localtime", "-bios", "bios.bin", "-hda", "disk.qcow2", "-netdev", "user,id=mynet,hostfwd=tcp::22205-:22", "-device", "e1000,netdev=mynet", "-vga", "std", "-device", "qemu-xhci", "-device", "usb-tablet", "-vnc", "127.0.0.1:15"],
|
|
181
|
-
"version":
|
|
181
|
+
"version": 11,
|
|
182
182
|
|
|
183
183
|
"ssh_port": 22205,
|
|
184
184
|
"vnc_port": 5915,
|
|
@@ -227,7 +227,7 @@
|
|
|
227
227
|
"Windows x64": {
|
|
228
228
|
"directory": "C:/Users/windows/Desktop/luigi_x64",
|
|
229
229
|
"build": {
|
|
230
|
-
"Build": "C:\\Node64\\node64.cmd node ../cnoke/cnoke.js -d test
|
|
230
|
+
"Build": "C:\\Node64\\node64.cmd node ../cnoke/cnoke.js -d test"
|
|
231
231
|
},
|
|
232
232
|
"commands": {
|
|
233
233
|
"Test Sync": "C:\\Node64\\node64.cmd node test/sync.js",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
25d4f2a86deb5e2574bb3210b67bb24fcc4afb19f93a7b65a057daa874a9d18e *qemu/windows_x64/VERSION
|
|
2
2
|
0a40f87b2a038522e55318a0abde60403bb13a5e81a7a0966a9a736e65d4ae46 *qemu/windows_x64/install.sh
|
|
3
3
|
f8c9a1638a3fc2cdd214f2cbcad6fee0e3b2c9383942bbd49b3915bb4c3da102 *qemu/windows_x64/bios.bin
|
|
4
|
-
|
|
4
|
+
62a6f3210acf3c9f8d1c5036998da8cecd24e59b75bb2fd6897e990f83546eec *qemu/windows_x64/disk.qcow2
|
|
5
5
|
1121cfccd5913f0a63fec40a6ffd44ea64f9dc135c66634ba001d10bcf4302a2 *qemu/debian_x64/VERSION
|
|
6
6
|
ba418d2d602981fe324ae7a1a608b0f2d8d7c6113d03a429cc402e24ddc81311 *qemu/debian_x64/vmlinuz-5.10.0-12-amd64
|
|
7
7
|
4d44622e8ce058017c08051d694b8e5afe9ff406b6ad91c17ebc4ec43d205c42 *qemu/debian_x64/install.sh
|
package/src/abi_arm32.cc
CHANGED
|
@@ -278,7 +278,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
278
278
|
#define PUSH_INTEGER_32(CType) \
|
|
279
279
|
do { \
|
|
280
280
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) { \
|
|
281
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
281
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
282
282
|
return false; \
|
|
283
283
|
} \
|
|
284
284
|
\
|
|
@@ -288,7 +288,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
288
288
|
#define PUSH_INTEGER_32_SWAP(CType) \
|
|
289
289
|
do { \
|
|
290
290
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) { \
|
|
291
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
291
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
292
292
|
return false; \
|
|
293
293
|
} \
|
|
294
294
|
\
|
|
@@ -298,7 +298,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
298
298
|
#define PUSH_INTEGER_64(CType) \
|
|
299
299
|
do { \
|
|
300
300
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) { \
|
|
301
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
301
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
302
302
|
return false; \
|
|
303
303
|
} \
|
|
304
304
|
\
|
|
@@ -317,7 +317,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
317
317
|
#define PUSH_INTEGER_64_SWAP(CType) \
|
|
318
318
|
do { \
|
|
319
319
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) { \
|
|
320
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
320
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
321
321
|
return false; \
|
|
322
322
|
} \
|
|
323
323
|
\
|
|
@@ -346,7 +346,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
346
346
|
|
|
347
347
|
case PrimitiveKind::Bool: {
|
|
348
348
|
if (RG_UNLIKELY(!value.IsBoolean())) {
|
|
349
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
349
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
|
|
350
350
|
return false;
|
|
351
351
|
}
|
|
352
352
|
|
|
@@ -369,44 +369,28 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
369
369
|
case PrimitiveKind::UInt64S: { PUSH_INTEGER_64_SWAP(uint64_t); } break;
|
|
370
370
|
case PrimitiveKind::String: {
|
|
371
371
|
const char *str;
|
|
372
|
-
if (
|
|
373
|
-
str = PushString(value);
|
|
374
|
-
if (RG_UNLIKELY(!str))
|
|
375
|
-
return false;
|
|
376
|
-
} else if (IsNullOrUndefined(value)) {
|
|
377
|
-
str = nullptr;
|
|
378
|
-
} else {
|
|
379
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), param.offset + 1);
|
|
372
|
+
if (RG_UNLIKELY(!PushString(value, &str)))
|
|
380
373
|
return false;
|
|
381
|
-
}
|
|
382
374
|
|
|
383
375
|
*(const char **)((param.gpr_count ? gpr_ptr : args_ptr)++) = str;
|
|
384
376
|
} break;
|
|
385
377
|
case PrimitiveKind::String16: {
|
|
386
378
|
const char16_t *str16;
|
|
387
|
-
if (
|
|
388
|
-
str16 = PushString16(value);
|
|
389
|
-
if (RG_UNLIKELY(!str16))
|
|
390
|
-
return false;
|
|
391
|
-
} else if (IsNullOrUndefined(value)) {
|
|
392
|
-
str16 = nullptr;
|
|
393
|
-
} else {
|
|
394
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), param.offset + 1);
|
|
379
|
+
if (RG_UNLIKELY(!PushString16(value, &str16)))
|
|
395
380
|
return false;
|
|
396
|
-
}
|
|
397
381
|
|
|
398
382
|
*(const char16_t **)((param.gpr_count ? gpr_ptr : args_ptr)++) = str16;
|
|
399
383
|
} break;
|
|
400
384
|
case PrimitiveKind::Pointer: {
|
|
401
385
|
void *ptr;
|
|
402
|
-
if (RG_UNLIKELY(!PushPointer(value, param, &ptr)))
|
|
386
|
+
if (RG_UNLIKELY(!PushPointer(value, param.type, param.directions, &ptr)))
|
|
403
387
|
return false;
|
|
404
388
|
|
|
405
389
|
*(void **)((param.gpr_count ? gpr_ptr : args_ptr)++) = ptr;
|
|
406
390
|
} break;
|
|
407
391
|
case PrimitiveKind::Record: {
|
|
408
392
|
if (RG_UNLIKELY(!IsObject(value))) {
|
|
409
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
393
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
|
|
410
394
|
return false;
|
|
411
395
|
}
|
|
412
396
|
|
|
@@ -439,7 +423,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
439
423
|
case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
|
|
440
424
|
case PrimitiveKind::Float32: {
|
|
441
425
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
442
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
426
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
443
427
|
return false;
|
|
444
428
|
}
|
|
445
429
|
|
|
@@ -455,7 +439,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
455
439
|
} break;
|
|
456
440
|
case PrimitiveKind::Float64: {
|
|
457
441
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
458
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
442
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
459
443
|
return false;
|
|
460
444
|
}
|
|
461
445
|
|
|
@@ -488,7 +472,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
488
472
|
} else if (IsNullOrUndefined(value)) {
|
|
489
473
|
ptr = nullptr;
|
|
490
474
|
} else {
|
|
491
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
475
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), param.type->name);
|
|
492
476
|
return false;
|
|
493
477
|
}
|
|
494
478
|
|
|
@@ -896,7 +880,7 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
|
|
|
896
880
|
#define RETURN_INTEGER_32_SWAP(CType) \
|
|
897
881
|
do { \
|
|
898
882
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) { \
|
|
899
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
883
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
900
884
|
return; \
|
|
901
885
|
} \
|
|
902
886
|
\
|
|
@@ -906,7 +890,7 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
|
|
|
906
890
|
#define RETURN_INTEGER_64(CType) \
|
|
907
891
|
do { \
|
|
908
892
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) { \
|
|
909
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
893
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
910
894
|
return; \
|
|
911
895
|
} \
|
|
912
896
|
\
|
|
@@ -918,7 +902,7 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
|
|
|
918
902
|
#define RETURN_INTEGER_64_SWAP(CType) \
|
|
919
903
|
do { \
|
|
920
904
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) { \
|
|
921
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
905
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
922
906
|
return; \
|
|
923
907
|
} \
|
|
924
908
|
\
|
|
@@ -933,7 +917,7 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
|
|
|
933
917
|
case PrimitiveKind::Void: {} break;
|
|
934
918
|
case PrimitiveKind::Bool: {
|
|
935
919
|
if (RG_UNLIKELY(!value.IsBoolean())) {
|
|
936
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
920
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
|
|
937
921
|
return;
|
|
938
922
|
}
|
|
939
923
|
|
|
@@ -956,31 +940,15 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
|
|
|
956
940
|
case PrimitiveKind::UInt64S: { RETURN_INTEGER_64_SWAP(uint64_t); } break;
|
|
957
941
|
case PrimitiveKind::String: {
|
|
958
942
|
const char *str;
|
|
959
|
-
if (
|
|
960
|
-
str = PushString(value);
|
|
961
|
-
if (RG_UNLIKELY(!str))
|
|
962
|
-
return;
|
|
963
|
-
} else if (IsNullOrUndefined(value)) {
|
|
964
|
-
str = nullptr;
|
|
965
|
-
} else {
|
|
966
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected string", GetValueType(instance, value));
|
|
943
|
+
if (RG_UNLIKELY(!PushString(value, &str)))
|
|
967
944
|
return;
|
|
968
|
-
}
|
|
969
945
|
|
|
970
946
|
out_reg->r0 = (uint32_t)str;
|
|
971
947
|
} break;
|
|
972
948
|
case PrimitiveKind::String16: {
|
|
973
949
|
const char16_t *str16;
|
|
974
|
-
if (
|
|
975
|
-
str16 = PushString16(value);
|
|
976
|
-
if (RG_UNLIKELY(!str16))
|
|
977
|
-
return;
|
|
978
|
-
} else if (IsNullOrUndefined(value)) {
|
|
979
|
-
str16 = nullptr;
|
|
980
|
-
} else {
|
|
981
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected string", GetValueType(instance, value));
|
|
950
|
+
if (RG_UNLIKELY(!PushString16(value, &str16)))
|
|
982
951
|
return;
|
|
983
|
-
}
|
|
984
952
|
|
|
985
953
|
out_reg->r0 = (uint32_t)str16;
|
|
986
954
|
} break;
|
|
@@ -999,7 +967,7 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
|
|
|
999
967
|
} else if (IsNullOrUndefined(value)) {
|
|
1000
968
|
ptr = nullptr;
|
|
1001
969
|
} else {
|
|
1002
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
970
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
|
|
1003
971
|
return;
|
|
1004
972
|
}
|
|
1005
973
|
|
|
@@ -1007,7 +975,7 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
|
|
|
1007
975
|
} break;
|
|
1008
976
|
case PrimitiveKind::Record: {
|
|
1009
977
|
if (RG_UNLIKELY(!IsObject(value))) {
|
|
1010
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
978
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
|
|
1011
979
|
return;
|
|
1012
980
|
}
|
|
1013
981
|
|
|
@@ -1026,7 +994,7 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
|
|
|
1026
994
|
case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
|
|
1027
995
|
case PrimitiveKind::Float32: {
|
|
1028
996
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
1029
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
997
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
1030
998
|
return;
|
|
1031
999
|
}
|
|
1032
1000
|
|
|
@@ -1039,7 +1007,7 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
|
|
|
1039
1007
|
} break;
|
|
1040
1008
|
case PrimitiveKind::Float64: {
|
|
1041
1009
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
1042
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
1010
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
1043
1011
|
return;
|
|
1044
1012
|
}
|
|
1045
1013
|
|
|
@@ -1064,7 +1032,7 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
|
|
|
1064
1032
|
} else if (IsNullOrUndefined(value)) {
|
|
1065
1033
|
ptr = nullptr;
|
|
1066
1034
|
} else {
|
|
1067
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value
|
|
1035
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
|
|
1068
1036
|
return;
|
|
1069
1037
|
}
|
|
1070
1038
|
|