Browse Source

Allow additional parameters in array.map()/array.apply() handler

Sometimes it is needed to process array when result depends not
on item value only, but also from its position or collection content.
So make array.map() and array.apply() functions more flexible by
supporting optional additional parameters in callback: item index
and reference to array being processed.
(The design is like in https://underscorejs.org/#map)
VasiliyRyabtsev 7 years ago
parent
commit
8e5b1e70d0
2 changed files with 24 additions and 3 deletions
  1. 3 2
      doc/source/reference/language/builtin_functions.rst
  2. 21 1
      squirrel/sqbaselib.cpp

+ 3 - 2
doc/source/reference/language/builtin_functions.rst

@@ -412,12 +412,13 @@ returns the string "(array : pointer)".
 removes all the items from the array
 removes all the items from the array
 
 
 
 
-.. js:function:: array.map(func(a))
+.. js:function:: array.map(func(item_value, [item_index], [array_ref]))
 
 
 Creates a new array of the same size. For each element in the original array invokes the function 'func' and assigns the return value of the function to the corresponding element of the newly created array.
 Creates a new array of the same size. For each element in the original array invokes the function 'func' and assigns the return value of the function to the corresponding element of the newly created array.
+Provided func can accept up to 3 arguments: array item value (required), array item index (optional), reference to array itself (optional).
 
 
 
 
-.. js:function:: array.apply(func(a))
+.. js:function:: array.apply(func([item_value, [item_index], [array_ref]))
 
 
 for each element in the array invokes the function 'func' and replace the original value of the element with the return value of the function.
 for each element in the array invokes the function 'func' and replace the original value of the element with the return value of the function.
 
 

+ 21 - 1
squirrel/sqbaselib.cpp

@@ -596,16 +596,36 @@ static SQInteger array_resize(HSQUIRRELVM v)
 static SQInteger __map_array(SQArray *dest,SQArray *src,HSQUIRRELVM v) {
 static SQInteger __map_array(SQArray *dest,SQArray *src,HSQUIRRELVM v) {
     SQObjectPtr temp;
     SQObjectPtr temp;
     SQInteger size = src->Size();
     SQInteger size = src->Size();
+    SQObject &closure = stack_get(v, 2);
+    v->Push(closure);
+
+    SQInteger nArgs;
+    if(sq_type(closure) == OT_CLOSURE) {
+        nArgs = _closure(closure)->_function->_nparameters;
+    }
+    else if (sq_type(closure) == OT_NATIVECLOSURE) {
+        SQInteger nParamsCheck = _nativeclosure(closure)->_nparamscheck;
+        if (nParamsCheck > 0)
+            nArgs = nParamsCheck;
+        else // push all params when there is no check or only minimal count set
+            nArgs = 4;
+    }
+
     for(SQInteger n = 0; n < size; n++) {
     for(SQInteger n = 0; n < size; n++) {
         src->Get(n,temp);
         src->Get(n,temp);
         v->Push(src);
         v->Push(src);
         v->Push(temp);
         v->Push(temp);
-        if(SQ_FAILED(sq_call(v,2,SQTrue,SQFalse))) {
+        if (nArgs >= 3)
+            v->Push(SQObjectPtr(n));
+        if (nArgs >= 4)
+            v->Push(src);
+        if(SQ_FAILED(sq_call(v,nArgs,SQTrue,SQFalse))) {
             return SQ_ERROR;
             return SQ_ERROR;
         }
         }
         dest->Set(n,v->GetUp(-1));
         dest->Set(n,v->GetUp(-1));
         v->Pop();
         v->Pop();
     }
     }
+    v->Pop();
     return 0;
     return 0;
 }
 }