]> granicus.if.org Git - icinga2/blob - lib/base/array-script.cpp
lib->compat->statusdatawriter: fix notifications_enabled
[icinga2] / lib / base / array-script.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/)  *
4  *                                                                            *
5  * This program is free software; you can redistribute it and/or              *
6  * modify it under the terms of the GNU General Public License                *
7  * as published by the Free Software Foundation; either version 2             *
8  * of the License, or (at your option) any later version.                     *
9  *                                                                            *
10  * This program is distributed in the hope that it will be useful,            *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
13  * GNU General Public License for more details.                               *
14  *                                                                            *
15  * You should have received a copy of the GNU General Public License          *
16  * along with this program; if not, write to the Free Software Foundation     *
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
18  ******************************************************************************/
19
20 #include "base/array.hpp"
21 #include "base/function.hpp"
22 #include "base/functionwrapper.hpp"
23 #include "base/scriptframe.hpp"
24 #include "base/objectlock.hpp"
25 #include "base/exception.hpp"
26
27 using namespace icinga;
28
29 static double ArrayLen()
30 {
31         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
32         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
33         REQUIRE_NOT_NULL(self);
34         return self->GetLength();
35 }
36
37 static void ArraySet(int index, const Value& value)
38 {
39         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
40         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
41         REQUIRE_NOT_NULL(self);
42         self->Set(index, value);
43 }
44
45 static Value ArrayGet(int index)
46 {
47         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
48         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
49         REQUIRE_NOT_NULL(self);
50         return self->Get(index);
51 }
52
53 static void ArrayAdd(const Value& value)
54 {
55         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
56         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
57         REQUIRE_NOT_NULL(self);
58         self->Add(value);
59 }
60
61 static void ArrayRemove(int index)
62 {
63         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
64         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
65         REQUIRE_NOT_NULL(self);
66         self->Remove(index);
67 }
68
69 static bool ArrayContains(const Value& value)
70 {
71         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
72         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
73         REQUIRE_NOT_NULL(self);
74         return self->Contains(value);
75 }
76
77 static void ArrayClear()
78 {
79         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
80         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
81         REQUIRE_NOT_NULL(self);
82         self->Clear();
83 }
84
85 static bool ArraySortCmp(const Function::Ptr& cmp, const Value& a, const Value& b)
86 {
87         return cmp->Invoke({ a, b });
88 }
89
90 static Array::Ptr ArraySort(const std::vector<Value>& args)
91 {
92         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
93         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
94         REQUIRE_NOT_NULL(self);
95
96         Array::Ptr arr = self->ShallowClone();
97
98         if (args.empty()) {
99                 ObjectLock olock(arr);
100                 std::sort(arr->Begin(), arr->End());
101         } else {
102                 Function::Ptr function = args[0];
103
104                 if (vframe->Sandboxed && !function->IsSideEffectFree())
105                         BOOST_THROW_EXCEPTION(ScriptError("Sort function must be side-effect free."));
106
107                 ObjectLock olock(arr);
108                 std::sort(arr->Begin(), arr->End(), std::bind(ArraySortCmp, args[0], _1, _2));
109         }
110
111         return arr;
112 }
113
114 static Array::Ptr ArrayShallowClone()
115 {
116         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
117         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
118         REQUIRE_NOT_NULL(self);
119         return self->ShallowClone();
120 }
121
122 static Value ArrayJoin(const Value& separator)
123 {
124         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
125         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
126         REQUIRE_NOT_NULL(self);
127
128         Value result;
129         bool first = true;
130
131         ObjectLock olock(self);
132         for (const Value& item : self) {
133                 if (first) {
134                         first = false;
135                 } else {
136                         result = result + separator;
137                 }
138
139                 result = result + item;
140         }
141
142         return result;
143 }
144
145 static Array::Ptr ArrayReverse()
146 {
147         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
148         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
149         REQUIRE_NOT_NULL(self);
150         return self->Reverse();
151 }
152
153 static Array::Ptr ArrayMap(const Function::Ptr& function)
154 {
155         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
156         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
157         REQUIRE_NOT_NULL(self);
158
159         if (vframe->Sandboxed && !function->IsSideEffectFree())
160                 BOOST_THROW_EXCEPTION(ScriptError("Map function must be side-effect free."));
161
162         ArrayData result;
163
164         ObjectLock olock(self);
165         for (const Value& item : self) {
166                 result.push_back(function->Invoke({ item }));
167         }
168
169         return new Array(std::move(result));
170 }
171
172 static Value ArrayReduce(const Function::Ptr& function)
173 {
174         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
175         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
176         REQUIRE_NOT_NULL(self);
177
178         if (vframe->Sandboxed && !function->IsSideEffectFree())
179                 BOOST_THROW_EXCEPTION(ScriptError("Reduce function must be side-effect free."));
180
181         if (self->GetLength() == 0)
182                 return Empty;
183
184         Value result = self->Get(0);
185
186         ObjectLock olock(self);
187         for (size_t i = 1; i < self->GetLength(); i++) {
188                 result = function->Invoke({ result, self->Get(i) });
189         }
190
191         return result;
192 }
193
194 static Array::Ptr ArrayFilter(const Function::Ptr& function)
195 {
196         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
197         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
198         REQUIRE_NOT_NULL(self);
199
200         if (vframe->Sandboxed && !function->IsSideEffectFree())
201                 BOOST_THROW_EXCEPTION(ScriptError("Filter function must be side-effect free."));
202
203         ArrayData result;
204
205         ObjectLock olock(self);
206         for (const Value& item : self) {
207                 if (function->Invoke({ item }))
208                         result.push_back(item);
209         }
210
211         return new Array(std::move(result));
212 }
213
214 static bool ArrayAny(const Function::Ptr& function)
215 {
216         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
217         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
218         REQUIRE_NOT_NULL(self);
219
220         if (vframe->Sandboxed && !function->IsSideEffectFree())
221                 BOOST_THROW_EXCEPTION(ScriptError("Filter function must be side-effect free."));
222
223         ObjectLock olock(self);
224         for (const Value& item : self) {
225                 if (function->Invoke({ item }))
226                         return true;
227         }
228
229         return false;
230 }
231
232 static bool ArrayAll(const Function::Ptr& function)
233 {
234         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
235         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
236         REQUIRE_NOT_NULL(self);
237
238         if (vframe->Sandboxed && !function->IsSideEffectFree())
239                 BOOST_THROW_EXCEPTION(ScriptError("Filter function must be side-effect free."));
240
241         ObjectLock olock(self);
242         for (const Value& item : self) {
243                 if (!function->Invoke({ item }))
244                         return false;
245         }
246
247         return true;
248 }
249 static Array::Ptr ArrayUnique()
250 {
251         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
252         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
253         REQUIRE_NOT_NULL(self);
254         return self->Unique();
255 }
256
257 static void ArrayFreeze()
258 {
259         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
260         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
261         self->Freeze();
262 }
263
264 Object::Ptr Array::GetPrototype()
265 {
266         static Dictionary::Ptr prototype = new Dictionary({
267                 { "len", new Function("Array#len", ArrayLen, {}, true) },
268                 { "set", new Function("Array#set", ArraySet, { "index", "value" }) },
269                 { "get", new Function("Array#get", ArrayGet, { "index" }) },
270                 { "add", new Function("Array#add", ArrayAdd, { "value" }) },
271                 { "remove", new Function("Array#remove", ArrayRemove, { "index" }) },
272                 { "contains", new Function("Array#contains", ArrayContains, { "value" }, true) },
273                 { "clear", new Function("Array#clear", ArrayClear) },
274                 { "sort", new Function("Array#sort", ArraySort, { "less_cmp" }, true) },
275                 { "shallow_clone", new Function("Array#shallow_clone", ArrayShallowClone, {}, true) },
276                 { "join", new Function("Array#join", ArrayJoin, { "separator" }, true) },
277                 { "reverse", new Function("Array#reverse", ArrayReverse, {}, true) },
278                 { "map", new Function("Array#map", ArrayMap, { "func" }, true) },
279                 { "reduce", new Function("Array#reduce", ArrayReduce, { "reduce" }, true) },
280                 { "filter", new Function("Array#filter", ArrayFilter, { "func" }, true) },
281                 { "any", new Function("Array#any", ArrayAny, { "func" }, true) },
282                 { "all", new Function("Array#all", ArrayAll, { "func" }, true) },
283                 { "unique", new Function("Array#unique", ArrayUnique, {}, true) },
284                 { "freeze", new Function("Array#freeze", ArrayFreeze, {}) }
285         });
286
287         return prototype;
288 }