diff --git a/src/be_byteslib.c b/src/be_byteslib.c index 2cc9253..beab914 100644 --- a/src/be_byteslib.c +++ b/src/be_byteslib.c @@ -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; } @@ -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); @@ -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); @@ -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; @@ -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); @@ -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); @@ -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; @@ -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; } } @@ -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); } } diff --git a/tests/bytes.be b/tests/bytes.be index e91f422..1f58118 100644 --- a/tests/bytes.be +++ b/tests/bytes.be @@ -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('')") @@ -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) @@ -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") @@ -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 @@ -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") @@ -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() @@ -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 -# @@ -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"))