Set key to value, creating the key if it does not already exist. * If 'update' is not NULL, *update is set to 1 if the key was * already preset, otherwise to 0. */
| 213 | * If 'update' is not NULL, *update is set to 1 if the key was |
| 214 | * already preset, otherwise to 0. */ |
| 215 | unsigned char *zipmapSet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char *val, unsigned int vlen, int *update) { |
| 216 | unsigned int zmlen, offset; |
| 217 | unsigned int freelen, reqlen = zipmapRequiredLength(klen,vlen); |
| 218 | unsigned int empty, vempty; |
| 219 | unsigned char *p; |
| 220 | |
| 221 | freelen = reqlen; |
| 222 | if (update) *update = 0; |
| 223 | p = zipmapLookupRaw(zm,key,klen,&zmlen); |
| 224 | if (p == NULL) { |
| 225 | /* Key not found: enlarge */ |
| 226 | zm = zipmapResize(zm, zmlen+reqlen); |
| 227 | p = zm+zmlen-1; |
| 228 | zmlen = zmlen+reqlen; |
| 229 | |
| 230 | /* Increase zipmap length (this is an insert) */ |
| 231 | if (zm[0] < ZIPMAP_BIGLEN) zm[0]++; |
| 232 | } else { |
| 233 | /* Key found. Is there enough space for the new value? */ |
| 234 | /* Compute the total length: */ |
| 235 | if (update) *update = 1; |
| 236 | freelen = zipmapRawEntryLength(p); |
| 237 | if (freelen < reqlen) { |
| 238 | /* Store the offset of this key within the current zipmap, so |
| 239 | * it can be resized. Then, move the tail backwards so this |
| 240 | * pair fits at the current position. */ |
| 241 | offset = p-zm; |
| 242 | zm = zipmapResize(zm, zmlen-freelen+reqlen); |
| 243 | p = zm+offset; |
| 244 | |
| 245 | /* The +1 in the number of bytes to be moved is caused by the |
| 246 | * end-of-zipmap byte. Note: the *original* zmlen is used. */ |
| 247 | memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1)); |
| 248 | zmlen = zmlen-freelen+reqlen; |
| 249 | freelen = reqlen; |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | /* We now have a suitable block where the key/value entry can |
| 254 | * be written. If there is too much free space, move the tail |
| 255 | * of the zipmap a few bytes to the front and shrink the zipmap, |
| 256 | * as we want zipmaps to be very space efficient. */ |
| 257 | empty = freelen-reqlen; |
| 258 | if (empty >= ZIPMAP_VALUE_MAX_FREE) { |
| 259 | /* First, move the tail <empty> bytes to the front, then resize |
| 260 | * the zipmap to be <empty> bytes smaller. */ |
| 261 | offset = p-zm; |
| 262 | memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1)); |
| 263 | zmlen -= empty; |
| 264 | zm = zipmapResize(zm, zmlen); |
| 265 | p = zm+offset; |
| 266 | vempty = 0; |
| 267 | } else { |
| 268 | vempty = empty; |
| 269 | } |
| 270 | |
| 271 | /* Just write the key + value and we are done. */ |
| 272 | /* Key: */ |
no test coverage detected