Cafu Engine
Array.hpp
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
6 
7 #ifndef CAFU_ARRAY_HPP_INCLUDED
8 #define CAFU_ARRAY_HPP_INCLUDED
9 
10 #include <stdlib.h>
11 #include <cassert>
12 
13 // Turn off bogus warnings that occur with VC11's static code analysis.
14 // (Should move this to a better place though, e.g. some `compat.h` file...)
15 #if defined(_WIN32) && defined(_MSC_VER)
16  // warning C6011: dereferencing NULL pointer <name>
17  #pragma warning(disable:6011)
18 
19  // warning C6385: invalid data: accessing <buffer name>, the readable size is <size1> bytes, but <size2> bytes may be read: Lines: x, y
20  #pragma warning(disable:6385)
21 
22  // warning C6386: buffer overrun: accessing <buffer name>, the writable size is <size1> bytes, but <size2> bytes may be written: Lines: x, y
23  #pragma warning(disable:6386)
24 
25  // warning C28159: Consider using another function instead.
26  #pragma warning(disable:28159)
27 
28  // warning C28251: Inconsistent annotation for function: this instance has an error.
29  #pragma warning(disable:28251)
30 #endif
31 
32 
33 // These classes are intentionally not defined in ArrayT<T>,
34 // because we don't need them parametrised by T.
35 class cfArrayError {}; ///< General array error.
36 class cfOutOfRange : public cfArrayError {}; ///< Array index exceeds array boundaries.
37 class cfSizeOverflow : public cfArrayError {}; ///< Overflow of the arrays size.
38 
39 
40 template<class T> class ArrayT
41 {
42  private:
43 
44  unsigned long MaxNrOfElements;
45  unsigned long NrOfElements;
46  T* Elements;
47 
48 
49  public:
50 
51  ArrayT(); ///< Usual constructor
52  ArrayT(const ArrayT<T>& OldArray); ///< Copy constructor
53  ~ArrayT(); ///< Destructor
54  ArrayT<T>& operator = (const ArrayT<T>& OldArray); ///< Assignment operator
55  bool operator == (const ArrayT<T>& Other) const; ///< Equality operator
56  bool operator != (const ArrayT<T>& Other) const; ///< Inequality operator
57 
58  unsigned long Size() const; ///< Get size of array
59  void Clear(); ///< Clear array (and free allocated memory)
60  void Overwrite(); ///< Clear array (but reuse memory)
61  T& operator [] (unsigned long Index);
62  const T& operator [] (unsigned long Index) const;
63  void PushBack(const T Element);
64  void PushBackEmpty(unsigned long Amount=1);
65  void PushBackEmptyExact(unsigned long Amount=1);
66  void DeleteBack(unsigned long Amount=1);
67 
68  // "Convenience" methods.
69  void PushBack(const ArrayT<T>& Other);
70  void InsertAt(unsigned long Index, const T Element); // TODO: Rename to InsertAtAndKeepOrder()
71  void RemoveAt(unsigned long Index);
72  void RemoveAtAndKeepOrder(unsigned long Index);
73  template<typename Function>
74  void QuickSort(Function IsLess);
75  // void QuickSort(unsigned long FirstIndex, unsigned long LastIndex, bool (*IsLess)(const T& E1, const T& E2));
76  int Find(const T& Element) const;
77 };
78 
79 
80 template<class T> inline ArrayT<T>::ArrayT() // Usual constructor
81 {
82  MaxNrOfElements=0;
83  NrOfElements =0;
84  Elements =NULL;
85 }
86 
87 
88 template<class T> inline ArrayT<T>::ArrayT(const ArrayT<T>& OldArray) // Copy constructor
89 {
90  MaxNrOfElements=OldArray.MaxNrOfElements;
91  NrOfElements =OldArray.NrOfElements;
92  Elements =MaxNrOfElements>0 ? new T[MaxNrOfElements] : NULL;
93 
94  for (unsigned long Nr=0; Nr<NrOfElements; Nr++) Elements[Nr]=OldArray.Elements[Nr];
95 }
96 
97 
98 template<class T> inline ArrayT<T>::~ArrayT() // Destructor
99 {
100  delete[] Elements;
101 }
102 
103 
104 template<class T> inline ArrayT<T>& ArrayT<T>::operator = (const ArrayT<T>& OldArray) // Assignment op
105 {
106  // Handles self-assignment implicitly right!
107  T* NewElements=OldArray.MaxNrOfElements>0 ? new T[OldArray.MaxNrOfElements] : NULL;
108  for (unsigned long Nr=0; Nr<OldArray.NrOfElements; Nr++) NewElements[Nr]=OldArray.Elements[Nr];
109 
110  delete[] Elements;
111 
112  MaxNrOfElements=OldArray.MaxNrOfElements;
113  NrOfElements =OldArray.NrOfElements;
114  Elements =NewElements;
115  return *this;
116 }
117 
118 
119 template<class T> inline bool ArrayT<T>::operator == (const ArrayT<T>& Other) const
120 {
121  if (NrOfElements != Other.NrOfElements)
122  return false;
123 
124  for (unsigned long Nr=0; Nr<NrOfElements; Nr++)
125  if (Elements[Nr] != Other.Elements[Nr])
126  return false;
127 
128  return true;
129 }
130 
131 
132 template<class T> inline bool ArrayT<T>::operator != (const ArrayT<T>& Other) const
133 {
134  return !(this->operator == (Other));
135 }
136 
137 
138 template<class T> inline unsigned long ArrayT<T>::Size() const
139 {
140  return NrOfElements;
141 }
142 
143 
144 template<class T> inline void ArrayT<T>::Clear()
145 {
146  delete[] Elements;
147 
148  MaxNrOfElements=0;
149  NrOfElements =0;
150  Elements =NULL;
151 }
152 
153 
154 template<class T> inline void ArrayT<T>::Overwrite()
155 {
156  // for (unsigned long Nr=0; Nr<NrOfElements; Nr++) Elements[Nr]=T();
157  NrOfElements=0;
158 }
159 
160 
161 template<class T> inline T& ArrayT<T>::operator [] (unsigned long Index)
162 {
163  assert(Index<NrOfElements);
164 
165  return Elements[Index];
166 }
167 
168 
169 template<class T> inline const T& ArrayT<T>::operator [] (unsigned long Index) const
170 {
171  assert(Index<NrOfElements);
172 
173  return Elements[Index];
174 }
175 
176 
177 // Der Parameter muß hier als Kopie übergeben werden, nicht als Referenz. Wenn man einem Array mit PushBack ein eigenes
178 // Element anhängen möchte (z.B. wie in Array.PushBack(Array[0]);), kann es ansonsten zu einem Fehler führen, wenn das
179 // Array gleichzeitig reallokiert und verschoben werden muß!
180 template<class T> inline void ArrayT<T>::PushBack(const T Element)
181 {
182  NrOfElements++;
183 
184  if (NrOfElements>MaxNrOfElements)
185  {
186  if (!MaxNrOfElements) MaxNrOfElements=1;
187  while (MaxNrOfElements<NrOfElements)
188  {
189  if (MaxNrOfElements>=0x80000000) throw cfSizeOverflow();
190  MaxNrOfElements*=2;
191  }
192 
193  T* NewElements=new T[MaxNrOfElements];
194  for (unsigned long Nr=0; Nr<NrOfElements-1; Nr++) NewElements[Nr]=Elements[Nr];
195 
196  delete[] Elements;
197  Elements=NewElements;
198  }
199 
200  Elements[NrOfElements-1]=Element;
201 }
202 
203 
204 template<class T> inline void ArrayT<T>::PushBackEmpty(unsigned long Amount)
205 {
206  NrOfElements+=Amount;
207 
208  if (NrOfElements>MaxNrOfElements)
209  {
210  if (!MaxNrOfElements) MaxNrOfElements=1;
211  while (MaxNrOfElements<NrOfElements)
212  {
213  if (MaxNrOfElements>=0x80000000) throw cfSizeOverflow();
214  MaxNrOfElements*=2;
215  }
216 
217  T* NewElements=new T[MaxNrOfElements];
218  for (unsigned long Nr=0; Nr<NrOfElements-Amount; Nr++) NewElements[Nr]=Elements[Nr];
219 
220  delete[] Elements;
221  Elements=NewElements;
222  }
223 }
224 
225 
226 template<class T> inline void ArrayT<T>::PushBackEmptyExact(unsigned long Amount)
227 {
228  NrOfElements+=Amount;
229 
230  if (NrOfElements>MaxNrOfElements)
231  {
232  MaxNrOfElements=NrOfElements;
233 
234  T* NewElements=new T[MaxNrOfElements];
235  for (unsigned long Nr=0; Nr<NrOfElements-Amount; Nr++) NewElements[Nr]=Elements[Nr];
236 
237  delete[] Elements;
238  Elements=NewElements;
239  }
240 }
241 
242 
243 template<class T> inline void ArrayT<T>::DeleteBack(unsigned long Amount)
244 {
245  while (Amount>0 && NrOfElements>0)
246  {
247  Elements[NrOfElements-1]=T();
248  NrOfElements--;
249  Amount--;
250  }
251 }
252 
253 
254 template<class T> inline void ArrayT<T>::PushBack(const ArrayT<T>& Other)
255 {
256  for (unsigned long Nr=0; Nr<Other.Size(); Nr++)
257  PushBack(Other[Nr]);
258 }
259 
260 
261 template<class T> inline void ArrayT<T>::InsertAt(unsigned long Index, const T Element)
262 {
263  assert(Index<=NrOfElements); // This is intentionally <= and not <, because we immediately add an element below.
264 
265  PushBackEmpty();
266 
267  for (unsigned long Nr=NrOfElements-1; Nr>Index; Nr--)
268  Elements[Nr]=Elements[Nr-1];
269 
270  Elements[Index]=Element;
271 }
272 
273 
274 template<class T> inline void ArrayT<T>::RemoveAt(unsigned long Index)
275 {
276  assert(Index<NrOfElements);
277 
278  Elements[Index]=Elements[NrOfElements-1];
279  DeleteBack();
280 }
281 
282 
283 template<class T> inline void ArrayT<T>::RemoveAtAndKeepOrder(unsigned long Index)
284 {
285  assert(Index<NrOfElements);
286 
287  for (unsigned long Nr=Index; Nr+1<NrOfElements; Nr++)
288  Elements[Nr]=Elements[Nr+1];
289 
290  DeleteBack();
291 }
292 
293 
294 template<class T> template<typename Function> inline void ArrayT<T>::QuickSort(Function IsLess)
295 {
296  static ArrayT<unsigned long> ToDoRanges;
297 
298  if (NrOfElements<=1) return;
299 
300  ToDoRanges.Overwrite();
301  ToDoRanges.PushBack(0);
302  ToDoRanges.PushBack(NrOfElements-1);
303 
304 
305  while (ToDoRanges.Size()>=2)
306  {
307  const unsigned long LastIndex =ToDoRanges[ToDoRanges.Size()-1]; ToDoRanges.DeleteBack();
308  const unsigned long FirstIndex=ToDoRanges[ToDoRanges.Size()-1]; ToDoRanges.DeleteBack();
309 
310  if (FirstIndex<LastIndex)
311  {
312  const T& x=Elements[LastIndex];
313  unsigned long i=FirstIndex-1;
314 
315  for (unsigned long j=FirstIndex; j<=LastIndex-1; j++)
316  if (IsLess(Elements[j], x))
317  {
318  i++;
319  const T Swap=Elements[i];
320  Elements[i]=Elements[j];
321  Elements[j]=Swap;
322  }
323 
324  const T Swap=Elements[i+1];
325  Elements[i+1]=Elements[LastIndex];
326  Elements[LastIndex]=Swap;
327 
328  i++;
329 
330  ToDoRanges.PushBack(i+1); ToDoRanges.PushBack(LastIndex);
331  if (i>0) { ToDoRanges.PushBack(FirstIndex); ToDoRanges.PushBack(i-1); }
332  }
333  }
334 }
335 
336 
337 /* // Simple recursive implementation from school.
338 template<class T> inline void ArrayT<T>::QuickSort(unsigned long FirstIndex, unsigned long LastIndex, bool (*IsLess)(const T& E1, const T& E2))
339 {
340  if (FirstIndex<LastIndex)
341  {
342  const T& x=Elements[LastIndex];
343  unsigned long i=FirstIndex-1;
344 
345  for (unsigned long j=FirstIndex; j<=LastIndex-1; j++)
346  if (IsLess(Elements[j], x))
347  {
348  i++;
349  const T Swap=Elements[i];
350  Elements[i]=Elements[j];
351  Elements[j]=Swap;
352  }
353 
354  const T Swap=Elements[i+1];
355  Elements[i+1]=Elements[LastIndex];
356  Elements[LastIndex]=Swap;
357 
358  i++;
359 
360  if (i>0) QuickSort(FirstIndex, i-1, IsLess);
361  QuickSort(i+1, LastIndex, IsLess);
362  }
363 } */
364 
365 
366 template<class T> inline int ArrayT<T>::Find(const T& Element) const
367 {
368  for (unsigned long Nr=0; Nr<NrOfElements; Nr++)
369  if (Elements[Nr]==Element)
370  return Nr;
371 
372  return -1;
373 }
374 
375 #endif
General array error.
Definition: Array.hpp:35
ArrayT< T > & operator=(const ArrayT< T > &OldArray)
Assignment operator.
Definition: Array.hpp:104
unsigned long Size() const
Get size of array.
Definition: Array.hpp:138
bool operator==(const ArrayT< T > &Other) const
Equality operator.
Definition: Array.hpp:119
Array index exceeds array boundaries.
Definition: Array.hpp:36
~ArrayT()
Destructor.
Definition: Array.hpp:98
bool operator!=(const ArrayT< T > &Other) const
Inequality operator.
Definition: Array.hpp:132
Overflow of the arrays size.
Definition: Array.hpp:37
void Overwrite()
Clear array (but reuse memory)
Definition: Array.hpp:154
void Clear()
Clear array (and free allocated memory)
Definition: Array.hpp:144
Definition: Renderer.hpp:16
ArrayT()
Usual constructor.
Definition: Array.hpp:80