]> granicus.if.org Git - icinga2/blob - lib/base/array.cpp
Implement support for modifying frozen attributes
[icinga2] / lib / base / array.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/objectlock.hpp"
22 #include "base/debug.hpp"
23 #include "base/primitivetype.hpp"
24 #include "base/dictionary.hpp"
25 #include "base/configwriter.hpp"
26 #include "base/convert.hpp"
27 #include "base/exception.hpp"
28
29 using namespace icinga;
30
31 template class std::vector<Value>;
32
33 REGISTER_PRIMITIVE_TYPE(Array, Object, Array::GetPrototype());
34
35 Array::Array(const ArrayData& other)
36         : m_Data(other)
37 { }
38
39 Array::Array(ArrayData&& other)
40         : m_Data(std::move(other))
41 { }
42
43 Array::Array(std::initializer_list<Value> init)
44         : m_Data(init)
45 { }
46
47 /**
48  * Restrieves a value from an array.
49  *
50  * @param index The index.
51  * @returns The value.
52  */
53 Value Array::Get(SizeType index) const
54 {
55         ObjectLock olock(this);
56
57         return m_Data.at(index);
58 }
59
60 /**
61  * Sets a value in the array.
62  *
63  * @param index The index.
64  * @param value The value.
65  * @param overrideFrozen Whether to allow modifying frozen arrays.
66  */
67 void Array::Set(SizeType index, const Value& value, bool overrideFrozen)
68 {
69         ObjectLock olock(this);
70
71         if (m_Frozen && !overrideFrozen)
72                 BOOST_THROW_EXCEPTION(std::invalid_argument("Value in array must not be modified."));
73
74         m_Data.at(index) = value;
75 }
76
77 /**
78  * Sets a value in the array.
79  *
80  * @param index The index.
81  * @param value The value.
82  * @param overrideFrozen Whether to allow modifying frozen arrays.
83  */
84 void Array::Set(SizeType index, Value&& value, bool overrideFrozen)
85 {
86         ObjectLock olock(this);
87
88         if (m_Frozen && !overrideFrozen)
89                 BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
90
91         m_Data.at(index).Swap(value);
92 }
93
94 /**
95  * Adds a value to the array.
96  *
97  * @param value The value.
98  * @param overrideFrozen Whether to allow modifying frozen arrays.
99  */
100 void Array::Add(Value value, bool overrideFrozen)
101 {
102         ObjectLock olock(this);
103
104         if (m_Frozen && !overrideFrozen)
105                 BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
106
107         m_Data.push_back(std::move(value));
108 }
109
110 /**
111  * Returns an iterator to the beginning of the array.
112  *
113  * Note: Caller must hold the object lock while using the iterator.
114  *
115  * @returns An iterator.
116  */
117 Array::Iterator Array::Begin()
118 {
119         ASSERT(OwnsLock());
120
121         return m_Data.begin();
122 }
123
124 /**
125  * Returns an iterator to the end of the array.
126  *
127  * Note: Caller must hold the object lock while using the iterator.
128  *
129  * @returns An iterator.
130  */
131 Array::Iterator Array::End()
132 {
133         ASSERT(OwnsLock());
134
135         return m_Data.end();
136 }
137
138 /**
139  * Returns the number of elements in the array.
140  *
141  * @returns Number of elements.
142  */
143 size_t Array::GetLength() const
144 {
145         ObjectLock olock(this);
146
147         return m_Data.size();
148 }
149
150 /**
151  * Checks whether the array contains the specified value.
152  *
153  * @param value The value.
154  * @returns true if the array contains the value, false otherwise.
155  */
156 bool Array::Contains(const Value& value) const
157 {
158         ObjectLock olock(this);
159
160         return (std::find(m_Data.begin(), m_Data.end(), value) != m_Data.end());
161 }
162
163 /**
164  * Insert the given value at the specified index
165  *
166  * @param index The index
167  * @param value The value to add
168  * @param overrideFrozen Whether to allow modifying frozen arrays.
169  */
170 void Array::Insert(SizeType index, Value value, bool overrideFrozen)
171 {
172         ObjectLock olock(this);
173
174         ASSERT(index <= m_Data.size());
175
176         if (m_Frozen && !overrideFrozen)
177                 BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
178
179         m_Data.insert(m_Data.begin() + index, std::move(value));
180 }
181
182 /**
183  * Removes the specified index from the array.
184  *
185  * @param index The index.
186  * @param overrideFrozen Whether to allow modifying frozen arrays.
187  */
188 void Array::Remove(SizeType index, bool overrideFrozen)
189 {
190         ObjectLock olock(this);
191
192         if (m_Frozen && !overrideFrozen)
193                 BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
194
195         m_Data.erase(m_Data.begin() + index);
196 }
197
198 /**
199  * Removes the item specified by the iterator from the array.
200  *
201  * @param it The iterator.
202  * @param overrideFrozen Whether to allow modifying frozen arrays.
203  */
204 void Array::Remove(Array::Iterator it, bool overrideFrozen)
205 {
206         ASSERT(OwnsLock());
207
208         if (m_Frozen && !overrideFrozen)
209                 BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
210
211         m_Data.erase(it);
212 }
213
214 void Array::Resize(SizeType newSize, bool overrideFrozen)
215 {
216         ObjectLock olock(this);
217
218         if (m_Frozen && !overrideFrozen)
219                 BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
220
221         m_Data.resize(newSize);
222 }
223
224 void Array::Clear(bool overrideFrozen)
225 {
226         ObjectLock olock(this);
227
228         if (m_Frozen && !overrideFrozen)
229                 BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
230
231         m_Data.clear();
232 }
233
234 void Array::Reserve(SizeType newSize, bool overrideFrozen)
235 {
236         ObjectLock olock(this);
237
238         if (m_Frozen && !overrideFrozen)
239                 BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
240
241         m_Data.reserve(newSize);
242 }
243
244 void Array::CopyTo(const Array::Ptr& dest) const
245 {
246         ObjectLock olock(this);
247         ObjectLock xlock(dest);
248
249         if (dest->m_Frozen)
250                 BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
251
252         std::copy(m_Data.begin(), m_Data.end(), std::back_inserter(dest->m_Data));
253 }
254
255 /**
256  * Makes a shallow copy of an array.
257  *
258  * @returns a copy of the array.
259  */
260 Array::Ptr Array::ShallowClone() const
261 {
262         Array::Ptr clone = new Array();
263         CopyTo(clone);
264         return clone;
265 }
266
267 /**
268  * Makes a deep clone of an array
269  * and its elements.
270  *
271  * @returns a copy of the array.
272  */
273 Object::Ptr Array::Clone() const
274 {
275         ArrayData arr;
276
277         ObjectLock olock(this);
278         for (const Value& val : m_Data) {
279                 arr.push_back(val.Clone());
280         }
281
282         return new Array(std::move(arr));
283 }
284
285 Array::Ptr Array::Reverse() const
286 {
287         Array::Ptr result = new Array();
288
289         ObjectLock olock(this);
290         ObjectLock xlock(result);
291
292         std::copy(m_Data.rbegin(), m_Data.rend(), std::back_inserter(result->m_Data));
293
294         return result;
295 }
296
297 void Array::Sort(bool overrideFrozen)
298 {
299         ObjectLock olock(this);
300
301         if (m_Frozen && !overrideFrozen)
302                 BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
303
304         std::sort(m_Data.begin(), m_Data.end());
305 }
306
307 String Array::ToString() const
308 {
309         std::ostringstream msgbuf;
310         ConfigWriter::EmitArray(msgbuf, 1, const_cast<Array *>(this));
311         return msgbuf.str();
312 }
313
314 Array::Ptr Array::Unique() const
315 {
316         std::set<Value> result;
317
318         ObjectLock olock(this);
319
320         for (const Value& item : m_Data) {
321                 result.insert(item);
322         }
323
324         return Array::FromSet(result);
325 }
326
327 void Array::Freeze()
328 {
329         ObjectLock olock(this);
330         m_Frozen = true;
331 }
332
333 Value Array::GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const
334 {
335         int index;
336
337         try {
338                 index = Convert::ToLong(field);
339         } catch (...) {
340                 return Object::GetFieldByName(field, sandboxed, debugInfo);
341         }
342
343         ObjectLock olock(this);
344
345         if (index < 0 || static_cast<size_t>(index) >= GetLength())
346                 BOOST_THROW_EXCEPTION(ScriptError("Array index '" + Convert::ToString(index) + "' is out of bounds.", debugInfo));
347
348         return Get(index);
349 }
350
351 void Array::SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo)
352 {
353         ObjectLock olock(this);
354
355         int index = Convert::ToLong(field);
356
357         if (index < 0)
358                 BOOST_THROW_EXCEPTION(ScriptError("Array index '" + Convert::ToString(index) + "' is out of bounds.", debugInfo));
359
360         if (static_cast<size_t>(index) >= GetLength())
361                 Resize(index + 1, overrideFrozen);
362
363         Set(index, value, overrideFrozen);
364 }
365
366 Array::Iterator icinga::begin(const Array::Ptr& x)
367 {
368         return x->Begin();
369 }
370
371 Array::Iterator icinga::end(const Array::Ptr& x)
372 {
373         return x->End();
374 }