]> granicus.if.org Git - icinga2/blob - lib/base/array-script.cpp
Merge pull request #7185 from Icinga/bugfix/gelfwriter-wrong-log-facility
[icinga2] / lib / base / array-script.cpp
1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
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"
9
10 using namespace icinga;
11
12 static double ArrayLen()
13 {
14         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
15         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
16         REQUIRE_NOT_NULL(self);
17         return self->GetLength();
18 }
19
20 static void ArraySet(int index, const Value& value)
21 {
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);
26 }
27
28 static Value ArrayGet(int index)
29 {
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);
34 }
35
36 static void ArrayAdd(const Value& value)
37 {
38         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
39         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
40         REQUIRE_NOT_NULL(self);
41         self->Add(value);
42 }
43
44 static void ArrayRemove(int index)
45 {
46         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
47         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
48         REQUIRE_NOT_NULL(self);
49         self->Remove(index);
50 }
51
52 static bool ArrayContains(const Value& value)
53 {
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);
58 }
59
60 static void ArrayClear()
61 {
62         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
63         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
64         REQUIRE_NOT_NULL(self);
65         self->Clear();
66 }
67
68 static bool ArraySortCmp(const Function::Ptr& cmp, const Value& a, const Value& b)
69 {
70         return cmp->Invoke({ a, b });
71 }
72
73 static Array::Ptr ArraySort(const std::vector<Value>& args)
74 {
75         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
76         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
77         REQUIRE_NOT_NULL(self);
78
79         Array::Ptr arr = self->ShallowClone();
80
81         if (args.empty()) {
82                 ObjectLock olock(arr);
83                 std::sort(arr->Begin(), arr->End());
84         } else {
85                 Function::Ptr function = args[0];
86
87                 if (vframe->Sandboxed && !function->IsSideEffectFree())
88                         BOOST_THROW_EXCEPTION(ScriptError("Sort function must be side-effect free."));
89
90                 ObjectLock olock(arr);
91                 std::sort(arr->Begin(), arr->End(), std::bind(ArraySortCmp, args[0], _1, _2));
92         }
93
94         return arr;
95 }
96
97 static Array::Ptr ArrayShallowClone()
98 {
99         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
100         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
101         REQUIRE_NOT_NULL(self);
102         return self->ShallowClone();
103 }
104
105 static Value ArrayJoin(const Value& separator)
106 {
107         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
108         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
109         REQUIRE_NOT_NULL(self);
110
111         Value result;
112         bool first = true;
113
114         ObjectLock olock(self);
115         for (const Value& item : self) {
116                 if (first) {
117                         first = false;
118                 } else {
119                         result = result + separator;
120                 }
121
122                 result = result + item;
123         }
124
125         return result;
126 }
127
128 static Array::Ptr ArrayReverse()
129 {
130         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
131         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
132         REQUIRE_NOT_NULL(self);
133         return self->Reverse();
134 }
135
136 static Array::Ptr ArrayMap(const Function::Ptr& function)
137 {
138         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
139         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
140         REQUIRE_NOT_NULL(self);
141
142         if (vframe->Sandboxed && !function->IsSideEffectFree())
143                 BOOST_THROW_EXCEPTION(ScriptError("Map function must be side-effect free."));
144
145         ArrayData result;
146
147         ObjectLock olock(self);
148         for (const Value& item : self) {
149                 result.push_back(function->Invoke({ item }));
150         }
151
152         return new Array(std::move(result));
153 }
154
155 static Value ArrayReduce(const Function::Ptr& function)
156 {
157         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
158         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
159         REQUIRE_NOT_NULL(self);
160
161         if (vframe->Sandboxed && !function->IsSideEffectFree())
162                 BOOST_THROW_EXCEPTION(ScriptError("Reduce function must be side-effect free."));
163
164         if (self->GetLength() == 0)
165                 return Empty;
166
167         Value result = self->Get(0);
168
169         ObjectLock olock(self);
170         for (size_t i = 1; i < self->GetLength(); i++) {
171                 result = function->Invoke({ result, self->Get(i) });
172         }
173
174         return result;
175 }
176
177 static Array::Ptr ArrayFilter(const Function::Ptr& function)
178 {
179         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
180         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
181         REQUIRE_NOT_NULL(self);
182
183         if (vframe->Sandboxed && !function->IsSideEffectFree())
184                 BOOST_THROW_EXCEPTION(ScriptError("Filter function must be side-effect free."));
185
186         ArrayData result;
187
188         ObjectLock olock(self);
189         for (const Value& item : self) {
190                 if (function->Invoke({ item }))
191                         result.push_back(item);
192         }
193
194         return new Array(std::move(result));
195 }
196
197 static bool ArrayAny(const Function::Ptr& function)
198 {
199         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
200         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
201         REQUIRE_NOT_NULL(self);
202
203         if (vframe->Sandboxed && !function->IsSideEffectFree())
204                 BOOST_THROW_EXCEPTION(ScriptError("Filter function must be side-effect free."));
205
206         ObjectLock olock(self);
207         for (const Value& item : self) {
208                 if (function->Invoke({ item }))
209                         return true;
210         }
211
212         return false;
213 }
214
215 static bool ArrayAll(const Function::Ptr& function)
216 {
217         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
218         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
219         REQUIRE_NOT_NULL(self);
220
221         if (vframe->Sandboxed && !function->IsSideEffectFree())
222                 BOOST_THROW_EXCEPTION(ScriptError("Filter function must be side-effect free."));
223
224         ObjectLock olock(self);
225         for (const Value& item : self) {
226                 if (!function->Invoke({ item }))
227                         return false;
228         }
229
230         return true;
231 }
232 static Array::Ptr ArrayUnique()
233 {
234         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
235         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
236         REQUIRE_NOT_NULL(self);
237         return self->Unique();
238 }
239
240 static void ArrayFreeze()
241 {
242         ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
243         Array::Ptr self = static_cast<Array::Ptr>(vframe->Self);
244         self->Freeze();
245 }
246
247 Object::Ptr Array::GetPrototype()
248 {
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, {}) }
268         });
269
270         return prototype;
271 }