]> git.kaiwu.me - njs.git/commitdiff
Added %TypedArray% remaining methods.
authorDmitry Volyntsev <xeioex@nginx.com>
Mon, 7 Sep 2020 12:44:07 +0000 (12:44 +0000)
committerDmitry Volyntsev <xeioex@nginx.com>
Mon, 7 Sep 2020 12:44:07 +0000 (12:44 +0000)
The following methods were added: of(), from().

src/njs_typed_array.c
src/njs_value.h
src/test/njs_unit_test.c

index 73b79be58c38e9cf118a1911e612d2a788c7a15c..be73e5080a02eb5a048d54c141670e292c63d452 100644 (file)
@@ -267,6 +267,194 @@ njs_typed_array_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 }
 
 
+static njs_int_t
+njs_typed_array_create(njs_vm_t *vm, njs_value_t *constructor,
+    njs_value_t *args, njs_uint_t nargs, njs_value_t *retval)
+{
+    njs_int_t     ret;
+    njs_value_t   this;
+    njs_object_t  *object;
+
+    object = njs_function_new_object(vm, constructor);
+    if (njs_slow_path(object == NULL)) {
+        return NJS_ERROR;
+    }
+
+    njs_set_object(&this, object);
+
+    ret = njs_function_call2(vm, njs_function(constructor), &this, args,
+                             nargs, retval, 1);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NJS_ERROR;
+    }
+
+    if (njs_slow_path(!njs_is_typed_array(retval))) {
+        njs_type_error(vm, "Derived TypedArray constructor "
+                       "returned not a typed array");
+        return NJS_ERROR;
+    }
+
+    if (njs_slow_path(nargs == 1 && njs_is_number(&args[0])
+                      && njs_typed_array_length(njs_typed_array(retval))
+                         < njs_number(&args[0])))
+    {
+        njs_type_error(vm, "Derived TypedArray constructor "
+                       "returned too short array");
+        return NJS_ERROR;
+    }
+
+    return NJS_OK;
+}
+
+
+static njs_int_t
+njs_typed_array_species_create(njs_vm_t *vm, njs_value_t *exemplar,
+    njs_value_t *args, njs_uint_t nargs, njs_value_t *retval)
+{
+    njs_int_t          ret;
+    njs_value_t        constructor;
+    njs_typed_array_t  *array;
+
+    array = njs_typed_array(exemplar);
+
+    njs_set_function(&constructor, &vm->constructors[array->type]);
+
+    ret = njs_value_species_constructor(vm, exemplar, &constructor,
+                                        &constructor);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    return njs_typed_array_create(vm, &constructor, args, nargs, retval);
+}
+
+
+static njs_int_t
+njs_typed_array_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t unused)
+{
+    double             num;
+    uint32_t           length, i;
+    njs_int_t          ret;
+    njs_value_t        *this;
+    njs_value_t        argument;
+    njs_typed_array_t  *array;
+
+    this = njs_argument(args, 0);
+
+    if (njs_slow_path(!njs_is_constructor(this))) {
+        njs_type_error(vm, "%s is not a constructor",
+                       njs_type_string(this->type));
+        return NJS_ERROR;
+    }
+
+    length = nargs - 1;
+
+    njs_set_number(&argument, length);
+    ret = njs_typed_array_create(vm, this, &argument, 1, &vm->retval);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NJS_ERROR;
+    }
+
+    array = njs_typed_array(&vm->retval);
+
+    for (i = 0; i < length; i++) {
+        ret = njs_value_to_number(vm, njs_argument(args, i + 1), &num);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return NJS_ERROR;
+        }
+
+        njs_typed_array_prop_set(vm, array, i, num);
+    }
+
+    njs_set_typed_array(&vm->retval, array);
+
+    return NJS_OK;
+}
+
+
+static njs_int_t
+njs_typed_array_from(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t unused)
+{
+    double             num;
+    int64_t            length, i;
+    njs_int_t          ret;
+    njs_value_t        *this, *source, *mapfn;
+    njs_value_t        arguments[3], retval;
+    njs_function_t     *function;
+    njs_typed_array_t  *array;
+
+    this = njs_argument(args, 0);
+
+    if (njs_slow_path(!njs_is_constructor(this))) {
+        njs_type_error(vm, "%s is not a constructor",
+                       njs_type_string(this->type));
+        return NJS_ERROR;
+    }
+
+    mapfn = njs_arg(args, nargs, 2);
+
+    if (njs_slow_path(!njs_is_function_or_undefined(mapfn))) {
+        njs_type_error(vm, "\"mapfn\" argument is not callable");
+        return NJS_ERROR;
+    }
+
+    function = NULL;
+    if (njs_is_function(mapfn)) {
+        function = njs_function(mapfn);
+    }
+
+    source = njs_arg(args, nargs, 1);
+
+    ret = njs_value_to_object(vm, source);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    ret = njs_object_length(vm, source, &length);
+    if (njs_slow_path(ret == NJS_ERROR)) {
+        return ret;
+    }
+
+    njs_set_number(&arguments[0], length);
+    ret = njs_typed_array_create(vm, this, arguments, 1, &vm->retval);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NJS_ERROR;
+    }
+
+    array = njs_typed_array(&vm->retval);
+    arguments[0] = *njs_arg(args, nargs, 3);
+
+    for (i = 0; i < length; i++) {
+        ret = njs_value_property_i64(vm, source, i, &retval);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            return NJS_ERROR;
+        }
+
+        if (function != NULL) {
+            arguments[1] = retval;
+            njs_set_number(&arguments[2], i);
+            ret = njs_function_apply(vm, function, arguments, 3, &retval);
+            if (njs_slow_path(ret != NJS_OK)) {
+                return NJS_ERROR;
+            }
+        }
+
+        ret = njs_value_to_number(vm, &retval, &num);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return NJS_ERROR;
+        }
+
+        njs_typed_array_prop_set(vm, array, i, num);
+    }
+
+    njs_set_typed_array(&vm->retval, array);
+
+    return NJS_OK;
+}
+
+
 static njs_int_t
 njs_typed_array_get_this(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused)
@@ -769,57 +957,6 @@ njs_typed_array_prototype_fill(njs_vm_t *vm, njs_value_t *args,
 }
 
 
-static njs_int_t
-njs_typed_array_species_create(njs_vm_t *vm, njs_value_t *exemplar,
-    njs_value_t *args, njs_uint_t nargs, njs_value_t *retval)
-{
-    njs_int_t          ret;
-    njs_value_t        this, constructor;
-    njs_object_t       *object;
-    njs_typed_array_t  *array;
-
-    array = njs_typed_array(exemplar);
-
-    njs_set_function(&constructor, &vm->constructors[array->type]);
-
-    ret = njs_value_species_constructor(vm, exemplar, &constructor,
-                                        &constructor);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
-
-    object = njs_function_new_object(vm, &constructor);
-    if (njs_slow_path(object == NULL)) {
-        return NJS_ERROR;
-    }
-
-    njs_set_object(&this, object);
-
-    ret = njs_function_call2(vm, njs_function(&constructor), &this,
-                             args, nargs, retval, 1);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return NJS_ERROR;
-    }
-
-    if (njs_slow_path(!njs_is_typed_array(retval))) {
-        njs_type_error(vm, "Derived TypedArray constructor "
-                       "returned not a typed array");
-        return NJS_ERROR;
-    }
-
-    if (njs_slow_path(nargs == 1 && njs_is_number(&args[0])
-                      && njs_typed_array_length(njs_typed_array(retval))
-                         < njs_number(&args[0])))
-    {
-        njs_type_error(vm, "Derived TypedArray constructor "
-                       "returned too short array");
-        return NJS_ERROR;
-    }
-
-    return NJS_OK;
-}
-
-
 static njs_int_t
 njs_typed_array_prototype_slice(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t copy)
@@ -2013,6 +2150,22 @@ static const njs_object_prop_t  njs_typed_array_constructor_props[] =
         .configurable = 1,
         .enumerable = 0,
     },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("of"),
+        .value = njs_native_function(njs_typed_array_of, 0),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("from"),
+        .value = njs_native_function(njs_typed_array_from, 1),
+        .writable = 1,
+        .configurable = 1,
+    },
 };
 
 
index 4a8da81bab599bb37980e7feaaf87948946c13f3..130abb7f2ccaa47e43273c6e40083f8d375e0526 100644 (file)
@@ -676,6 +676,10 @@ typedef struct {
     ((value)->type == NJS_FUNCTION || (value)->type == NJS_UNDEFINED)
 
 
+#define njs_is_constructor(value)                                             \
+    (njs_is_function(value) && njs_function(value)->ctor)
+
+
 #define njs_is_regexp(value)                                                  \
     ((value)->type == NJS_REGEXP)
 
index 13825d2aec56d03a15ecc5e16134ae71077873d5..2475ddcd72733cb60492eac449f852f84f24c936 100644 (file)
@@ -5472,6 +5472,58 @@ static njs_unit_test_t  njs_test[] =
               ".every(v=>{var a = new v(1); return --a[0] == -1})"),
       njs_str("true") },
 
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var a = v.of(); return njs.dump(a) === `${v.name} []`})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var a = v.of(1); return njs.dump(a) === `${v.name} [1]`})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var a = v.of(1,2,3,4,5); return njs.dump(a) === `${v.name} [1,2,3,4,5]`})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ try{ v.of(Symbol()); } catch (e) { return e.name === 'TypeError'}})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ try{ v.of.call(()=>1); } catch (e) { return e.name === 'TypeError'}})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{ try{ v.of.call(function(){}); } catch (e) { return e.name === 'TypeError'}})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var a = v.from([1,2]); return njs.dump(a) === `${v.name} [1,2]`})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var a = v.from([1,2], v=>2*v); return njs.dump(a) === `${v.name} [2,4]`})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var a = v.from([1,2], function(v){return v * this.m}, {m:3}); "
+              "           return njs.dump(a) === `${v.name} [3,6]`})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var a = v.from([1,2], function(v){return v * this.m}, {m:3}); "
+              "           return njs.dump(a) === `${v.name} [3,6]`})"),
+      njs_str("true") },
+
+    { njs_str(NJS_INT_TYPED_ARRAY_LIST
+              ".every(v=>{var a = v.from({length:3, 0:1, 2:'a'});"
+              "           return njs.dump(a) === `${v.name} [1,0,0]`})"),
+      njs_str("true") },
+
+    { njs_str(NJS_FLOAT_TYPED_ARRAY_LIST
+              ".every(v=>{var a = v.from({length:3, 0:1, 2:'a'});"
+              "           return njs.dump(a) === `${v.name} [1,NaN,NaN]`})"),
+      njs_str("true") },
+
     { njs_str(NJS_TYPED_ARRAY_LIST
               ".every(v=>{var a = new v(4); a.fill(42); return (a[0] === 42 && a.length == 4)})"),
       njs_str("true") },