From 4c896cd8bc7c46c1c851dcb520bd60a375bf2873 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Tue, 1 Nov 2022 23:07:15 +0100 Subject: [PATCH] Added Berry ``bytes().reverse()`` method --- CHANGELOG.md | 1 + lib/libesp32/berry/src/be_byteslib.c | 69 ++++++++++++++++++++++++++-- lib/libesp32/berry/tests/bytes.be | 23 ++++++++++ 3 files changed, 89 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f93336f0..2e4175b87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. - Support for Digital Addressable Lighting Interface (DALI) by Andrei Kazmirtsuk (#16938) - Support for two phase power calibration using commands ``PowerSet2``, ``VoltageSet2`` and ``CurrentSet2`` - Support for NTAG2xx tags read and write on PN532 NFC reader (#16939) +- Added Berry ``bytes().reverse()`` method ### Breaking Changed diff --git a/lib/libesp32/berry/src/be_byteslib.c b/lib/libesp32/berry/src/be_byteslib.c index b2dc9856a..6fcd457db 100644 --- a/lib/libesp32/berry/src/be_byteslib.c +++ b/lib/libesp32/berry/src/be_byteslib.c @@ -957,7 +957,6 @@ static int m_setfloat(bvm *vm) * `setbytes(index:int, fill:bytes [, from:int, len:int]) -> nil` * */ -#include static int m_setbytes(bvm *vm) { int argc = be_top(vm); @@ -968,7 +967,7 @@ static int m_setbytes(bvm *vm) size_t from_len_total; const uint8_t* buf_ptr = (const uint8_t*) be_tobytes(vm, 3, &from_len_total); if (idx < 0) { idx = 0; } - if ((size_t)idx >= attr.len) { idx = attr.len; } + if (idx >= attr.len) { idx = attr.len; } int32_t from_byte = 0; if (argc >= 4 && be_isint(vm, 4)) { @@ -981,9 +980,9 @@ static int m_setbytes(bvm *vm) if (argc >= 5 && be_isint(vm, 5)) { from_len = be_toint(vm, 5); if (from_len < 0) { from_len = 0; } - if (from_len >= from_len_total) { from_len = from_len_total; } + if (from_len >= (int32_t)from_len_total) { from_len = from_len_total; } } - if ((size_t) idx + (size_t)from_len >= attr.len) { from_len = attr.len - idx; } + if (idx + from_len >= attr.len) { from_len = attr.len - idx; } // all parameters ok if (from_len > 0) { @@ -993,6 +992,66 @@ static int m_setbytes(bvm *vm) be_return_nil(vm); } + +/* + * Reverses in-place a sub-buffer composed of groups of n-bytes packets + * + * This is useful for pixel manipulation when displaying RGB pixels + * + * `reverse([index:int, len:int, grouplen:int]) -> self` + * + */ +static int m_reverse(bvm *vm) +{ + int argc = be_top(vm); + buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */ + check_ptr(vm, &attr); + + int32_t idx = 0; /* start from index 0 */ + int32_t len = attr.len; /* entire len */ + int32_t grouplen = 1; /* default to 1-byte group */ + + if (argc >= 2 && be_isint(vm, 2)) { + idx = be_toint(vm, 2); + if (idx < 0) { idx = 0; } /* railguards */ + if (idx > attr.len) { idx = attr.len; } + } + if (argc >= 3 && be_isint(vm, 3)) { + len = be_toint(vm, 3); + if (len < 0) { len = attr.len - idx; } /* negative len means */ + } + if (idx + len >= attr.len) { len = attr.len - idx; } + + // truncate len to multiple of grouplen + if (argc >= 4 && be_isint(vm, 4)) { + grouplen = be_toint(vm, 4); + if (grouplen <= 0) { grouplen = 1; } + } + len = len - (len % grouplen); + + // apply reverse + if (len > 0) { + if (grouplen == 1) { + /* fast version if simple byte inversion */ + for (int32_t i = idx, j = idx + len -1; i < j; i++, j--) { + uint8_t temp = attr.bufptr[i]; + attr.bufptr[i] = attr.bufptr[j]; + attr.bufptr[j] = temp; + } + } else { + for (int32_t i = idx, j = idx + len - grouplen; i < j; i += grouplen, j -= grouplen) { + for (int32_t k = 0; k < grouplen; k++) { + uint8_t temp = attr.bufptr[i+k]; + attr.bufptr[i+k] = attr.bufptr[j+k]; + attr.bufptr[j+k] = temp; + } + } + } + } + be_pushvalue(vm, 1); /* push bytes object */ + be_return(vm); +} + static int m_setitem(bvm *vm) { int argc = be_top(vm); @@ -1627,6 +1686,7 @@ void be_load_byteslib(bvm *vm) { "size", m_size }, { "resize", m_resize }, { "clear", m_clear }, + { "reverse", m_reverse }, { "copy", m_copy }, { "+", m_merge }, { "..", m_connect }, @@ -1672,6 +1732,7 @@ class be_class_bytes (scope: global, name: bytes) { size, func(m_size) resize, func(m_resize) clear, func(m_clear) + reverse, func(m_reverse) copy, func(m_copy) +, func(m_merge) .., func(m_connect) diff --git a/lib/libesp32/berry/tests/bytes.be b/lib/libesp32/berry/tests/bytes.be index 44d3f56aa..d2b2c1573 100644 --- a/lib/libesp32/berry/tests/bytes.be +++ b/lib/libesp32/berry/tests/bytes.be @@ -225,3 +225,26 @@ assert(a == bytes('112233445566CCDD99')) a = b.copy() a.setbytes(0, a0) assert(a == bytes('112233445566')) + +# reverse +assert(bytes().reverse() == bytes()) +assert(bytes("AA").reverse() == bytes("AA")) +assert(bytes("1122334455").reverse() == bytes("5544332211")) +assert(bytes("11223344").reverse() == bytes("44332211")) + +assert(bytes("0011223344").reverse(1) == bytes("0044332211")) +assert(bytes("0011223344").reverse(3) == bytes("0011224433")) +assert(bytes("0011223344").reverse(4) == bytes("0011223344")) +assert(bytes("0011223344").reverse(5) == bytes("0011223344")) +assert(bytes("0011223344").reverse(15) == bytes("0011223344")) +assert(bytes("0011223344").reverse(-2) == bytes("4433221100")) + +assert(bytes("0011223344").reverse(1,3) == bytes("0033221144")) +assert(bytes("0011223344").reverse(1,0) == bytes("0011223344")) +assert(bytes("0011223344").reverse(2,2) == bytes("0011332244")) +assert(bytes("0011223344").reverse(0,2) == bytes("1100223344")) +assert(bytes("0011223344").reverse(nil,2) == bytes("1100223344")) +assert(bytes("0011223344").reverse(1, nil) == bytes("0044332211")) + +assert(bytes("0011223344").reverse(nil, nil, 2) == bytes("2233001144")) +assert(bytes("001122334455").reverse(nil, nil, 3) == bytes("334455001122"))