Add map/reduce and filter functionality for the Array class

fixes #12247
This commit is contained in:
Gunnar Beutner 2016-07-29 10:47:13 +02:00
parent 0d02b01c02
commit a3815e4efd
3 changed files with 136 additions and 0 deletions

View File

@ -692,6 +692,43 @@ Signature:
Returns a new array with all elements of the current array in reverse order. Returns a new array with all elements of the current array in reverse order.
### <a id="array-map"></a> Array#map
Signature:
function map(func);
Calls `func(element)` for each of the elements in the array and returns
a new array containing the return values of these function calls.
### <a id="array-reduce"></a> Array#reduce
Signature:
function reduce(func);
Reduces the elements of the array into a single value by calling the provided
function `func` as `func(a, b)` repeatedly where `a` is the previous result of
function call (null initially) and `b` is an element of the array.
### <a id="array-filter"> Array#filter
Signature:
function filter(func);
Returns a copy of the array containing only the elements for which `func(element)`
is true.
### <a id="array-filter"> Array#unique
Signature:
function unique();
Returns a copy of the array with all duplicate elements removed. The original order
of the array is not preserved.
## <a id="dictionary-type"></a> Dictionary type ## <a id="dictionary-type"></a> Dictionary type
Inherits methods from the [Object type](19-library-reference.md#object-type). Inherits methods from the [Object type](19-library-reference.md#object-type).

View File

@ -22,6 +22,7 @@
#include "base/functionwrapper.hpp" #include "base/functionwrapper.hpp"
#include "base/scriptframe.hpp" #include "base/scriptframe.hpp"
#include "base/objectlock.hpp" #include "base/objectlock.hpp"
#include "base/exception.hpp"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
using namespace icinga; using namespace icinga;
@ -94,6 +95,11 @@ static Array::Ptr ArraySort(const std::vector<Value>& args)
ObjectLock olock(arr); ObjectLock olock(arr);
std::sort(arr->Begin(), arr->End()); std::sort(arr->Begin(), arr->End());
} else { } else {
Function::Ptr function = args[0];
if (vframe->Sandboxed && !function->IsSideEffectFree())
BOOST_THROW_EXCEPTION(ScriptError("Sort function must be side-effect free."));
ObjectLock olock(arr); ObjectLock olock(arr);
std::sort(arr->Begin(), arr->End(), boost::bind(ArraySortCmp, args[0], _1, _2)); std::sort(arr->Begin(), arr->End(), boost::bind(ArraySortCmp, args[0], _1, _2));
} }
@ -137,6 +143,86 @@ static Array::Ptr ArrayReverse(void)
return self->Reverse(); return self->Reverse();
} }
static Array::Ptr ArrayMap(const Function::Ptr& function)
{
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
if (vframe->Sandboxed && !function->IsSideEffectFree())
BOOST_THROW_EXCEPTION(ScriptError("Map function must be side-effect free."));
Array::Ptr result = new Array();
ObjectLock olock(self);
BOOST_FOREACH(const Value& item, self) {
ScriptFrame uframe;
std::vector<Value> args;
args.push_back(item);
result->Add(function->Invoke(args));
}
return result;
}
static Value ArrayReduce(const Function::Ptr& function)
{
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
if (vframe->Sandboxed && !function->IsSideEffectFree())
BOOST_THROW_EXCEPTION(ScriptError("Reduce function must be side-effect free."));
Value result;
ObjectLock olock(self);
BOOST_FOREACH(const Value& item, self) {
ScriptFrame uframe;
std::vector<Value> args;
args.push_back(result);
args.push_back(item);
result = function->Invoke(args);
}
return result;
}
static Array::Ptr ArrayFilter(const Function::Ptr& function)
{
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
if (vframe->Sandboxed && !function->IsSideEffectFree())
BOOST_THROW_EXCEPTION(ScriptError("Filter function must be side-effect free."));
Array::Ptr result = new Array();
ObjectLock olock(self);
BOOST_FOREACH(const Value& item, self) {
ScriptFrame uframe;
std::vector<Value> args;
args.push_back(item);
if (function->Invoke(args))
result->Add(item);
}
return result;
}
static Array::Ptr ArrayUnique(void)
{
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
std::set<Value> result;
ObjectLock olock(self);
BOOST_FOREACH(const Value& item, self) {
result.insert(item);
}
return Array::FromSet(result);
}
Object::Ptr Array::GetPrototype(void) Object::Ptr Array::GetPrototype(void)
{ {
static Dictionary::Ptr prototype; static Dictionary::Ptr prototype;
@ -154,6 +240,10 @@ Object::Ptr Array::GetPrototype(void)
prototype->Set("shallow_clone", new Function(WrapFunction(ArrayShallowClone), true)); prototype->Set("shallow_clone", new Function(WrapFunction(ArrayShallowClone), true));
prototype->Set("join", new Function(WrapFunction(ArrayJoin), true)); prototype->Set("join", new Function(WrapFunction(ArrayJoin), true));
prototype->Set("reverse", new Function(WrapFunction(ArrayReverse), true)); prototype->Set("reverse", new Function(WrapFunction(ArrayReverse), true));
prototype->Set("map", new Function(WrapFunction(ArrayMap), true));
prototype->Set("reduce", new Function(WrapFunction(ArrayReduce), true));
prototype->Set("filter", new Function(WrapFunction(ArrayFilter), true));
prototype->Set("unique", new Function(WrapFunction(ArrayUnique), true));
} }
return prototype; return prototype;

View File

@ -118,6 +118,15 @@ public:
return std::set<T>(Begin(), End()); return std::set<T>(Begin(), End());
} }
template<typename T>
static Array::Ptr FromSet(const std::set<T>& v)
{
Array::Ptr result = new Array();
ObjectLock olock(result);
std::copy(v.begin(), v.end(), std::back_inserter(result->m_Data));
return result;
}
virtual Object::Ptr Clone(void) const override; virtual Object::Ptr Clone(void) const override;
Array::Ptr Reverse(void) const; Array::Ptr Reverse(void) const;