]> git.kaiwu.me - quickjs.git/commitdiff
added Map and WeakMap upsert methods (bnoordhuis)
authorFabrice Bellard <fabrice@bellard.org>
Sat, 27 Sep 2025 08:24:48 +0000 (10:24 +0200)
committerFabrice Bellard <fabrice@bellard.org>
Sat, 27 Sep 2025 08:24:48 +0000 (10:24 +0200)
TODO
quickjs.c
test262.conf

diff --git a/TODO b/TODO
index 8f7dc8b634debf95ec9f3fc0af5518f4db501a06..33f0ab575e02b26adf3595c25f974492f1e8cc09 100644 (file)
--- a/TODO
+++ b/TODO
@@ -62,5 +62,5 @@ Optimization ideas:
 Test262o:   0/11262 errors, 463 excluded
 Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
 
-Result: 48/81760 errors, 1631 excluded, 5564 skipped
+Result: 48/81914 errors, 1631 excluded, 5486 skipped
 Test262 commit: e7e136756cd67c1ffcf7c09d03aeb8ad5a6cec0c
index 752ff91ae50e159a5b5b1b55980491f466499db8..db54f3b865068121d24a3e4498845a6a1cb6077b 100644 (file)
--- a/quickjs.c
+++ b/quickjs.c
@@ -49759,20 +49759,6 @@ static JSValue js_map_get(JSContext *ctx, JSValueConst this_val,
         return JS_DupValue(ctx, mr->value);
 }
 
-static JSValue js_map_has(JSContext *ctx, JSValueConst this_val,
-                          int argc, JSValueConst *argv, int magic)
-{
-    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
-    JSMapRecord *mr;
-    JSValueConst key;
-
-    if (!s)
-        return JS_EXCEPTION;
-    key = map_normalize_key_const(ctx, argv[0]);
-    mr = map_find_record(ctx, s, key);
-    return JS_NewBool(ctx, mr != NULL);
-}
-
 /* return JS_TRUE or JS_FALSE */
 static JSValue map_delete_record(JSContext *ctx, JSMapState *s, JSValueConst key)
 {
@@ -49803,6 +49789,57 @@ static JSValue map_delete_record(JSContext *ctx, JSMapState *s, JSValueConst key
     return JS_TRUE;
 }
 
+static JSValue js_map_getOrInsert(JSContext *ctx, JSValueConst this_val,
+                                  int argc, JSValueConst *argv, int magic)
+{
+    BOOL computed = magic & 1;
+    JSClassID class_id = magic >> 1;
+    JSMapState *s = JS_GetOpaque2(ctx, this_val, class_id);
+    JSMapRecord *mr;
+    JSValueConst key;
+    JSValue value;
+
+    if (!s)
+        return JS_EXCEPTION;
+    if (computed && !JS_IsFunction(ctx, argv[1]))
+        return JS_ThrowTypeError(ctx, "not a function");
+    key = map_normalize_key_const(ctx, argv[0]);
+    if (s->is_weak && !js_weakref_is_target(key))
+        return JS_ThrowTypeError(ctx, "invalid value used as WeakMap key");
+    mr = map_find_record(ctx, s, key);
+    if (!mr) {
+        if (computed) {
+            value = JS_Call(ctx, argv[1], JS_UNDEFINED, 1, &key);
+            if (JS_IsException(value))
+                return JS_EXCEPTION;
+            map_delete_record(ctx, s, key);
+        } else {
+            value = JS_DupValue(ctx, argv[1]);
+        }
+        mr = map_add_record(ctx, s, key);
+        if (!mr) {
+            JS_FreeValue(ctx, value);
+            return JS_EXCEPTION;
+        }
+        mr->value = value;
+    }
+    return JS_DupValue(ctx, mr->value);
+}
+
+static JSValue js_map_has(JSContext *ctx, JSValueConst this_val,
+                          int argc, JSValueConst *argv, int magic)
+{
+    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
+    JSMapRecord *mr;
+    JSValueConst key;
+
+    if (!s)
+        return JS_EXCEPTION;
+    key = map_normalize_key_const(ctx, argv[0]);
+    mr = map_find_record(ctx, s, key);
+    return JS_NewBool(ctx, mr != NULL);
+}
+
 static JSValue js_map_delete(JSContext *ctx, JSValueConst this_val,
                              int argc, JSValueConst *argv, int magic)
 {
@@ -50749,6 +50786,10 @@ static const JSCFunctionListEntry js_map_funcs[] = {
 static const JSCFunctionListEntry js_map_proto_funcs[] = {
     JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, 0 ),
     JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, 0 ),
+    JS_CFUNC_MAGIC_DEF("getOrInsert", 2, js_map_getOrInsert,
+                       (JS_CLASS_MAP << 1) | /*computed*/FALSE ),
+    JS_CFUNC_MAGIC_DEF("getOrInsertComputed", 2, js_map_getOrInsert,
+                       (JS_CLASS_MAP << 1) | /*computed*/TRUE ),
     JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, 0 ),
     JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, 0 ),
     JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, 0 ),
@@ -50795,6 +50836,10 @@ static const JSCFunctionListEntry js_set_iterator_proto_funcs[] = {
 static const JSCFunctionListEntry js_weak_map_proto_funcs[] = {
     JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, MAGIC_WEAK ),
     JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, MAGIC_WEAK ),
+    JS_CFUNC_MAGIC_DEF("getOrInsert", 2, js_map_getOrInsert,
+                       (JS_CLASS_WEAKMAP << 1) | /*computed*/FALSE ),
+    JS_CFUNC_MAGIC_DEF("getOrInsertComputed", 2, js_map_getOrInsert,
+                       (JS_CLASS_WEAKMAP << 1) | /*computed*/TRUE ),
     JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_WEAK ),
     JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_WEAK ),
     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakMap", JS_PROP_CONFIGURABLE ),
index 52291c5ac7d709e011856caede515cf7c31a729d..7300f426297d7e513b20f7b8611028e595477ca3 100644 (file)
@@ -228,7 +228,7 @@ Uint32Array
 Uint8Array
 uint8array-base64=skip
 Uint8ClampedArray
-upsert=skip
+upsert
 WeakMap
 WeakRef
 WeakSet