diff --git a/py/modmicropython.c b/py/modmicropython.c index bdb1e8b9b4c00..c0465e4665d72 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -25,8 +25,10 @@ */ #include +#include #include "py/builtin.h" +#include "py/obj.h" #include "py/stackctrl.h" #include "py/runtime.h" #include "py/gc.h" @@ -166,6 +168,96 @@ STATIC mp_obj_t mp_micropython_schedule(mp_obj_t function, mp_obj_t arg) { STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_micropython_schedule_obj, mp_micropython_schedule); #endif +#if MICROPY_ENABLE_MEM_FUNCTIONS + +STATIC mp_obj_t mp_micropython_memmove(size_t n_args, const mp_obj_t *args) { + enum { ARG_dest, ARG_dest_idx, ARG_src, ARG_src_idx, ARG_len }; // len is optional + mp_buffer_info_t src, dest; + mp_int_t src_idx, dest_idx, len, max_len; + + mp_get_buffer_raise(args[ARG_dest], &dest, MP_BUFFER_WRITE); + mp_get_buffer_raise(args[ARG_src], &src, MP_BUFFER_READ); + dest_idx = mp_obj_get_int(args[ARG_dest_idx]); + src_idx = mp_obj_get_int(args[ARG_src_idx]); + + // similar to slice syntax, negative indexes are relative to the end + if (dest_idx < 0) { + dest_idx += dest.len; + } + if (src_idx < 0) { + src_idx += src.len; + } + + if (dest_idx < 0 || src_idx < 0 || (size_t)dest_idx >= dest.len || (size_t)src_idx >= src.len) { + // TODO: Maybe it's better to emulate slice syntax here and have ranges + // past the end silently truncate to the end? + mp_raise_type(&mp_type_IndexError); // TODO: ValueError? IndexError is what equivalent Python code would raise + } + + // The most bytes we can move + max_len = MIN(dest.len - dest_idx, src.len - src_idx); + + if (n_args > ARG_len) { + len = mp_obj_get_int(args[ARG_len]); + if (len < 0 || len > max_len) { + // TODO: maybe better to truncate here as well? + mp_raise_type(&mp_type_IndexError); // TODO: ValueError? see above + } + } else { + len = max_len; + } + + memmove((char *)dest.buf + dest_idx, (char *)src.buf + src_idx, len); + + return mp_obj_new_int(len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_memmove_obj, 4, 5, mp_micropython_memmove); + +STATIC mp_obj_t mp_micropython_memset(size_t n_args, const mp_obj_t *args) { + enum { ARG_dest, ARG_dest_idx, ARG_c, ARG_len }; + mp_buffer_info_t dest; + mp_int_t dest_idx = 0; + uint8_t c = 0; + mp_int_t len; + + mp_get_buffer_raise(args[ARG_dest], &dest, MP_BUFFER_WRITE); + if (n_args > ARG_dest_idx) { + dest_idx = mp_obj_get_int(args[ARG_dest_idx]); + + if (dest_idx < 0) { + // Like slice syntax, negative value indexes from the end + dest_idx += dest.len; + } + + if (dest_idx < 0 || (size_t)dest_idx >= dest.len) { + mp_raise_type(&mp_type_IndexError); // TODO: ValueError? see above + } + } + + if (n_args > ARG_c) { + // To save code size, don't range-check if c is a single byte integer, + // out of range values are truncated and then used. + c = mp_obj_get_int(args[ARG_c]); + } + + if (n_args > ARG_len) { + len = mp_obj_get_int(args[ARG_len]); + if (len < 0 || (size_t)len > dest.len - dest_idx) { + mp_raise_type(&mp_type_IndexError); // TODO: ValueError? see above + } + } else { + len = dest.len - dest_idx; + } + + memset((char *)dest.buf + dest_idx, c, len); + + return mp_obj_new_int(len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_memset_obj, 1, 4, mp_micropython_memset); + +#endif + + STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_micropython) }, { MP_ROM_QSTR(MP_QSTR_const), MP_ROM_PTR(&mp_identity_obj) }, @@ -203,6 +295,10 @@ STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { #if MICROPY_ENABLE_SCHEDULER { MP_ROM_QSTR(MP_QSTR_schedule), MP_ROM_PTR(&mp_micropython_schedule_obj) }, #endif + #if MICROPY_ENABLE_MEM_FUNCTIONS + { MP_ROM_QSTR(MP_QSTR_memmove), MP_ROM_PTR(&mp_micropython_memmove_obj) }, + { MP_ROM_QSTR(MP_QSTR_memset), MP_ROM_PTR(&mp_micropython_memset_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(mp_module_micropython_globals, mp_module_micropython_globals_table); diff --git a/py/mpconfig.h b/py/mpconfig.h index 433d6e50def2d..db0f2f5f2190f 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1256,6 +1256,11 @@ typedef double mp_float_t; #define MICROPY_PY_MICROPYTHON_HEAP_LOCKED (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EVERYTHING) #endif +// Whether to provide "micropython.memmove" and "micropython.memset" functions +#ifndef MICROPY_ENABLE_MEM_FUNCTIONS +#define MICROPY_ENABLE_MEM_FUNCTIONS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_BASIC_FEATURES) +#endif + // Whether to provide "array" module. Note that large chunk of the // underlying code is shared with "bytearray" builtin type, so to // get real savings, it should be disabled too. diff --git a/tests/internal_bench/set_bytearray-1-naive.py b/tests/internal_bench/set_bytearray-1-naive.py new file mode 100644 index 0000000000000..3f29330e24232 --- /dev/null +++ b/tests/internal_bench/set_bytearray-1-naive.py @@ -0,0 +1,14 @@ +import bench + + +def test(num): + buf = bytearray(16) + c = b"U"[0] + i = 0 + while i < 20000000: + for n in range(len(buf)): + buf[n] = c + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/set_bytearray-2-naive-while.py b/tests/internal_bench/set_bytearray-2-naive-while.py new file mode 100644 index 0000000000000..dae0b61291c98 --- /dev/null +++ b/tests/internal_bench/set_bytearray-2-naive-while.py @@ -0,0 +1,16 @@ +import bench + + +def test(num): + buf = bytearray(16) + c = b"U"[0] + i = 0 + while i < 20000000: + n = 0 # compared to -1-naive.py, eliminate the for loop + while n < 16: + buf[n] = c + n += 1 + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/set_bytearray-3-copy_bytes.py b/tests/internal_bench/set_bytearray-3-copy_bytes.py new file mode 100644 index 0000000000000..c65b94055266a --- /dev/null +++ b/tests/internal_bench/set_bytearray-3-copy_bytes.py @@ -0,0 +1,12 @@ +import bench + + +def test(num): + buf = bytearray(16) + i = 0 + while i < 20000000: + buf[:] = b"UUUUUUUUUUUUUUUU" + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/set_bytearray-4-memset.py b/tests/internal_bench/set_bytearray-4-memset.py new file mode 100644 index 0000000000000..b904f140b2920 --- /dev/null +++ b/tests/internal_bench/set_bytearray-4-memset.py @@ -0,0 +1,15 @@ +import bench + +from micropython import memset + + +def test(num): + buf = bytearray(16) + c = b"U"[0] + i = 0 + while i < 20000000: + memset(buf, 0, c) + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/slice_copy-1-lvalue_start.py b/tests/internal_bench/slice_copy-1-lvalue_start.py new file mode 100644 index 0000000000000..c90482df3c553 --- /dev/null +++ b/tests/internal_bench/slice_copy-1-lvalue_start.py @@ -0,0 +1,14 @@ +import bench + + +def test(num): + buf = bytearray(16) + a = b"\x00\x01\x02\x03\x04\x05\x06\x07" + i = 0 + while i < 20000000: + # slice only the starting index of lvalue + buf[8:] = a + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/slice_copy-2-lvalue_start_end.py b/tests/internal_bench/slice_copy-2-lvalue_start_end.py new file mode 100644 index 0000000000000..277e9cd6e5377 --- /dev/null +++ b/tests/internal_bench/slice_copy-2-lvalue_start_end.py @@ -0,0 +1,14 @@ +import bench + + +def test(num): + buf = bytearray(16) + a = b"\x00\x01\x02\x03\x04\x05\x06\x07" + i = 0 + while i < 20000000: + # slice the starting index and length of lvalue + buf[8:16] = a + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/slice_copy-3-lvalue_rvalue_start.py b/tests/internal_bench/slice_copy-3-lvalue_rvalue_start.py new file mode 100644 index 0000000000000..22d9b32048d80 --- /dev/null +++ b/tests/internal_bench/slice_copy-3-lvalue_rvalue_start.py @@ -0,0 +1,14 @@ +import bench + + +def test(num): + buf = bytearray(16) + a = b"\x00\x01\x02\x03\x04\x05\x06\x07" + i = 0 + while i < 20000000: + # slice the starting index of lvalue and rvalue + buf[8:] = a[0:] + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/slice_copy-4-lvalue_memoryview.py b/tests/internal_bench/slice_copy-4-lvalue_memoryview.py new file mode 100644 index 0000000000000..b12175086c9e3 --- /dev/null +++ b/tests/internal_bench/slice_copy-4-lvalue_memoryview.py @@ -0,0 +1,14 @@ +import bench + + +def test(num): + buf = memoryview(bytearray(16)) + a = b"\x00\x01\x02\x03\x04\x05\x06\x07" + i = 0 + while i < 20000000: + # slice the memoryview lvalue + buf[8:] = a + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/slice_copy-5-lvalue_rvalue_memoryview.py b/tests/internal_bench/slice_copy-5-lvalue_rvalue_memoryview.py new file mode 100644 index 0000000000000..99b12e235c721 --- /dev/null +++ b/tests/internal_bench/slice_copy-5-lvalue_rvalue_memoryview.py @@ -0,0 +1,14 @@ +import bench + + +def test(num): + buf = memoryview(bytearray(16)) + a = memoryview(b"\x00\x01\x02\x03\x04\x05\x06\x07") + i = 0 + while i < 20000000: + # slice both the lvalue & rvalue memoryviews + buf[8:] = a[0:] + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/slice_copy-6-memmove.py b/tests/internal_bench/slice_copy-6-memmove.py new file mode 100644 index 0000000000000..0127840939d0e --- /dev/null +++ b/tests/internal_bench/slice_copy-6-memmove.py @@ -0,0 +1,15 @@ +import bench + +from micropython import memmove + + +def test(num): + buf = bytearray(16) + a = b"\x00\x01\x02\x03\x04\x05\x06\x07" + i = 0 + while i < 20000000: + memmove(buf, 8, a, 0) # implicit 'len' + i += 1 + + +bench.run(test) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy