[icinga-checkins] icinga.org: icinga2/master: Add map/ reduce and filter functionality for the Array class

git at icinga.org git at icinga.org
Fri Jul 29 10:48:17 CEST 2016


Module: icinga2
Branch: master
Commit: a3815e4efde57f4cfba8c8aa9446c0b498de30d9
URL:    https://git.icinga.org/?p=icinga2.git;a=commit;h=a3815e4efde57f4cfba8c8aa9446c0b498de30d9

Author: Gunnar Beutner <gunnar.beutner at netways.de>
Date:   Fri Jul 29 10:47:13 2016 +0200

Add map/reduce and filter functionality for the Array class

fixes #12247

---

 doc/19-library-reference.md |   37 ++++++++++++++++++
 lib/base/array-script.cpp   |   90 +++++++++++++++++++++++++++++++++++++++++++
 lib/base/array.hpp          |    9 +++++
 3 files changed, 136 insertions(+)

diff --git a/doc/19-library-reference.md b/doc/19-library-reference.md
index 3d1f136..99664fb 100644
--- a/doc/19-library-reference.md
+++ b/doc/19-library-reference.md
@@ -692,6 +692,43 @@ Signature:
 
 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
 
 Inherits methods from the [Object type](19-library-reference.md#object-type).
diff --git a/lib/base/array-script.cpp b/lib/base/array-script.cpp
index c8e4731..c048231 100644
--- a/lib/base/array-script.cpp
+++ b/lib/base/array-script.cpp
@@ -22,6 +22,7 @@
 #include "base/functionwrapper.hpp"
 #include "base/scriptframe.hpp"
 #include "base/objectlock.hpp"
+#include "base/exception.hpp"
 #include <boost/foreach.hpp>
 
 using namespace icinga;
@@ -94,6 +95,11 @@ static Array::Ptr ArraySort(const std::vector<Value>& args)
 		ObjectLock olock(arr);
 		std::sort(arr->Begin(), arr->End());
 	} 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);
 		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();
 }
 
+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)
 {
 	static Dictionary::Ptr prototype;
@@ -154,6 +240,10 @@ Object::Ptr Array::GetPrototype(void)
 		prototype->Set("shallow_clone", new Function(WrapFunction(ArrayShallowClone), true));
 		prototype->Set("join", new Function(WrapFunction(ArrayJoin), 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;
diff --git a/lib/base/array.hpp b/lib/base/array.hpp
index 5981ab0..0d50be8 100644
--- a/lib/base/array.hpp
+++ b/lib/base/array.hpp
@@ -118,6 +118,15 @@ public:
 		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;
 
 	Array::Ptr Reverse(void) const;



More information about the icinga-checkins mailing list