source: trunk/src/array.h @ 1687

Last change on this file since 1687 was 1381, checked in by sam, 9 years ago

core: some clang and g++ 4.7 compilation fixes.

  • Property svn:keywords set to Id
File size: 14.6 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://sam.zoy.org/projects/COPYING.WTFPL for more details.
9//
10
11//
12// The Array class
13// ---------------
14// A very simple Array class not unlike the std::vector, with some nice
15// additional features, eg. Array<int,float> for automatic arrays of structs.
16//
17
18#if !defined __LOL_ARRAY_H__
19#define __LOL_ARRAY_H__
20
21#include <new>
22#include <stdint.h>
23
24namespace lol
25{
26
27/*
28 * The base array type.
29 *
30 * Contains an m_data memory array of Elements, of which only the first
31 * m_count are allocated. The rest is uninitialised memory.
32 */
33
34template<typename T, typename ARRAY> class ArrayBase
35{
36public:
37    typedef T Element;
38
39    inline ArrayBase() : m_data(0), m_count(0), m_reserved(0)
40    {
41    }
42
43    inline ~ArrayBase()
44    {
45        for (int i = 0; i < m_count; i++)
46            m_data[i].~Element();
47        delete[] reinterpret_cast<uint8_t *>(m_data);
48    }
49
50    ArrayBase(ArrayBase const& that) : m_data(0), m_count(0), m_reserved(0)
51    {
52        /* Reserve the exact number of values instead of what the other
53         * array had reserved. Just a method for not wasting too much. */
54        Reserve(that.m_count);
55        for (int i = 0; i < that.m_count; i++)
56            new(&m_data[i]) Element(that[i]);
57        m_count = that.m_count;
58    }
59
60    ArrayBase& operator=(ArrayBase const& that)
61    {
62        if ((uintptr_t)this != (uintptr_t)&that)
63        {
64            if (m_reserved < that.m_count)
65            {
66                /* If not enough space, reserve memory and use placement
67                 * new directly for all elements. */
68                Reserve(that.m_count);
69                for (int i = 0; i < that.m_count; i++)
70                    new(&m_data[i]) Element(that[i]);
71            }
72            else
73            {
74                /* If enough space, overwrite the common elements, then
75                 * use placement new for the elements in the other array
76                 * that we do not have, and finally destroy the remaining
77                 * elements. */
78                for (int i = 0; i < m_count && i < that.m_count; i++)
79                    m_data[i] = Element(that[i]);
80                for (int i = m_count; i < that.m_count; i++)
81                    new(&m_data[i]) Element(that[i]);
82                for (int i = that.m_count; i < m_count; i++)
83                    m_data[i].~Element();
84            }
85            m_count = that.m_count;
86        }
87        return *this;
88    }
89
90    ArrayBase& operator+=(ARRAY const &that)
91    {
92        int todo = that.m_count;
93        Reserve(m_count + that.m_count);
94        for (int i = 0; i < todo; i++)
95            *this << that[i];
96        return *this;
97    }
98
99    ARRAY operator+(ARRAY const &that) const
100    {
101        /* FIXME: upon return, this makes a copy of the temporary object;
102         * use either C++11 move semantics, or add a special flag to the
103         * object indicating we're a temporary about to be destroyed */
104        ARRAY ret;
105        ret.Reserve(m_count + that.m_count);
106        for (int i = 0; i < m_count; i++)
107            ret << (*this)[i];
108        for (int i = 0; i < that.m_count; i++)
109            ret << that[i];
110        return ret;
111    }
112
113    inline Element& operator[](int n)
114    {
115        return m_data[n];
116    }
117
118    inline Element const& operator[](int n) const
119    {
120        return m_data[n];
121    }
122
123    inline Element& Last()
124    {
125        return m_data[m_count - 1];
126    }
127
128    inline Element const& Last() const
129    {
130        return m_data[m_count - 1];
131    }
132
133    inline ArrayBase& operator<<(T const &x)
134    {
135        if (m_count >= m_reserved)
136        {
137            T tmp = x;
138            Reserve(m_count * 13 / 8 + 8);
139            new (&m_data[m_count++]) Element(tmp);
140        }
141        else
142        {
143            new (&m_data[m_count++]) Element(x);
144        }
145        return *this;
146    }
147
148    inline void Push(T const &x)
149    {
150        *this << x;
151    }
152
153    inline void Pop()
154    {
155        Remove(m_count - 1, 1);
156    }
157
158    void Remove(int pos, int todelete = 1)
159    {
160        for (int i = pos; i + todelete < m_count; i++)
161            m_data[i] = m_data[i + todelete];
162        for (int i = m_count - todelete; i < m_count; i++)
163            m_data[i].~Element();
164        m_count -= todelete;
165    }
166
167    inline void Empty()
168    {
169        Remove(0, m_count);
170    }
171
172    void Reserve(int toreserve)
173    {
174        if (toreserve <= (int)m_reserved)
175            return;
176
177        Element *tmp = reinterpret_cast<Element *>
178                               (new uint8_t [sizeof(Element) * toreserve]);
179        for (int i = 0; i < m_count; i++)
180        {
181            new(&tmp[i]) Element(m_data[i]);
182            m_data[i].~Element();
183        }
184        if (m_data)
185            delete[] reinterpret_cast<uint8_t *>(m_data);
186        m_data = tmp;
187        m_reserved = toreserve;
188    }
189
190    inline int Count() const { return m_count; }
191    inline int Bytes() const { return m_count * sizeof(Element); }
192
193protected:
194    Element *m_data;
195    int m_count, m_reserved;
196};
197
198/*
199 * Element types
200 */
201
202template<typename T1, typename T2, typename T3 = void, typename T4 = void,
203         typename T5 = void, typename T6 = void, typename T7 = void,
204         typename T8 = void>
205class ArrayElement
206{
207public:
208    T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6; T7 m7; T8 m8;
209};
210
211template<typename T1, typename T2, typename T3, typename T4, typename T5,
212         typename T6, typename T7>
213class ArrayElement<T1, T2, T3, T4, T5, T6, T7, void>
214{
215public:
216    T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6; T7 m7;
217};
218
219template<typename T1, typename T2, typename T3, typename T4, typename T5,
220         typename T6>
221class ArrayElement<T1, T2, T3, T4, T5, T6, void, void>
222{
223public:
224    T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6;
225};
226
227template<typename T1, typename T2, typename T3, typename T4, typename T5>
228class ArrayElement<T1, T2, T3, T4, T5, void, void, void>
229{
230public:
231    T1 m1; T2 m2; T3 m3; T4 m4; T5 m5;
232};
233
234template<typename T1, typename T2, typename T3, typename T4>
235class ArrayElement<T1, T2, T3, T4, void, void, void, void>
236{
237public:
238    T1 m1; T2 m2; T3 m3; T4 m4;
239};
240
241template<typename T1, typename T2, typename T3>
242class ArrayElement<T1, T2, T3, void, void, void, void, void>
243{
244public:
245    T1 m1; T2 m2; T3 m3;
246};
247
248template<typename T1, typename T2>
249class ArrayElement<T1, T2, void, void, void, void, void, void>
250{
251public:
252    T1 m1; T2 m2;
253};
254
255/*
256 * Array specialisations implementing specific setters
257 */
258
259template<typename T1, typename T2 = void, typename T3 = void,
260         typename T4 = void, typename T5 = void, typename T6 = void,
261         typename T7 = void, typename T8 = void>
262class Array : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, T7, T8>,
263                               Array<T1, T2, T3, T4, T5, T6, T7, T8> >
264{
265public:
266    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
267                     T5 const &m5, T6 const &m6, T7 const &m7, T8 const &m8)
268    {
269        if (this->m_count >= this->m_reserved)
270        {
271            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
272            T5 tmp5 = m5; T6 tmp6 = m6; T7 tmp7 = m7; T8 tmp8 = m8;
273            this->Reserve(this->m_count * 13 / 8 + 8);
274            this->m_data[this->m_count].m1 = tmp1;
275            this->m_data[this->m_count].m2 = tmp2;
276            this->m_data[this->m_count].m3 = tmp3;
277            this->m_data[this->m_count].m4 = tmp4;
278            this->m_data[this->m_count].m5 = tmp5;
279            this->m_data[this->m_count].m6 = tmp6;
280            this->m_data[this->m_count].m7 = tmp7;
281            this->m_data[this->m_count].m8 = tmp8;
282        }
283        else
284        {
285            this->m_data[this->m_count].m1 = m1;
286            this->m_data[this->m_count].m2 = m2;
287            this->m_data[this->m_count].m3 = m3;
288            this->m_data[this->m_count].m4 = m4;
289            this->m_data[this->m_count].m5 = m5;
290            this->m_data[this->m_count].m6 = m6;
291            this->m_data[this->m_count].m7 = m7;
292            this->m_data[this->m_count].m8 = m8;
293        }
294        ++this->m_count;
295    }
296};
297
298template<typename T1, typename T2, typename T3, typename T4, typename T5,
299         typename T6, typename T7>
300class Array<T1, T2, T3, T4, T5, T6, T7, void>
301  : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, T7, void>,
302                     Array<T1, T2, T3, T4, T5, T6, T7> >
303{
304public:
305    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
306                     T5 const &m5, T6 const &m6, T7 const &m7)
307    {
308        if (this->m_count >= this->m_reserved)
309        {
310            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
311            T5 tmp5 = m5; T6 tmp6 = m6; T7 tmp7 = m7;
312            this->Reserve(this->m_count * 13 / 8 + 8);
313            this->m_data[this->m_count].m1 = tmp1;
314            this->m_data[this->m_count].m2 = tmp2;
315            this->m_data[this->m_count].m3 = tmp3;
316            this->m_data[this->m_count].m4 = tmp4;
317            this->m_data[this->m_count].m5 = tmp5;
318            this->m_data[this->m_count].m6 = tmp6;
319            this->m_data[this->m_count].m7 = tmp7;
320        }
321        else
322        {
323            this->m_data[this->m_count].m1 = m1;
324            this->m_data[this->m_count].m2 = m2;
325            this->m_data[this->m_count].m3 = m3;
326            this->m_data[this->m_count].m4 = m4;
327            this->m_data[this->m_count].m5 = m5;
328            this->m_data[this->m_count].m6 = m6;
329            this->m_data[this->m_count].m7 = m7;
330        }
331        ++this->m_count;
332    }
333};
334
335template<typename T1, typename T2, typename T3, typename T4, typename T5,
336         typename T6>
337class Array<T1, T2, T3, T4, T5, T6, void, void>
338  : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, void, void>,
339                     Array<T1, T2, T3, T4, T5, T6> >
340{
341public:
342    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
343                     T5 const &m5, T6 const &m6)
344    {
345        if (this->m_count >= this->m_reserved)
346        {
347            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
348            T5 tmp5 = m5; T6 tmp6 = m6;
349            this->Reserve(this->m_count * 13 / 8 + 8);
350            this->m_data[this->m_count].m1 = tmp1;
351            this->m_data[this->m_count].m2 = tmp2;
352            this->m_data[this->m_count].m3 = tmp3;
353            this->m_data[this->m_count].m4 = tmp4;
354            this->m_data[this->m_count].m5 = tmp5;
355            this->m_data[this->m_count].m6 = tmp6;
356        }
357        else
358        {
359            this->m_data[this->m_count].m1 = m1;
360            this->m_data[this->m_count].m2 = m2;
361            this->m_data[this->m_count].m3 = m3;
362            this->m_data[this->m_count].m4 = m4;
363            this->m_data[this->m_count].m5 = m5;
364            this->m_data[this->m_count].m6 = m6;
365        }
366        ++this->m_count;
367    }
368};
369
370template<typename T1, typename T2, typename T3, typename T4, typename T5>
371class Array<T1, T2, T3, T4, T5, void, void, void>
372  : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, void, void, void>,
373                     Array<T1, T2, T3, T4, T5> >
374{
375public:
376    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
377                     T5 const &m5)
378    {
379        if (this->m_count >= this->m_reserved)
380        {
381            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
382            T5 tmp5 = m5;
383            this->Reserve(this->m_count * 13 / 8 + 8);
384            this->m_data[this->m_count].m1 = tmp1;
385            this->m_data[this->m_count].m2 = tmp2;
386            this->m_data[this->m_count].m3 = tmp3;
387            this->m_data[this->m_count].m4 = tmp4;
388            this->m_data[this->m_count].m5 = tmp5;
389        }
390        else
391        {
392            this->m_data[this->m_count].m1 = m1;
393            this->m_data[this->m_count].m2 = m2;
394            this->m_data[this->m_count].m3 = m3;
395            this->m_data[this->m_count].m4 = m4;
396            this->m_data[this->m_count].m5 = m5;
397        }
398        ++this->m_count;
399    }
400};
401
402template<typename T1, typename T2, typename T3, typename T4>
403class Array<T1, T2, T3, T4, void, void, void, void>
404  : public ArrayBase<ArrayElement<T1, T2, T3, T4, void, void, void, void>,
405                     Array<T1, T2, T3, T4> >
406{
407public:
408    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4)
409    {
410        if (this->m_count >= this->m_reserved)
411        {
412            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
413            this->Reserve(this->m_count * 13 / 8 + 8);
414            this->m_data[this->m_count].m1 = tmp1;
415            this->m_data[this->m_count].m2 = tmp2;
416            this->m_data[this->m_count].m3 = tmp3;
417            this->m_data[this->m_count].m4 = tmp4;
418        }
419        else
420        {
421            this->m_data[this->m_count].m1 = m1;
422            this->m_data[this->m_count].m2 = m2;
423            this->m_data[this->m_count].m3 = m3;
424            this->m_data[this->m_count].m4 = m4;
425        }
426        ++this->m_count;
427    }
428};
429
430template<typename T1, typename T2, typename T3>
431class Array<T1, T2, T3, void, void, void, void, void>
432  : public ArrayBase<ArrayElement<T1, T2, T3, void, void, void, void, void>,
433                     Array<T1, T2, T3> >
434{
435public:
436    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3)
437    {
438        if (this->m_count >= this->m_reserved)
439        {
440            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3;
441            this->Reserve(this->m_count * 13 / 8 + 8);
442            this->m_data[this->m_count].m1 = tmp1;
443            this->m_data[this->m_count].m2 = tmp2;
444            this->m_data[this->m_count].m3 = tmp3;
445        }
446        else
447        {
448            this->m_data[this->m_count].m1 = m1;
449            this->m_data[this->m_count].m2 = m2;
450            this->m_data[this->m_count].m3 = m3;
451        }
452        ++this->m_count;
453    }
454};
455
456template<typename T1, typename T2>
457class Array<T1, T2, void, void, void, void, void, void>
458  : public ArrayBase<ArrayElement<T1, T2, void, void, void, void, void, void>,
459                     Array<T1, T2> >
460{
461public:
462    inline void Push(T1 const &m1, T2 const &m2)
463    {
464        if (this->m_count >= this->m_reserved)
465        {
466            T1 tmp1 = m1; T2 tmp2 = m2;
467            this->Reserve(this->m_count * 13 / 8 + 8);
468            this->m_data[this->m_count].m1 = tmp1;
469            this->m_data[this->m_count].m2 = tmp2;
470        }
471        else
472        {
473            this->m_data[this->m_count].m1 = m1;
474            this->m_data[this->m_count].m2 = m2;
475        }
476        ++this->m_count;
477    }
478};
479
480template<typename T>
481class Array<T, void, void, void, void, void, void, void>
482  : public ArrayBase<T,
483                     Array<T> >
484{
485};
486
487} /* namespace lol */
488
489#endif // __LOL_ARRAY_H__
490
Note: See TracBrowser for help on using the repository browser.