SDB_API int sdb_array_set(Sdb *s, const char *key, int idx, const char *val, ut32 cas) { int lstr, lval, len; const char *usr, *str = sdb_const_get_len (s, key, &lstr, 0); char *ptr; if (!str || !*str) { return sdb_set (s, key, val, cas); } // XXX: should we cache sdb_alen value inside kv? len = sdb_alen (str); lstr--; if (idx < 0 || idx == len) { // append return sdb_array_insert (s, key, -1, val, cas); } lval = strlen (val); if (idx > len) { int ret, i, ilen = idx-len; char *newkey = malloc (ilen + lval + 1); if (!newkey) { return 0; } for (i = 0; i < ilen; i++) { newkey [i] = SDB_RS; } memcpy (newkey + i, val, lval + 1); ret = sdb_array_insert (s, key, -1, newkey, cas); free (newkey); return ret; } //lstr = strlen (str); ptr = (char*)Aindexof (str, idx); if (ptr) { int diff = ptr - str; char *nstr = malloc (lstr + lval + 2); if (!nstr) { return false; } ptr = nstr + diff; //memcpy (nstr, str, lstr+1); memcpy (nstr, str, diff); memcpy (ptr, val, lval + 1); usr = Aindexof (str, idx + 1); if (usr) { ptr[lval] = SDB_RS; strcpy (ptr + lval + 1, usr); } return sdb_set_owned (s, key, nstr, 0); } return 0; }
// TODO: done, but there's room for improvement SDB_API int sdb_array_insert(Sdb *s, const char *key, int idx, const char *val, ut32 cas) { int lnstr, lstr, lval; char *x, *ptr; const char *str = sdb_const_get_len (s, key, &lstr, 0); if (!str || !*str) { return sdb_set (s, key, val, cas); } lval = strlen (val); lstr--; //lstr = strlen (str); // we can optimize this by caching value len in memory . add sdb_const_get_size() x = malloc (lval + lstr + 2); if (idx == -1) { memcpy (x, str, lstr); x[lstr] = SDB_RS; memcpy (x+lstr+1, val, lval + 1); } else if (idx == 0) { memcpy (x, val, lval); x[lval] = SDB_RS; memcpy (x + lval + 1, str, lstr + 1); } else { char *nstr = malloc (lstr + 1); if (!nstr) { free (x); return false; } memcpy (nstr, str, lstr + 1); ptr = (char *)Aindexof (nstr, idx); if (ptr) { int lptr = (nstr+lstr+1)-ptr; *(ptr-1) = 0; lnstr = ptr-nstr-1; memcpy (x, nstr, lnstr); x[lnstr] = SDB_RS; memcpy (x + lnstr + 1, val, lval); x[lnstr + lval + 1] = SDB_RS; // TODO: this strlen hurts performance memcpy (x + lval + 2 + lnstr, ptr, lptr); //strlen (ptr)+1); free (nstr); } else { // this is not efficient free (nstr); free (x); // fallback for empty buckets return sdb_array_set (s, key, idx, val, cas); } } return sdb_set_owned (s, key, x, cas); }
// TODO: done, but there's room for improvement SDB_API int sdb_array_insert(Sdb *s, const char *key, int idx, const char *val, ut32 cas) { int lnstr, lstr; size_t lval; char *x, *ptr; const char *str = sdb_const_get_len (s, key, &lstr, 0); if (!str || !*str) { return sdb_set (s, key, val, cas); } lval = strlen (val); lstr--; // XXX: lstr is wrongly computed in sdb_const_get_with an off-by-one // we can optimize this by caching value len in memory . add // sdb_const_get_size() lstr = strlen (str); // When removing strlen this conversion should be checked size_t lstr_tmp = lstr; if (SZT_ADD_OVFCHK (lval, lstr_tmp) || SZT_ADD_OVFCHK (lval + lstr_tmp, 2)) { return false; } x = malloc (lval + lstr_tmp + 2); if (!x) { return false; } if (idx == -1) { memcpy (x, str, lstr); x[lstr] = SDB_RS; memcpy (x + lstr + 1, val, lval + 1); } else if (!idx) { memcpy (x, val, lval); x[lval] = SDB_RS; memcpy (x + lval + 1, str, lstr + 1); } else { char *nstr = malloc (lstr + 1); if (!nstr) { free (x); return false; } memcpy (nstr, str, lstr + 1); ptr = (char *)Aindexof (nstr, idx); if (ptr) { int lptr = (nstr + lstr + 1) - ptr; char *p_1 = ptr > nstr? ptr - 1: ptr; *p_1 = 0; lnstr = ptr - nstr - 1; memcpy (x, nstr, lnstr); x[lnstr] = SDB_RS; memcpy (x + lnstr + 1, val, lval); x[lnstr + lval + 1] = SDB_RS; // TODO: this strlen hurts performance memcpy (x + lval + 2 + lnstr, ptr, lptr); //strlen (ptr)+1); free (nstr); } else { // this is not efficient free (nstr); free (x); // fallback for empty buckets return sdb_array_set (s, key, idx, val, cas); } } return sdb_set_owned (s, key, x, cas); }