From 3aa8ee7c9e2e9fd50ffb4b588518bd84b40fef84 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 9 Apr 2014 00:25:28 +0300 Subject: [PATCH 1/2] py: Add mp_get_buffer(), mp_get_buffer_raise() convenience functions to API. --- py/obj.c | 18 ++++++++++++++++++ py/obj.h | 2 ++ unix/modsocket.c | 21 +++------------------ 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/py/obj.c b/py/obj.c index 8d5467c5e7..d1db53690f 100644 --- a/py/obj.c +++ b/py/obj.c @@ -330,3 +330,21 @@ mp_obj_t mp_identity(mp_obj_t self) { return self; } MP_DEFINE_CONST_FUN_OBJ_1(mp_identity_obj, mp_identity); + +bool mp_get_buffer(mp_obj_t obj, buffer_info_t *bufinfo) { + mp_obj_base_t *o = (mp_obj_base_t *)obj; + if (o->type->buffer_p.get_buffer == NULL) { + return false; + } + o->type->buffer_p.get_buffer(o, bufinfo, BUFFER_READ); + if (bufinfo->buf == NULL) { + return false; + } + return true; +} + +void mp_get_buffer_raise(mp_obj_t obj, buffer_info_t *bufinfo) { + if (!mp_get_buffer(obj, bufinfo)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "Object with buffer protocol required")); + } +} diff --git a/py/obj.h b/py/obj.h index 92dd6a8a0b..ab1685d4d0 100644 --- a/py/obj.h +++ b/py/obj.h @@ -196,6 +196,8 @@ typedef struct _buffer_info_t { typedef struct _mp_buffer_p_t { machine_int_t (*get_buffer)(mp_obj_t obj, buffer_info_t *bufinfo, int flags); } mp_buffer_p_t; +bool mp_get_buffer(mp_obj_t obj, buffer_info_t *bufinfo); +void mp_get_buffer_raise(mp_obj_t obj, buffer_info_t *bufinfo); // Stream protocol typedef struct _mp_stream_p_t { diff --git a/unix/modsocket.c b/unix/modsocket.c index 62f10300f8..8f47a8b157 100644 --- a/unix/modsocket.c +++ b/unix/modsocket.c @@ -34,21 +34,6 @@ STATIC const mp_obj_type_t microsocket_type; { if (err_flag == -1) \ { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error_val)); } } -STATIC void get_buffer(mp_obj_t obj, buffer_info_t *bufinfo) { - mp_obj_base_t *o = (mp_obj_base_t *)obj; - if (o->type->buffer_p.get_buffer == NULL) { - goto error; - } - o->type->buffer_p.get_buffer(o, bufinfo, BUFFER_READ); - if (bufinfo->buf == NULL) { - goto error; - } - return; - -error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "Operation not supported")); -} - STATIC mp_obj_socket_t *socket_new(int fd) { mp_obj_socket_t *o = m_new_obj(mp_obj_socket_t); o->base.type = µsocket_type; @@ -96,7 +81,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_fileno_obj, socket_fileno); STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { mp_obj_socket_t *self = self_in; buffer_info_t bufinfo; - get_buffer(addr_in, &bufinfo); + mp_get_buffer_raise(addr_in, &bufinfo); int r = connect(self->fd, (const struct sockaddr *)bufinfo.buf, bufinfo.len); RAISE_ERRNO(r, errno); return mp_const_none; @@ -106,7 +91,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { mp_obj_socket_t *self = self_in; buffer_info_t bufinfo; - get_buffer(addr_in, &bufinfo); + mp_get_buffer_raise(addr_in, &bufinfo); int r = bind(self->fd, (const struct sockaddr *)bufinfo.buf, bufinfo.len); RAISE_ERRNO(r, errno); return mp_const_none; @@ -184,7 +169,7 @@ STATIC mp_obj_t socket_setsockopt(uint n_args, const mp_obj_t *args) { optlen = sizeof(val); } else { buffer_info_t bufinfo; - get_buffer(args[3], &bufinfo); + mp_get_buffer_raise(args[3], &bufinfo); optval = bufinfo.buf; optlen = bufinfo.len; } From a985b4593d3f0c788c5e6ef0066bf82ae550cfb8 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 9 Apr 2014 00:40:58 +0300 Subject: [PATCH 2/2] objint: Implement int.from_bytes() class method and .to_bytes() method. These two are apprerently the most concise and efficient way to convert int to/from bytes in Python. The alternatives are struct and array modules, but methods using them are more verbose in Python code and less efficient in memory/cycles. --- py/objint.c | 38 ++++++++++++++++++++++++++++++++++++++ py/qstrdefs.h | 2 ++ tests/basics/int-bytes.py | 6 ++++++ 3 files changed, 46 insertions(+) create mode 100644 tests/basics/int-bytes.py diff --git a/py/objint.c b/py/objint.c index e1b67a16b3..05269ce379 100644 --- a/py/objint.c +++ b/py/objint.c @@ -261,6 +261,43 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_ return MP_OBJ_NULL; } +STATIC mp_obj_t int_from_bytes(uint n_args, const mp_obj_t *args) { + buffer_info_t bufinfo; + mp_get_buffer_raise(args[0], &bufinfo); + + assert(bufinfo.len >= sizeof(machine_int_t)); + // TODO: Support long ints + // TODO: Support byteorder param + // TODO: Support signed param + return mp_obj_new_int_from_uint(*(machine_uint_t*)bufinfo.buf); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_obj, 1, 3, int_from_bytes); + +STATIC mp_obj_t int_to_bytes(uint n_args, const mp_obj_t *args) { + machine_int_t val = mp_obj_int_get_checked(args[0]); + + uint len = MP_OBJ_SMALL_INT_VALUE(args[1]); + byte *data; + + // TODO: Support long ints + // TODO: Support byteorder param + // TODO: Support signed param + mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, len, &data); + memset(data, 0, len); + memcpy(data, &val, len < sizeof(machine_int_t) ? len : sizeof(machine_int_t)); + return mp_obj_str_builder_end(o); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_to_bytes_obj, 2, 4, int_to_bytes); + +STATIC const mp_map_elem_t int_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_from_bytes), (mp_obj_t)&int_from_bytes_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_to_bytes), (mp_obj_t)&int_to_bytes_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(int_locals_dict, int_locals_dict_table); + const mp_obj_type_t mp_type_int = { { &mp_type_type }, .name = MP_QSTR_int, @@ -268,4 +305,5 @@ const mp_obj_type_t mp_type_int = { .make_new = mp_obj_int_make_new, .unary_op = mp_obj_int_unary_op, .binary_op = mp_obj_int_binary_op, + .locals_dict = (mp_obj_t)&int_locals_dict, }; diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 29eb51d0ba..0c2c032f29 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -96,6 +96,7 @@ Q(eval) Q(exec) Q(filter) Q(float) +Q(from_bytes) Q(getattr) Q(globals) Q(hash) @@ -127,6 +128,7 @@ Q(sum) Q(super) Q(str) Q(sys) +Q(to_bytes) Q(tuple) Q(type) Q(value) diff --git a/tests/basics/int-bytes.py b/tests/basics/int-bytes.py new file mode 100644 index 0000000000..45965ed464 --- /dev/null +++ b/tests/basics/int-bytes.py @@ -0,0 +1,6 @@ +print((10).to_bytes(1, "little")) +print((111111).to_bytes(4, "little")) +print((100).to_bytes(10, "little")) +print(int.from_bytes(b"\x00\x01\0\0\0\0\0\0", "little")) +print(int.from_bytes(b"\x01\0\0\0\0\0\0\0", "little")) +print(int.from_bytes(b"\x00\x01\0\0\0\0\0\0", "little"))