Skip to content

Commit

Permalink
Merge pull request #440 from s-hadinger/bytes_negative_offset
Browse files Browse the repository at this point in the history
Bytes accept negative offset
  • Loading branch information
skiars authored Aug 23, 2024
2 parents 7819c5e + e3bb100 commit d6025fc
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 31 deletions.
74 changes: 50 additions & 24 deletions src/be_byteslib.c
Original file line number Diff line number Diff line change
Expand Up @@ -867,9 +867,15 @@ static int m_get(bvm *vm, bbool sign)
if (argc >= 3 && be_isint(vm, 3)) {
vsize = be_toint(vm, 3);
}
if (idx < 0) {
idx = attr.len + idx; /* if index is negative, count from end */
}
if (idx < 0) {
vsize = 0; /* if still negative, then invalid, return 0 */
}
int ret = 0;
switch (vsize) {
case 0: break;
case 0: break;
case -1: /* fallback below */
case 1: ret = buf_get1(&attr, idx);
if (sign) { ret = (int8_t)(uint8_t) ret; }
Expand All @@ -891,11 +897,7 @@ static int m_get(bvm *vm, bbool sign)
default: be_raise(vm, "type_error", "size must be -4, -3, -2, -1, 0, 1, 2, 3 or 4.");
}
be_pop(vm, argc - 1);
if (vsize != 0) {
be_pushint(vm, ret);
} else {
be_pushnil(vm);
}
be_pushint(vm, ret);
be_return(vm);
}
be_return_nil(vm);
Expand All @@ -912,14 +914,20 @@ static int m_getfloat(bvm *vm)
check_ptr(vm, &attr);
if (argc >=2 && be_isint(vm, 2)) {
int32_t idx = be_toint(vm, 2);
bbool be = bfalse; /* little endian? */
if (argc >= 3) {
be = be_tobool(vm, 3);
float ret_f = 0;
if (idx < 0) {
idx = attr.len + idx; /* if index is negative, count from end */
}
if (idx >= 0) {
bbool be = bfalse; /* little endian? */
if (argc >= 3) {
be = be_tobool(vm, 3);
}
int32_t ret_i = be ? buf_get4_be(&attr, idx) : buf_get4_le(&attr, idx);
ret_f = *(float*) &ret_i;
}
int32_t ret_i = be ? buf_get4_be(&attr, idx) : buf_get4_le(&attr, idx);
float* ret_f = (float*) &ret_i;
be_pop(vm, argc - 1);
be_pushreal(vm, *ret_f);
be_pushreal(vm, ret_f);
be_return(vm);
}
be_return_nil(vm);
Expand Down Expand Up @@ -957,8 +965,14 @@ static int m_set(bvm *vm)
if (argc >= 4 && be_isint(vm, 4)) {
vsize = be_toint(vm, 4);
}
if (idx < 0) {
idx = attr.len + idx; /* if index is negative, count from end */
}
if (idx < 0) {
vsize = 0; /* if still negative, then invalid, do nothing */
}
switch (vsize) {
case 0: break;
case 0: break;
case -1: /* fallback below */
case 1: buf_set1(&attr, idx, value); break;
case 2: buf_set2_le(&attr, idx, value); break;
Expand All @@ -970,7 +984,7 @@ static int m_set(bvm *vm)
default: be_raise(vm, "type_error", "size must be -4, -3, -2, -1, 0, 1, 2, 3 or 4.");
}
be_pop(vm, argc - 1);
m_write_attributes(vm, 1, &attr); /* update attributes */
// m_write_attributes(vm, 1, &attr); /* update attributes */
be_return_nil(vm);
}
be_return_nil(vm);
Expand All @@ -988,15 +1002,20 @@ static int m_setfloat(bvm *vm)
check_ptr(vm, &attr);
if (argc >=3 && be_isint(vm, 2) && (be_isint(vm, 3) || be_isreal(vm, 3))) {
int32_t idx = be_toint(vm, 2);
float val_f = (float) be_toreal(vm, 3);
int32_t* val_i = (int32_t*) &val_f;
bbool be = bfalse;
if (argc >= 4) {
be = be_tobool(vm, 4);
if (idx < 0) {
idx = attr.len + idx; /* if index is negative, count from end */
}
if (idx >= 0) {
float val_f = (float) be_toreal(vm, 3);
int32_t* val_i = (int32_t*) &val_f;
bbool be = bfalse;
if (argc >= 4) {
be = be_tobool(vm, 4);
}
if (be) { buf_set4_be(&attr, idx, *val_i); } else { buf_set4_le(&attr, idx, *val_i); }
be_pop(vm, argc - 1);
// m_write_attributes(vm, 1, &attr); /* update attributes */
}
if (be) { buf_set4_be(&attr, idx, *val_i); } else { buf_set4_le(&attr, idx, *val_i); }
be_pop(vm, argc - 1);
m_write_attributes(vm, 1, &attr); /* update attributes */
be_return_nil(vm);
}
be_return_nil(vm);
Expand Down Expand Up @@ -1045,7 +1064,10 @@ static int m_setbytes(bvm *vm)
int32_t idx = be_toint(vm, 2);
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 (idx < 0) {
idx = attr.len + idx; /* if index is negative, count from end */
}
if (idx < 0) { idx = 0; } /* if still negative, start from offset 0 */
if (idx >= attr.len) { idx = attr.len; }

int32_t from_byte = 0;
Expand Down Expand Up @@ -1092,6 +1114,7 @@ static int m_reverse(bvm *vm)

if (argc >= 2 && be_isint(vm, 2)) {
idx = be_toint(vm, 2);
if (idx < 0) { idx = attr.len + idx; } /* if negative, count from end */
if (idx < 0) { idx = 0; } /* railguards */
if (idx > attr.len) { idx = attr.len; }
}
Expand Down Expand Up @@ -1139,9 +1162,12 @@ static int m_setitem(bvm *vm)
if (argc >=3 && be_isint(vm, 2) && be_isint(vm, 3)) {
int index = be_toint(vm, 2);
int val = be_toint(vm, 3);
if (index < 0) {
index += attr.len; /* if index is negative, count from end */
}
if (index >= 0 && index < attr.len) {
buf_set1(&attr, index, val);
m_write_attributes(vm, 1, &attr); /* update attributes */
// m_write_attributes(vm, 1, &attr); /* update attributes */
be_return_nil(vm);
}
}
Expand Down
43 changes: 36 additions & 7 deletions tests/bytes.be
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
def assert_error(f, error_type)
try
f()
assert(false, 'unexpected execution flow')
except .. as e, m
assert(e == error_type)
end
end

#- basic initialization -#
b=bytes()
assert(str(b) == "bytes('')")
Expand Down Expand Up @@ -48,18 +57,22 @@ assert(str(b) == "bytes('227878567856341278567812345678')")
#- get -#
b=bytes("000102030405")
assert(b.get(0) == 0)
assert(b.get(-1) == 0) #- could consider nil as well -#
assert(b.get(6) == 0) #- could consider nil as well -#
assert(b.get(-1) == 0x05) #- last byte -#
assert(b.get(6) == 0)
assert(b.get(1) == 1)
assert(b.get(5) == 5)
assert(b.get(-1000) == 0) # out of range, default to zero
assert(b.get(1000) == 0) # out of range, default to zero

assert(b.get(1,0) == nil)
assert(b.get(1,1) == 0x01)
assert(b.get(1,2) == 0x0201)
assert(b.get(1,4) == 0x04030201)
assert(b.get(1,-1) == 0x01)
assert(b.get(1,-2) == 0x0102) #- big endian -#
assert(b.get(1,-4) == 0x01020304)
assert(b.get(1,0) == 0) # size zero is invalid, returns zero
assert(b.get(-1000,1) == 0) # out of range, default to zero
assert(b.get(1000,1) == 0) # out of range, default to zero

#- resize -#
assert(bytes().size() == 0)
Expand All @@ -76,6 +89,10 @@ assert(b.size() == 20)
b.resize(0)
assert(str(b) == "bytes('')")
assert(b.size() == 0)
b=bytes("112233")
b.resize(-5) # resize negative is equivalent to resize(0)
assert(str(b) == "bytes('')")
assert(b.size() == 0)

#- clear -#
b=bytes("aabb")
Expand Down Expand Up @@ -110,7 +127,7 @@ assert(str(b) == "bytes('AA')")
b = b1 + '01'
assert(str(b) == "bytes('AA3031')")

#- .. and append as synonym-#
#- .. and append as synonyms -#
b1 = bytes("1122")
b2 = bytes("334455")
b = b1..b2
Expand Down Expand Up @@ -143,6 +160,12 @@ b = bytes("334455")
assert(b[0] == 0x33)
assert(b[1] == 0x44)
assert(b[2] == 0x55)
assert(b[-1] == 0x55)
assert(b[-2] == 0x44)
assert(b[-3] == 0x33)
# out of range raises "index_error" exceptions
assert_error(def () return b[-4] end, 'index_error')
assert_error(def () return b[4] end, 'index_error')

#- item range -#
b = bytes("00112233445566778899AABBCCDDEEFF")
Expand All @@ -169,6 +192,14 @@ b[0]=0xBB
assert(str(b) =="bytes('BBAA33')")
b[2]=-1
assert(str(b) =="bytes('BBAAFF')")
# negative indices, counting from end
b[-1]=0xFE
assert(str(b) =="bytes('BBAAFE')")
b[-3]=0xBC
assert(str(b) =="bytes('BCAAFE')")
# out of range raises "index_error" exceptions
assert_error(def () b[-4]=0x11 end, 'index_error')
assert_error(def () b[4]=0x11 end, 'index_error')

#- resize -#
b=bytes()
Expand All @@ -191,9 +222,7 @@ b.fromstring("Aa0")
assert(str(b) =="bytes('416130')")
b=bytes()
b.fromstring("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
assert(str(b) =="bytes('4C6F72656D20697073756D20646F6C6F722073697420616D65742C20636F6E73...')")
assert(b.tostring(0) =="bytes('4C6F72656D20697073756D20646F6C6F722073697420616D65742C20636F6E73656374657475722061646970697363696E6720656C69742C2073656420646F20656975736D6F642074656D706F7220696E6369646964756E74207574206C61626F726520657420646F6C6F7265206D61676E6120616C697175612E')")

assert(size(bytes('4C6F72656D20697073756D20646F6C6F722073697420616D65742C20636F6E73656374657475722061646970697363696E6720656C69742C2073656420646F20656975736D6F642074656D706F7220696E6369646964756E74207574206C61626F726520657420646F6C6F7265206D61676E6120616C697175612E')) == 123)

#- negative index -#
Expand Down Expand Up @@ -271,7 +300,7 @@ 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(-2) == bytes("0011224433")) # reverse starting 2 from end

assert(bytes("0011223344").reverse(1,3) == bytes("0033221144"))
assert(bytes("0011223344").reverse(1,0) == bytes("0011223344"))
Expand Down

0 comments on commit d6025fc

Please sign in to comment.