1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
3 #include "base/array.hpp"
4 #include "base/function.hpp"
5 #include "base/functionwrapper.hpp"
6 #include "base/scriptframe.hpp"
7 #include "base/objectlock.hpp"
8 #include "base/exception.hpp"
10 using namespace icinga;
12 static double ArrayLen()
14 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
15 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
16 REQUIRE_NOT_NULL(self);
17 return self->GetLength();
20 static void ArraySet(int index, const Value& value)
22 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
23 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
24 REQUIRE_NOT_NULL(self);
25 self->Set(index, value);
28 static Value ArrayGet(int index)
30 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
31 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
32 REQUIRE_NOT_NULL(self);
33 return self->Get(index);
36 static void ArrayAdd(const Value& value)
38 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
39 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
40 REQUIRE_NOT_NULL(self);
44 static void ArrayRemove(int index)
46 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
47 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
48 REQUIRE_NOT_NULL(self);
52 static bool ArrayContains(const Value& value)
54 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
55 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
56 REQUIRE_NOT_NULL(self);
57 return self->Contains(value);
60 static void ArrayClear()
62 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
63 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
64 REQUIRE_NOT_NULL(self);
68 static bool ArraySortCmp(const Function::Ptr& cmp, const Value& a, const Value& b)
70 return cmp->Invoke({ a, b });
73 static Array::Ptr ArraySort(const std::vector<Value>& args)
75 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
76 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
77 REQUIRE_NOT_NULL(self);
79 Array::Ptr arr = self->ShallowClone();
82 ObjectLock olock(arr);
83 std::sort(arr->Begin(), arr->End());
85 Function::Ptr function = args[0];
87 if (vframe->Sandboxed && !function->IsSideEffectFree())
88 BOOST_THROW_EXCEPTION(ScriptError("Sort function must be side-effect free."));
90 ObjectLock olock(arr);
91 std::sort(arr->Begin(), arr->End(), std::bind(ArraySortCmp, args[0], _1, _2));
97 static Array::Ptr ArrayShallowClone()
99 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
100 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
101 REQUIRE_NOT_NULL(self);
102 return self->ShallowClone();
105 static Value ArrayJoin(const Value& separator)
107 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
108 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
109 REQUIRE_NOT_NULL(self);
114 ObjectLock olock(self);
115 for (const Value& item : self) {
119 result = result + separator;
122 result = result + item;
128 static Array::Ptr ArrayReverse()
130 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
131 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
132 REQUIRE_NOT_NULL(self);
133 return self->Reverse();
136 static Array::Ptr ArrayMap(const Function::Ptr& function)
138 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
139 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
140 REQUIRE_NOT_NULL(self);
142 if (vframe->Sandboxed && !function->IsSideEffectFree())
143 BOOST_THROW_EXCEPTION(ScriptError("Map function must be side-effect free."));
147 ObjectLock olock(self);
148 for (const Value& item : self) {
149 result.push_back(function->Invoke({ item }));
152 return new Array(std::move(result));
155 static Value ArrayReduce(const Function::Ptr& function)
157 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
158 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
159 REQUIRE_NOT_NULL(self);
161 if (vframe->Sandboxed && !function->IsSideEffectFree())
162 BOOST_THROW_EXCEPTION(ScriptError("Reduce function must be side-effect free."));
164 if (self->GetLength() == 0)
167 Value result = self->Get(0);
169 ObjectLock olock(self);
170 for (size_t i = 1; i < self->GetLength(); i++) {
171 result = function->Invoke({ result, self->Get(i) });
177 static Array::Ptr ArrayFilter(const Function::Ptr& function)
179 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
180 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
181 REQUIRE_NOT_NULL(self);
183 if (vframe->Sandboxed && !function->IsSideEffectFree())
184 BOOST_THROW_EXCEPTION(ScriptError("Filter function must be side-effect free."));
188 ObjectLock olock(self);
189 for (const Value& item : self) {
190 if (function->Invoke({ item }))
191 result.push_back(item);
194 return new Array(std::move(result));
197 static bool ArrayAny(const Function::Ptr& function)
199 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
200 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
201 REQUIRE_NOT_NULL(self);
203 if (vframe->Sandboxed && !function->IsSideEffectFree())
204 BOOST_THROW_EXCEPTION(ScriptError("Filter function must be side-effect free."));
206 ObjectLock olock(self);
207 for (const Value& item : self) {
208 if (function->Invoke({ item }))
215 static bool ArrayAll(const Function::Ptr& function)
217 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
218 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
219 REQUIRE_NOT_NULL(self);
221 if (vframe->Sandboxed && !function->IsSideEffectFree())
222 BOOST_THROW_EXCEPTION(ScriptError("Filter function must be side-effect free."));
224 ObjectLock olock(self);
225 for (const Value& item : self) {
226 if (!function->Invoke({ item }))
232 static Array::Ptr ArrayUnique()
234 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
235 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
236 REQUIRE_NOT_NULL(self);
237 return self->Unique();
240 static void ArrayFreeze()
242 ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
243 Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
247 Object::Ptr Array::GetPrototype()
249 static Dictionary::Ptr prototype = new Dictionary({
250 { "len", new Function("Array#len", ArrayLen, {}, true) },
251 { "set", new Function("Array#set", ArraySet, { "index", "value" }) },
252 { "get", new Function("Array#get", ArrayGet, { "index" }) },
253 { "add", new Function("Array#add", ArrayAdd, { "value" }) },
254 { "remove", new Function("Array#remove", ArrayRemove, { "index" }) },
255 { "contains", new Function("Array#contains", ArrayContains, { "value" }, true) },
256 { "clear", new Function("Array#clear", ArrayClear) },
257 { "sort", new Function("Array#sort", ArraySort, { "less_cmp" }, true) },
258 { "shallow_clone", new Function("Array#shallow_clone", ArrayShallowClone, {}, true) },
259 { "join", new Function("Array#join", ArrayJoin, { "separator" }, true) },
260 { "reverse", new Function("Array#reverse", ArrayReverse, {}, true) },
261 { "map", new Function("Array#map", ArrayMap, { "func" }, true) },
262 { "reduce", new Function("Array#reduce", ArrayReduce, { "reduce" }, true) },
263 { "filter", new Function("Array#filter", ArrayFilter, { "func" }, true) },
264 { "any", new Function("Array#any", ArrayAny, { "func" }, true) },
265 { "all", new Function("Array#all", ArrayAll, { "func" }, true) },
266 { "unique", new Function("Array#unique", ArrayUnique, {}, true) },
267 { "freeze", new Function("Array#freeze", ArrayFreeze, {}) }