MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add upsert

+151 -2
+2 -2
examples/results.txt
··· 1489 1489 compat-table/next/AsyncIterator.prototype.take.js: failed 1490 1490 compat-table/next/AsyncIterator.prototype.toArray.js: TIMEOUT: >5s 1491 1491 compat-table/next/DisposableStack.js: ReferenceError: 'DisposableStack' is not defined 1492 - compat-table/next/Map.prototype.upsert.js: TypeError: undefined is not a function 1492 + compat-table/next/Map.prototype.upsert.js: OK 1493 1493 compat-table/next/RegExp.1-9.js: OK 1494 1494 compat-table/next/RegExp.lastMatch.js: OK 1495 1495 compat-table/next/ShadowRealm.js: failed ··· 1501 1501 compat-table/next/Uint8Array.setFromHex.js: TypeError: undefined is not a function 1502 1502 compat-table/next/Uint8Array.toBase64.js: TypeError: undefined is not a function 1503 1503 compat-table/next/Uint8Array.toHex.js: TypeError: undefined is not a function 1504 - compat-table/next/WeakMap.prototype.upsert.js: TypeError: undefined is not a function 1504 + compat-table/next/WeakMap.prototype.upsert.js: OK 1505 1505 compat-table/next/await-using.for-of.js: ReferenceError: 'using' is not defined 1506 1506 compat-table/next/await-using.js: ReferenceError: 'using' is not defined 1507 1507 compat-table/next/class-decorators.js: failed
+92
src/modules/collections.c
··· 383 383 return js_bool(entry != NULL); 384 384 } 385 385 386 + static ant_value_t map_upsert(ant_t *js, ant_value_t *args, int nargs) { 387 + if (nargs < 3) return js_mkerr(js, "Map.upsert() requires 3 arguments"); 388 + 389 + ant_value_t this_val = js->this_val; 390 + map_entry_t **map_ptr = get_map_from_obj(this_val); 391 + if (!map_ptr) return js_mkerr(js, "Invalid Map object"); 392 + 393 + ant_value_t update_fn = args[1]; 394 + ant_value_t insert_fn = args[2]; 395 + if (!is_callable(update_fn)) 396 + return js_mkerr_typed(js, JS_ERR_TYPE, "Map.upsert update callback must be callable"); 397 + if (!is_callable(insert_fn)) 398 + return js_mkerr_typed(js, JS_ERR_TYPE, "Map.upsert insert callback must be callable"); 399 + 400 + map_entry_t *entry = map_find_entry(js, map_ptr, args[0]); 401 + ant_value_t value; 402 + 403 + if (entry) { 404 + ant_value_t call_args[3] = { entry->value, args[0], this_val }; 405 + value = sv_vm_call(js->vm, js, update_fn, js_mkundef(), call_args, 3, NULL, false); 406 + } else { 407 + ant_value_t call_args[2] = { args[0], this_val }; 408 + value = sv_vm_call(js->vm, js, insert_fn, js_mkundef(), call_args, 2, NULL, false); 409 + } 410 + 411 + if (is_err(value)) return value; 412 + 413 + ant_value_t key_val = normalize_map_key(args[0]); 414 + if (!map_store_entry(js, map_ptr, args[0], key_val, value)) 415 + return js_mkerr(js, "out of memory"); 416 + 417 + ant_object_t *map_obj = js_obj_ptr(this_val); 418 + if (map_obj) { 419 + gc_write_barrier(js, map_obj, key_val); 420 + gc_write_barrier(js, map_obj, value); 421 + } 422 + 423 + return value; 424 + } 425 + 386 426 static ant_value_t map_delete(ant_t *js, ant_value_t *args, int nargs) { 387 427 if (nargs < 1) return js_mkerr(js, "Map.delete() requires 1 argument"); 388 428 ··· 1107 1147 return js_bool(entry != NULL); 1108 1148 } 1109 1149 1150 + static ant_value_t weakmap_upsert(ant_t *js, ant_value_t *args, int nargs) { 1151 + if (nargs < 3) return js_mkerr(js, "WeakMap.upsert() requires 3 arguments"); 1152 + 1153 + ant_value_t this_val = js->this_val; 1154 + weakmap_entry_t **wm_ptr = get_weakmap_from_obj(this_val); 1155 + if (!wm_ptr) return js_mkerr(js, "Invalid WeakMap object"); 1156 + 1157 + if (!is_object_type(args[0])) 1158 + return js_mkerr(js, "WeakMap key must be an object"); 1159 + 1160 + ant_value_t update_fn = args[1]; 1161 + ant_value_t insert_fn = args[2]; 1162 + if (!is_callable(update_fn)) 1163 + return js_mkerr_typed(js, JS_ERR_TYPE, "WeakMap.upsert update callback must be callable"); 1164 + if (!is_callable(insert_fn)) 1165 + return js_mkerr_typed(js, JS_ERR_TYPE, "WeakMap.upsert insert callback must be callable"); 1166 + 1167 + ant_value_t key_obj = args[0]; 1168 + weakmap_entry_t *entry; 1169 + HASH_FIND(hh, *wm_ptr, &key_obj, sizeof(ant_value_t), entry); 1170 + 1171 + ant_value_t value; 1172 + if (entry) { 1173 + ant_value_t call_args[3] = { entry->value, key_obj, this_val }; 1174 + value = sv_vm_call(js->vm, js, update_fn, js_mkundef(), call_args, 3, NULL, false); 1175 + } else { 1176 + ant_value_t call_args[2] = { key_obj, this_val }; 1177 + value = sv_vm_call(js->vm, js, insert_fn, js_mkundef(), call_args, 2, NULL, false); 1178 + } 1179 + 1180 + if (is_err(value)) return value; 1181 + 1182 + HASH_FIND(hh, *wm_ptr, &key_obj, sizeof(ant_value_t), entry); 1183 + if (entry) entry->value = value; else { 1184 + entry = ant_calloc(sizeof(weakmap_entry_t)); 1185 + if (!entry) return js_mkerr(js, "out of memory"); 1186 + entry->key_obj = key_obj; 1187 + entry->value = value; 1188 + HASH_ADD(hh, *wm_ptr, key_obj, sizeof(ant_value_t), entry); 1189 + } 1190 + 1191 + ant_object_t *wm_obj = js_obj_ptr(this_val); 1192 + if (wm_obj) { 1193 + gc_write_barrier(js, wm_obj, key_obj); 1194 + gc_write_barrier(js, wm_obj, value); 1195 + } 1196 + 1197 + return value; 1198 + } 1199 + 1110 1200 static ant_value_t weakmap_delete(ant_t *js, ant_value_t *args, int nargs) { 1111 1201 if (nargs < 1) return js_mkerr(js, "WeakMap.delete() requires 1 argument"); 1112 1202 ··· 1481 1571 js_set(js, map_proto, "set", js_mkfun(map_set)); 1482 1572 js_set(js, map_proto, "get", js_mkfun(map_get)); 1483 1573 js_set(js, map_proto, "has", js_mkfun(map_has)); 1574 + js_set(js, map_proto, "upsert", js_mkfun(map_upsert)); 1484 1575 js_set(js, map_proto, "delete", js_mkfun(map_delete)); 1485 1576 js_set(js, map_proto, "clear", js_mkfun(map_clear)); 1486 1577 js_set_getter_desc(js, map_proto, "size", 4, js_mkfun(map_size), JS_DESC_C); ··· 1534 1625 js_set(js, weakmap_proto, "set", js_mkfun(weakmap_set)); 1535 1626 js_set(js, weakmap_proto, "get", js_mkfun(weakmap_get)); 1536 1627 js_set(js, weakmap_proto, "has", js_mkfun(weakmap_has)); 1628 + js_set(js, weakmap_proto, "upsert", js_mkfun(weakmap_upsert)); 1537 1629 js_set(js, weakmap_proto, "delete", js_mkfun(weakmap_delete)); 1538 1630 js_set_sym(js, weakmap_proto, tag_sym, js_mkstr(js, "WeakMap", 7)); 1539 1631
+57
tests/test_map_upsert.cjs
··· 1 + function assert(condition, message) { 2 + if (!condition) throw new Error(message); 3 + } 4 + 5 + const map = new Map([["a", 1]]); 6 + let updateCalls = 0; 7 + let insertCalls = 0; 8 + 9 + const updated = map.upsert( 10 + "a", 11 + (value, key, receiver) => { 12 + updateCalls++; 13 + assert(value === 1, "Map update callback receives existing value"); 14 + assert(key === "a", "Map update callback receives key"); 15 + assert(receiver === map, "Map update callback receives receiver"); 16 + return 2; 17 + }, 18 + () => { 19 + insertCalls++; 20 + return 3; 21 + } 22 + ); 23 + 24 + assert(updated === 2, "Map.upsert returns updated value"); 25 + assert(map.get("a") === 2, "Map.upsert stores updated value"); 26 + assert(updateCalls === 1, "Map update callback called once"); 27 + assert(insertCalls === 0, "Map insert callback not called for existing key"); 28 + 29 + const inserted = map.upsert( 30 + "b", 31 + () => { 32 + updateCalls++; 33 + return 4; 34 + }, 35 + (key, receiver) => { 36 + insertCalls++; 37 + assert(key === "b", "Map insert callback receives key"); 38 + assert(receiver === map, "Map insert callback receives receiver"); 39 + return 3; 40 + } 41 + ); 42 + 43 + assert(inserted === 3, "Map.upsert returns inserted value"); 44 + assert(Array.from(map).join() === "a,2,b,3", "Map.upsert inserts missing key"); 45 + assert(updateCalls === 1, "Map update callback not called for missing key"); 46 + assert(insertCalls === 1, "Map insert callback called once"); 47 + 48 + const a = {}; 49 + const b = {}; 50 + const weak = new WeakMap([[a, 1]]); 51 + 52 + assert(weak.upsert(a, value => value + 1, () => 3) === 2, "WeakMap.upsert returns updated value"); 53 + assert(weak.get(a) === 2, "WeakMap.upsert stores updated value"); 54 + assert(weak.upsert(b, () => 4, () => 3) === 3, "WeakMap.upsert returns inserted value"); 55 + assert(weak.get(b) === 3, "WeakMap.upsert stores inserted value"); 56 + 57 + console.log("Map/WeakMap upsert tests completed!");