source: trunk/src/lol/core/array.h @ 2086

Last change on this file since 2086 was 2086, checked in by sam, 7 years ago

core: new String class.

  • Property svn:keywords set to Id
File size: 15.3 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        /* FIXME: we need to call dtors for the first
161         * todelete elements here */
162        for (int i = pos; i + todelete < m_count; i++)
163            m_data[i] = m_data[i + todelete];
164        for (int i = m_count - todelete; i < m_count; i++)
165            m_data[i].~Element();
166        m_count -= todelete;
167    }
168
169    void Resize(int count, Element e = Element())
170    {
171        Reserve(count);
172
173        /* Too many elements? Remove them. */
174        for (int i = count; i < m_count; ++i)
175            m_data[i].~Element();
176
177        /* Not enough elements? Add some. */
178        for (int i = m_count; i < count; ++i)
179            m_data[i] = e;
180
181        m_count = count;
182    }
183
184    inline void Empty()
185    {
186        Remove(0, m_count);
187    }
188
189    void Reserve(int toreserve)
190    {
191        if (toreserve <= (int)m_reserved)
192            return;
193
194        /* This cast is not very nice, because we kill any alignment
195         * information we could have. But until C++ gives us the proper
196         * tools to deal with it, we assume new uint8_t[] returns properly
197         * aligned data. */
198        Element *tmp = reinterpret_cast<Element *>(reinterpret_cast<uintptr_t>
199                               (new uint8_t[sizeof(Element) * toreserve]));
200        for (int i = 0; i < m_count; i++)
201        {
202            new(&tmp[i]) Element(m_data[i]);
203            m_data[i].~Element();
204        }
205        if (m_data)
206            delete[] reinterpret_cast<uint8_t *>(m_data);
207        m_data = tmp;
208        m_reserved = toreserve;
209    }
210
211    inline int Count() const { return m_count; }
212    inline int Bytes() const { return m_count * sizeof(Element); }
213
214protected:
215    Element *m_data;
216    int m_count, m_reserved;
217};
218
219/*
220 * Element types
221 */
222
223template<typename T1, typename T2, typename T3 = void, typename T4 = void,
224         typename T5 = void, typename T6 = void, typename T7 = void,
225         typename T8 = void>
226class ArrayElement
227{
228public:
229    T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6; T7 m7; T8 m8;
230};
231
232template<typename T1, typename T2, typename T3, typename T4, typename T5,
233         typename T6, typename T7>
234class ArrayElement<T1, T2, T3, T4, T5, T6, T7, void>
235{
236public:
237    T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6; T7 m7;
238};
239
240template<typename T1, typename T2, typename T3, typename T4, typename T5,
241         typename T6>
242class ArrayElement<T1, T2, T3, T4, T5, T6, void, void>
243{
244public:
245    T1 m1; T2 m2; T3 m3; T4 m4; T5 m5; T6 m6;
246};
247
248template<typename T1, typename T2, typename T3, typename T4, typename T5>
249class ArrayElement<T1, T2, T3, T4, T5, void, void, void>
250{
251public:
252    T1 m1; T2 m2; T3 m3; T4 m4; T5 m5;
253};
254
255template<typename T1, typename T2, typename T3, typename T4>
256class ArrayElement<T1, T2, T3, T4, void, void, void, void>
257{
258public:
259    T1 m1; T2 m2; T3 m3; T4 m4;
260};
261
262template<typename T1, typename T2, typename T3>
263class ArrayElement<T1, T2, T3, void, void, void, void, void>
264{
265public:
266    T1 m1; T2 m2; T3 m3;
267};
268
269template<typename T1, typename T2>
270class ArrayElement<T1, T2, void, void, void, void, void, void>
271{
272public:
273    T1 m1; T2 m2;
274};
275
276/*
277 * Array specialisations implementing specific setters
278 */
279
280template<typename T1, typename T2 = void, typename T3 = void,
281         typename T4 = void, typename T5 = void, typename T6 = void,
282         typename T7 = void, typename T8 = void>
283class Array : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, T7, T8>,
284                               Array<T1, T2, T3, T4, T5, T6, T7, T8> >
285{
286public:
287    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
288                     T5 const &m5, T6 const &m6, T7 const &m7, T8 const &m8)
289    {
290        if (this->m_count >= this->m_reserved)
291        {
292            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
293            T5 tmp5 = m5; T6 tmp6 = m6; T7 tmp7 = m7; T8 tmp8 = m8;
294            this->Reserve(this->m_count * 13 / 8 + 8);
295            this->m_data[this->m_count].m1 = tmp1;
296            this->m_data[this->m_count].m2 = tmp2;
297            this->m_data[this->m_count].m3 = tmp3;
298            this->m_data[this->m_count].m4 = tmp4;
299            this->m_data[this->m_count].m5 = tmp5;
300            this->m_data[this->m_count].m6 = tmp6;
301            this->m_data[this->m_count].m7 = tmp7;
302            this->m_data[this->m_count].m8 = tmp8;
303        }
304        else
305        {
306            this->m_data[this->m_count].m1 = m1;
307            this->m_data[this->m_count].m2 = m2;
308            this->m_data[this->m_count].m3 = m3;
309            this->m_data[this->m_count].m4 = m4;
310            this->m_data[this->m_count].m5 = m5;
311            this->m_data[this->m_count].m6 = m6;
312            this->m_data[this->m_count].m7 = m7;
313            this->m_data[this->m_count].m8 = m8;
314        }
315        ++this->m_count;
316    }
317};
318
319template<typename T1, typename T2, typename T3, typename T4, typename T5,
320         typename T6, typename T7>
321class Array<T1, T2, T3, T4, T5, T6, T7, void>
322  : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, T7, void>,
323                     Array<T1, T2, T3, T4, T5, T6, T7> >
324{
325public:
326    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
327                     T5 const &m5, T6 const &m6, T7 const &m7)
328    {
329        if (this->m_count >= this->m_reserved)
330        {
331            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
332            T5 tmp5 = m5; T6 tmp6 = m6; T7 tmp7 = m7;
333            this->Reserve(this->m_count * 13 / 8 + 8);
334            this->m_data[this->m_count].m1 = tmp1;
335            this->m_data[this->m_count].m2 = tmp2;
336            this->m_data[this->m_count].m3 = tmp3;
337            this->m_data[this->m_count].m4 = tmp4;
338            this->m_data[this->m_count].m5 = tmp5;
339            this->m_data[this->m_count].m6 = tmp6;
340            this->m_data[this->m_count].m7 = tmp7;
341        }
342        else
343        {
344            this->m_data[this->m_count].m1 = m1;
345            this->m_data[this->m_count].m2 = m2;
346            this->m_data[this->m_count].m3 = m3;
347            this->m_data[this->m_count].m4 = m4;
348            this->m_data[this->m_count].m5 = m5;
349            this->m_data[this->m_count].m6 = m6;
350            this->m_data[this->m_count].m7 = m7;
351        }
352        ++this->m_count;
353    }
354};
355
356template<typename T1, typename T2, typename T3, typename T4, typename T5,
357         typename T6>
358class Array<T1, T2, T3, T4, T5, T6, void, void>
359  : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, T6, void, void>,
360                     Array<T1, T2, T3, T4, T5, T6> >
361{
362public:
363    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
364                     T5 const &m5, T6 const &m6)
365    {
366        if (this->m_count >= this->m_reserved)
367        {
368            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
369            T5 tmp5 = m5; T6 tmp6 = m6;
370            this->Reserve(this->m_count * 13 / 8 + 8);
371            this->m_data[this->m_count].m1 = tmp1;
372            this->m_data[this->m_count].m2 = tmp2;
373            this->m_data[this->m_count].m3 = tmp3;
374            this->m_data[this->m_count].m4 = tmp4;
375            this->m_data[this->m_count].m5 = tmp5;
376            this->m_data[this->m_count].m6 = tmp6;
377        }
378        else
379        {
380            this->m_data[this->m_count].m1 = m1;
381            this->m_data[this->m_count].m2 = m2;
382            this->m_data[this->m_count].m3 = m3;
383            this->m_data[this->m_count].m4 = m4;
384            this->m_data[this->m_count].m5 = m5;
385            this->m_data[this->m_count].m6 = m6;
386        }
387        ++this->m_count;
388    }
389};
390
391template<typename T1, typename T2, typename T3, typename T4, typename T5>
392class Array<T1, T2, T3, T4, T5, void, void, void>
393  : public ArrayBase<ArrayElement<T1, T2, T3, T4, T5, void, void, void>,
394                     Array<T1, T2, T3, T4, T5> >
395{
396public:
397    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4,
398                     T5 const &m5)
399    {
400        if (this->m_count >= this->m_reserved)
401        {
402            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
403            T5 tmp5 = m5;
404            this->Reserve(this->m_count * 13 / 8 + 8);
405            this->m_data[this->m_count].m1 = tmp1;
406            this->m_data[this->m_count].m2 = tmp2;
407            this->m_data[this->m_count].m3 = tmp3;
408            this->m_data[this->m_count].m4 = tmp4;
409            this->m_data[this->m_count].m5 = tmp5;
410        }
411        else
412        {
413            this->m_data[this->m_count].m1 = m1;
414            this->m_data[this->m_count].m2 = m2;
415            this->m_data[this->m_count].m3 = m3;
416            this->m_data[this->m_count].m4 = m4;
417            this->m_data[this->m_count].m5 = m5;
418        }
419        ++this->m_count;
420    }
421};
422
423template<typename T1, typename T2, typename T3, typename T4>
424class Array<T1, T2, T3, T4, void, void, void, void>
425  : public ArrayBase<ArrayElement<T1, T2, T3, T4, void, void, void, void>,
426                     Array<T1, T2, T3, T4> >
427{
428public:
429    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3, T4 const &m4)
430    {
431        if (this->m_count >= this->m_reserved)
432        {
433            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3; T4 tmp4 = m4;
434            this->Reserve(this->m_count * 13 / 8 + 8);
435            this->m_data[this->m_count].m1 = tmp1;
436            this->m_data[this->m_count].m2 = tmp2;
437            this->m_data[this->m_count].m3 = tmp3;
438            this->m_data[this->m_count].m4 = tmp4;
439        }
440        else
441        {
442            this->m_data[this->m_count].m1 = m1;
443            this->m_data[this->m_count].m2 = m2;
444            this->m_data[this->m_count].m3 = m3;
445            this->m_data[this->m_count].m4 = m4;
446        }
447        ++this->m_count;
448    }
449};
450
451template<typename T1, typename T2, typename T3>
452class Array<T1, T2, T3, void, void, void, void, void>
453  : public ArrayBase<ArrayElement<T1, T2, T3, void, void, void, void, void>,
454                     Array<T1, T2, T3> >
455{
456public:
457    inline void Push(T1 const &m1, T2 const &m2, T3 const &m3)
458    {
459        if (this->m_count >= this->m_reserved)
460        {
461            T1 tmp1 = m1; T2 tmp2 = m2; T3 tmp3 = m3;
462            this->Reserve(this->m_count * 13 / 8 + 8);
463            this->m_data[this->m_count].m1 = tmp1;
464            this->m_data[this->m_count].m2 = tmp2;
465            this->m_data[this->m_count].m3 = tmp3;
466        }
467        else
468        {
469            this->m_data[this->m_count].m1 = m1;
470            this->m_data[this->m_count].m2 = m2;
471            this->m_data[this->m_count].m3 = m3;
472        }
473        ++this->m_count;
474    }
475};
476
477template<typename T1, typename T2>
478class Array<T1, T2, void, void, void, void, void, void>
479  : public ArrayBase<ArrayElement<T1, T2, void, void, void, void, void, void>,
480                     Array<T1, T2> >
481{
482public:
483    inline void Push(T1 const &m1, T2 const &m2)
484    {
485        if (this->m_count >= this->m_reserved)
486        {
487            T1 tmp1 = m1; T2 tmp2 = m2;
488            this->Reserve(this->m_count * 13 / 8 + 8);
489            this->m_data[this->m_count].m1 = tmp1;
490            this->m_data[this->m_count].m2 = tmp2;
491        }
492        else
493        {
494            this->m_data[this->m_count].m1 = m1;
495            this->m_data[this->m_count].m2 = m2;
496        }
497        ++this->m_count;
498    }
499};
500
501template<typename T>
502class Array<T, void, void, void, void, void, void, void>
503  : public ArrayBase<T,
504                     Array<T> >
505{
506};
507
508} /* namespace lol */
509
510#endif // __LOL_ARRAY_H__
511
Note: See TracBrowser for help on using the repository browser.