ScummVM API documentation
as_array.h
1 /*
2  AngelCode Scripting Library
3  Copyright (c) 2003-2015 Andreas Jonsson
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any
7  damages arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any
10  purpose, including commercial applications, and to alter it and
11  redistribute it freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you
14  must not claim that you wrote the original software. If you use
15  this software in a product, an acknowledgment in the product
16  documentation would be appreciated but is not required.
17 
18  2. Altered source versions must be plainly marked as such, and
19  must not be misrepresented as being the original software.
20 
21  3. This notice may not be removed or altered from any source
22  distribution.
23 
24  The original version of this library can be located at:
25  http://www.angelcode.com/angelscript/
26 
27  Andreas Jonsson
28  andreas@angelcode.com
29 */
30 
31 #ifndef AS_ARRAY_H
32 #define AS_ARRAY_H
33 
34 #if !defined(AS_NO_MEMORY_H)
35 #include <memory.h>
36 #endif
37 #include <string.h> // some compilers declare memcpy() here
38 
39 #ifdef _MSC_VER
40 #pragma warning(disable:4345) // warning about a change in how the code is handled in this version
41 #endif
42 
43 #include "as_config.h"
44 
45 BEGIN_AS_NAMESPACE
46 
47 template <class T> class asCArray {
48 public:
49  asCArray();
50  asCArray(const asCArray<T> &);
51  asCArray(asUINT reserve);
52  ~asCArray();
53 
54  void Allocate(asUINT numElements, bool keepData);
55  void AllocateNoConstruct(asUINT numElements, bool keepData);
56  asUINT GetCapacity() const;
57 
58  void PushLast(const T &element);
59  T PopLast();
60 
61  bool SetLength(asUINT numElements);
62  bool SetLengthNoConstruct(asUINT numElements);
63  asUINT GetLength() const;
64 
65  void Copy(const T *, asUINT count);
66  asCArray<T> &operator =(const asCArray<T> &);
67  void SwapWith(asCArray<T> &other);
68 
69  const T &operator [](asUINT index) const;
70  T &operator [](asUINT index);
71  T *AddressOf();
72  const T *AddressOf() const;
73 
74  bool Concatenate(const asCArray<T> &);
75  void Concatenate(T *, unsigned int count);
76 
77  bool Exists(const T &element) const;
78  int IndexOf(const T &element) const;
79  void RemoveIndex(asUINT index); // Removes the entry without reordering the array
80  void RemoveValue(const T &element); // Removes the value without reordering the array
81  void RemoveIndexUnordered(asUINT index); // Removes the entry without keeping the order
82 
83  bool operator==(const asCArray<T> &) const;
84  bool operator!=(const asCArray<T> &) const;
85 
86 protected:
87  T *array;
88  asUINT length; // 32bits is enough for all uses of this array
89  asUINT maxLength;
90  char buf[2 * 4 * AS_PTR_SIZE]; // Avoid dynamically allocated memory for tiny arrays
91 };
92 
93 // Implementation
94 
95 template <class T>
97  return array;
98 }
99 
100 template <class T>
101 const T *asCArray<T>::AddressOf() const {
102  return array;
103 }
104 
105 template <class T>
106 asCArray<T>::asCArray(void) {
107  array = 0;
108  length = 0;
109  maxLength = 0;
110 }
111 
112 template <class T>
114  array = 0;
115  length = 0;
116  maxLength = 0;
117 
118  *this = copy;
119 }
120 
121 template <class T>
122 asCArray<T>::asCArray(asUINT reserve) {
123  array = 0;
124  length = 0;
125  maxLength = 0;
126 
127  Allocate(reserve, false);
128 }
129 
130 template <class T>
132  // Allocating a zero length array will free all memory
133  Allocate(0, 0);
134 }
135 
136 template <class T>
137 asUINT asCArray<T>::GetLength() const {
138  return length;
139 }
140 
141 template <class T>
142 const T &asCArray<T>::operator [](asUINT index) const {
143  asASSERT(index < length);
144 
145  return array[index];
146 }
147 
148 template <class T>
149 T &asCArray<T>::operator [](asUINT index) {
150  asASSERT(index < length);
151 
152  return array[index];
153 }
154 
155 template <class T>
156 void asCArray<T>::PushLast(const T &element) {
157  if (length == maxLength) {
158  if (maxLength == 0)
159  Allocate(1, false);
160  else
161  Allocate(2 * maxLength, true);
162 
163  if (length == maxLength) {
164  // Out of memory. Return without doing anything
165  return;
166  }
167  }
168 
169  array[length++] = element;
170 }
171 
172 template <class T>
174  asASSERT(length > 0);
175 
176  return array[--length];
177 }
178 
179 template <class T>
180 void asCArray<T>::Allocate(asUINT numElements, bool keepData) {
181  // We have 4 situations
182  // 1. The previous array is 8 bytes or smaller and the new array is also 8 bytes or smaller
183  // 2. The previous array is 8 bytes or smaller and the new array is larger than 8 bytes
184  // 3. The previous array is larger than 8 bytes and the new array is 8 bytes or smaller
185  // 4. The previous array is larger than 8 bytes and the new array is also larger than 8 bytes
186 
187  T *tmp = 0;
188  if (numElements) {
189  if (sizeof(T)*numElements <= sizeof(buf))
190  // Use the internal buffer
191  tmp = reinterpret_cast<T *>(buf);
192  else {
193  // Allocate the array and construct each of the elements
194  tmp = asNEWARRAY(T, numElements);
195  if (tmp == 0) {
196  // Out of memory. Return without doing anything
197  return;
198  }
199  }
200 
201  if (array == tmp) {
202  // Construct only the newly allocated elements
203  for (asUINT n = length; n < numElements; n++)
204  new (&tmp[n]) T();
205  } else {
206  // Construct all elements
207  for (asUINT n = 0; n < numElements; n++)
208  new (&tmp[n]) T();
209  }
210  }
211 
212  if (array) {
213  asUINT oldLength = length;
214 
215  if (array == tmp) {
216  if (keepData) {
217  if (length > numElements)
218  length = numElements;
219  } else
220  length = 0;
221 
222  // Call the destructor for elements that are no longer used
223  for (asUINT n = length; n < oldLength; n++)
224  array[n].~T();
225  } else {
226  if (keepData) {
227  if (length > numElements)
228  length = numElements;
229 
230  for (asUINT n = 0; n < length; n++)
231  tmp[n] = array[n];
232  } else
233  length = 0;
234 
235  // Call the destructor for all elements
236  for (asUINT n = 0; n < oldLength; n++)
237  array[n].~T();
238 
239  if (array != reinterpret_cast<T *>(buf))
240  asDELETEARRAY(array);
241  }
242  }
243 
244  array = tmp;
245  maxLength = numElements;
246 }
247 
248 template <class T>
249 void asCArray<T>::AllocateNoConstruct(asUINT numElements, bool keepData) {
250  // We have 4 situations
251  // 1. The previous array is 8 bytes or smaller and the new array is also 8 bytes or smaller
252  // 2. The previous array is 8 bytes or smaller and the new array is larger than 8 bytes
253  // 3. The previous array is larger than 8 bytes and the new array is 8 bytes or smaller
254  // 4. The previous array is larger than 8 bytes and the new array is also larger than 8 bytes
255 
256  T *tmp = 0;
257  if (numElements) {
258  if (sizeof(T)*numElements <= sizeof(buf))
259  // Use the internal buffer
260  tmp = reinterpret_cast<T *>(buf);
261  else {
262  // Allocate the array and construct each of the elements
263  tmp = asNEWARRAY(T, numElements);
264  if (tmp == 0) {
265  // Out of memory. Return without doing anything
266  return;
267  }
268  }
269  }
270 
271  if (array) {
272  if (array == tmp) {
273  if (keepData) {
274  if (length > numElements)
275  length = numElements;
276  } else
277  length = 0;
278  } else {
279  if (keepData) {
280  if (length > numElements)
281  length = numElements;
282 
283  memcpy(tmp, array, sizeof(T)*length);
284  } else
285  length = 0;
286 
287  if (array != reinterpret_cast<T *>(buf))
288  asDELETEARRAY(array);
289  }
290  }
291 
292  array = tmp;
293  maxLength = numElements;
294 }
295 
296 template <class T>
297 asUINT asCArray<T>::GetCapacity() const {
298  return maxLength;
299 }
300 
301 template <class T>
302 bool asCArray<T>::SetLength(asUINT numElements) {
303  if (numElements > maxLength) {
304  Allocate(numElements, true);
305  if (numElements > maxLength) {
306  // Out of memory. Return without doing anything
307  return false;
308  }
309  }
310 
311  length = numElements;
312  return true;
313 }
314 
315 template <class T>
316 bool asCArray<T>::SetLengthNoConstruct(asUINT numElements) {
317  if (numElements > maxLength) {
318  AllocateNoConstruct(numElements, true);
319  if (numElements > maxLength) {
320  // Out of memory. Return without doing anything
321  return false;
322  }
323  }
324 
325  length = numElements;
326  return true;
327 }
328 
329 template <class T>
330 void asCArray<T>::Copy(const T *data, asUINT count) {
331  if (maxLength < count) {
332  Allocate(count, false);
333  if (maxLength < count) {
334  // Out of memory. Return without doing anything
335  return;
336  }
337  }
338 
339  for (asUINT n = 0; n < count; n++)
340  array[n] = data[n];
341 
342  length = count;
343 }
344 
345 template <class T>
347  Copy(copy.array, copy.length);
348 
349  return *this;
350 }
351 
352 template <class T>
353 void asCArray<T>::SwapWith(asCArray<T> &other) {
354  T *tmpArray = array;
355  asUINT tmpLength = length;
356  asUINT tmpMaxLength = maxLength;
357  char tmpBuf[sizeof(buf)];
358  memcpy(tmpBuf, buf, sizeof(buf));
359 
360  array = other.array;
361  length = other.length;
362  maxLength = other.maxLength;
363  memcpy(buf, other.buf, sizeof(buf));
364 
365  other.array = tmpArray;
366  other.length = tmpLength;
367  other.maxLength = tmpMaxLength;
368  memcpy(other.buf, tmpBuf, sizeof(buf));
369 
370  // If the data is in the internal buffer, then the array pointer must refer to it
371  if (array == reinterpret_cast<T *>(other.buf))
372  array = reinterpret_cast<T *>(buf);
373  if (other.array == reinterpret_cast<T *>(buf))
374  other.array = reinterpret_cast<T *>(other.buf);
375 }
376 
377 template <class T>
378 bool asCArray<T>::operator ==(const asCArray<T> &other) const {
379  if (length != other.length) return false;
380 
381  for (asUINT n = 0; n < length; n++)
382  if (array[n] != other.array[n])
383  return false;
384 
385  return true;
386 }
387 
388 template <class T>
389 bool asCArray<T>::operator !=(const asCArray<T> &other) const {
390  return !(*this == other);
391 }
392 
393 
394 // Returns false if the concatenation wasn't successful due to out of memory
395 template <class T>
396 bool asCArray<T>::Concatenate(const asCArray<T> &other) {
397  if (maxLength < length + other.length) {
398  Allocate(length + other.length, true);
399  if (maxLength < length + other.length) {
400  // Out of memory
401  return false;
402  }
403  }
404 
405  for (asUINT n = 0; n < other.length; n++)
406  array[length + n] = other.array[n];
407 
408  length += other.length;
409 
410  // Success
411  return true;
412 }
413 
414 template <class T>
415 void asCArray<T>::Concatenate(T *other, unsigned int count) {
416  for (unsigned int c = 0; c < count; c++)
417  PushLast(other[c]);
418 }
419 
420 template <class T>
421 bool asCArray<T>::Exists(const T &e) const {
422  return IndexOf(e) == -1 ? false : true;
423 }
424 
425 template <class T>
426 int asCArray<T>::IndexOf(const T &e) const {
427  for (asUINT n = 0; n < length; n++)
428  if (array[n] == e) return static_cast<int>(n);
429 
430  return -1;
431 }
432 
433 template <class T>
434 void asCArray<T>::RemoveIndex(asUINT index) {
435  if (index < length) {
436  for (asUINT n = index; n < length - 1; n++)
437  array[n] = array[n + 1];
438 
439  PopLast();
440  }
441 }
442 
443 template <class T>
444 void asCArray<T>::RemoveValue(const T &e) {
445  for (asUINT n = 0; n < length; n++) {
446  if (array[n] == e) {
447  RemoveIndex(n);
448  break;
449  }
450  }
451 }
452 
453 template <class T>
454 void asCArray<T>::RemoveIndexUnordered(asUINT index) {
455  if (index == length - 1)
456  PopLast();
457  else if (index < length)
458  array[index] = PopLast();
459 }
460 
461 END_AS_NAMESPACE
462 
463 #endif
Out copy(In first, In last, Out dst)
Definition: algorithm.h:52
Definition: as_array.h:47