source: trunk/src/array.h @ 1328

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

core: the Array class now properly works with non-POD types.

  • Property svn:keywords set to Id
File size: 13.2 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> 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    inline Element& operator[](int n)
91    {
92        return m_data[n];
93    }
94
95    inline Element const& operator[](int n) const
96    {
97        return m_data[n];
98    }
99
100    inline ArrayBase<T> const& operator<<(T const &x)
101    {
102        if (m_count >= m_reserved)
103        {
104            T tmp = x;
105            Reserve(m_count * 13 / 8 + 8);
106            new (&m_data[m_count++]) Element(tmp);
107        }
108        else
109        {
110            new (&m_data[m_count++]) Element(x);
111        }
112        return *this;
113    }
114
115    inline void Push(T const &x)
116    {
117        *this << x;
118    }
119
120    void Remove(int pos, int todelete = 1)
121    {
122        for (int i = pos; i + todelete < m_count; i++)
123            m_data[i] = m_data[i + todelete];
124        for (int i = m_count - todelete; i < m_count; i++)
125            m_data[i].~Element();
126        m_count -= todelete;
127    }
128
129    void Reserve(int toreserve)
130    {
131        if (toreserve <= (int)m_reserved)
132            return;
133
134        Element *tmp = reinterpret_cast<Element *>
135                               (new uint8_t [sizeof(Element) * toreserve]);
136        for (int i = 0; i < m_count; i++)
137        {
138            new(&tmp[i]) Element(m_data[i]);
139            m_data[i].~Element();
140        }
141        if (m_data)
142            delete[] reinterpret_cast<uint8_t *>(m_data);
143        m_data = tmp;
144        m_reserved = toreserve;
145    }
146
147    inline int Count() const { return m_count; }
148    inline int Bytes() const { return m_count * sizeof(Element); }
149
150protected:
151    Element *m_data;
152    int m_count, m_reserved;
153};
154
155/*
156 * Element types
157 */
158
159template<typename T1, typename T2, typename T3 = void, typename T4 = void,
160         typename T5 = void, typename T6 = void, typename T7 = void,
161         typename T8 = void>
162class ArrayElement
163{
164public:
165    T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6; T7 m7; T8 m8;
166};
167
168template<typename T1, typename T2, typename T3, typename T4, typename T5,
169         typename T6, typename T7>
170class ArrayElement<T1, T2, T3, T4, T5, T6, T7, void>
171{
172public:
173    T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6; T7 m7;
174};
175
176template<typename T1, typename T2, typename T3, typename T4, typename T5,
177         typename T6>
178class ArrayElement<T1, T2, T3, T4, T5, T6, void, void>
179{
180public:
181    T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6;
182};
183
184template<typename T1, typename T2, typename T3, typename T4, typename T5>
185class ArrayElement<T1, T2, T3, T4, T5, void, void, void>
186{
187public:
188    T1 m1; T2 m2; T3 m3; T4 m4; T5 m5;
189};
190
191template<typename T1, typename T2, typename T3, typename T4>
192class ArrayElement<T1, T2, T3, T4, void, void, void, void>
193{
194public:
195    T1 m1; T2 m2; T3 m3; T4 m4;
196};
197
198template<typename T1, typename T2, typename T3>
199class ArrayElement<T1, T2, T3, void, void, void, void, void>
200{
201public:
202    T1 m1; T2 m2; T3 m3;
203};
204
205template<typename T1, typename T2>
206class ArrayElement<T1, T2, void, void, void, void, void, void>
207{
208public:
209    T1 m1; T2 m2;
210};
211
212/*
213 * Array specialisations implementing specific setters
214 */
215
216template<typename T1, typename T2 = void, typename T3 = void,
217         typename T4 = void, typename T5 = void, typename T6 = void,
218         typename T7 = void, typename T8 = void>
219class Array : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, T7, T8> >
220{
221public:
222    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
223                     T5 const &m5, T6 const &m6, T7 const &m7, T8 const &m8)
224    {
225        if (this->m_count >= this->m_reserved)
226        {
227            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
228            T5 tmp5 = m5; T6 tmp6 = m6; T7 tmp7 = m7; T8 tmp8 = m8;
229            Reserve(this->m_count * 13 / 8 + 8);
230            this->m_data[this->m_count].m1 = tmp1;
231            this->m_data[this->m_count].m2 = tmp2;
232            this->m_data[this->m_count].m3 = tmp3;
233            this->m_data[this->m_count].m4 = tmp4;
234            this->m_data[this->m_count].m5 = tmp5;
235            this->m_data[this->m_count].m6 = tmp6;
236            this->m_data[this->m_count].m7 = tmp7;
237            this->m_data[this->m_count].m8 = tmp8;
238        }
239        else
240        {
241            this->m_data[this->m_count].m1 = m1;
242            this->m_data[this->m_count].m2 = m2;
243            this->m_data[this->m_count].m3 = m3;
244            this->m_data[this->m_count].m4 = m4;
245            this->m_data[this->m_count].m5 = m5;
246            this->m_data[this->m_count].m6 = m6;
247            this->m_data[this->m_count].m7 = m7;
248            this->m_data[this->m_count].m8 = m8;
249        }
250        ++this->m_count;
251    }
252};
253
254template<typename T1, typename T2, typename T3, typename T4, typename T5,
255         typename T6, typename T7>
256class Array<T1, T2, T3, T4, T5, T6, T7, void>
257  : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, T7, void> >
258{
259public:
260    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
261                     T5 const &m5, T6 const &m6, T7 const &m7)
262    {
263        if (this->m_count >= this->m_reserved)
264        {
265            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
266            T5 tmp5 = m5; T6 tmp6 = m6; T7 tmp7 = m7;
267            Reserve(this->m_count * 13 / 8 + 8);
268            this->m_data[this->m_count].m1 = tmp1;
269            this->m_data[this->m_count].m2 = tmp2;
270            this->m_data[this->m_count].m3 = tmp3;
271            this->m_data[this->m_count].m4 = tmp4;
272            this->m_data[this->m_count].m5 = tmp5;
273            this->m_data[this->m_count].m6 = tmp6;
274            this->m_data[this->m_count].m7 = tmp7;
275        }
276        else
277        {
278            this->m_data[this->m_count].m1 = m1;
279            this->m_data[this->m_count].m2 = m2;
280            this->m_data[this->m_count].m3 = m3;
281            this->m_data[this->m_count].m4 = m4;
282            this->m_data[this->m_count].m5 = m5;
283            this->m_data[this->m_count].m6 = m6;
284            this->m_data[this->m_count].m7 = m7;
285        }
286        ++this->m_count;
287    }
288};
289
290template<typename T1, typename T2, typename T3, typename T4, typename T5,
291         typename T6>
292class Array<T1, T2, T3, T4, T5, T6, void, void>
293  : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, void, void> >
294{
295public:
296    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
297                     T5 const &m5, T6 const &m6)
298    {
299        if (this->m_count >= this->m_reserved)
300        {
301            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
302            T5 tmp5 = m5; T6 tmp6 = m6;
303            Reserve(this->m_count * 13 / 8 + 8);
304            this->m_data[this->m_count].m1 = tmp1;
305            this->m_data[this->m_count].m2 = tmp2;
306            this->m_data[this->m_count].m3 = tmp3;
307            this->m_data[this->m_count].m4 = tmp4;
308            this->m_data[this->m_count].m5 = tmp5;
309            this->m_data[this->m_count].m6 = tmp6;
310        }
311        else
312        {
313            this->m_data[this->m_count].m1 = m1;
314            this->m_data[this->m_count].m2 = m2;
315            this->m_data[this->m_count].m3 = m3;
316            this->m_data[this->m_count].m4 = m4;
317            this->m_data[this->m_count].m5 = m5;
318            this->m_data[this->m_count].m6 = m6;
319        }
320        ++this->m_count;
321    }
322};
323
324template<typename T1, typename T2, typename T3, typename T4, typename T5>
325class Array<T1, T2, T3, T4, T5, void, void, void>
326  : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, void, void, void> >
327{
328public:
329    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
330                     T5 const &m5)
331    {
332        if (this->m_count >= this->m_reserved)
333        {
334            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
335            T5 tmp5 = m5;
336            Reserve(this->m_count * 13 / 8 + 8);
337            this->m_data[this->m_count].m1 = tmp1;
338            this->m_data[this->m_count].m2 = tmp2;
339            this->m_data[this->m_count].m3 = tmp3;
340            this->m_data[this->m_count].m4 = tmp4;
341            this->m_data[this->m_count].m5 = tmp5;
342        }
343        else
344        {
345            this->m_data[this->m_count].m1 = m1;
346            this->m_data[this->m_count].m2 = m2;
347            this->m_data[this->m_count].m3 = m3;
348            this->m_data[this->m_count].m4 = m4;
349            this->m_data[this->m_count].m5 = m5;
350        }
351        ++this->m_count;
352    }
353};
354
355template<typename T1, typename T2, typename T3, typename T4>
356class Array<T1, T2, T3, T4, void, void, void, void>
357  : public ArrayBase<ArrayElement<T1, T2, T3, T4, void, void, void, void> >
358{
359public:
360    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4)
361    {
362        if (this->m_count >= this->m_reserved)
363        {
364            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
365            Reserve(this->m_count * 13 / 8 + 8);
366            this->m_data[this->m_count].m1 = tmp1;
367            this->m_data[this->m_count].m2 = tmp2;
368            this->m_data[this->m_count].m3 = tmp3;
369            this->m_data[this->m_count].m4 = tmp4;
370        }
371        else
372        {
373            this->m_data[this->m_count].m1 = m1;
374            this->m_data[this->m_count].m2 = m2;
375            this->m_data[this->m_count].m3 = m3;
376            this->m_data[this->m_count].m4 = m4;
377        }
378        ++this->m_count;
379    }
380};
381
382template<typename T1, typename T2, typename T3>
383class Array<T1, T2, T3, void, void, void, void, void>
384  : public ArrayBase<ArrayElement<T1, T2, T3, void, void, void, void, void> >
385{
386public:
387    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3)
388    {
389        if (this->m_count >= this->m_reserved)
390        {
391            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3;
392            Reserve(this->m_count * 13 / 8 + 8);
393            this->m_data[this->m_count].m1 = tmp1;
394            this->m_data[this->m_count].m2 = tmp2;
395            this->m_data[this->m_count].m3 = tmp3;
396        }
397        else
398        {
399            this->m_data[this->m_count].m1 = m1;
400            this->m_data[this->m_count].m2 = m2;
401            this->m_data[this->m_count].m3 = m3;
402        }
403        ++this->m_count;
404    }
405};
406
407template<typename T1, typename T2>
408class Array<T1, T2, void, void, void, void, void, void>
409  : public ArrayBase<ArrayElement<T1, T2, void, void, void, void, void, void> >
410{
411public:
412    inline void Push(T1 const &m1, T2 const &m2)
413    {
414        if (this->m_count >= this->m_reserved)
415        {
416            T1 tmp1 = m1; T2 tmp2 = m2;
417            Reserve(this->m_count * 13 / 8 + 8);
418            this->m_data[this->m_count].m1 = tmp1;
419            this->m_data[this->m_count].m2 = tmp2;
420        }
421        else
422        {
423            this->m_data[this->m_count].m1 = m1;
424            this->m_data[this->m_count].m2 = m2;
425        }
426        ++this->m_count;
427    }
428};
429
430template<typename T>
431class Array<T, void, void, void, void, void, void, void> : public ArrayBase<T>
432{
433};
434
435} /* namespace lol */
436
437#endif // __LOL_ARRAY_H__
438
Note: See TracBrowser for help on using the repository browser.