summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/fixedvector.h
blob: 81221b15eb1ae88f3f943ff94d87ddf8a1a1942c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/**
 * @file
 * @brief Fixed size vector class that asserts if you do something bad.
**/

#ifndef FIXVEC_H
#define FIXVEC_H

#include <cstdarg>
#include <cstring>

// ==========================================================================
//    class FixedVector
// ==========================================================================

template <class TYPE, int SIZE> class FixedVector
{

//-----------------------------------
//    Types
//
public:
    typedef TYPE            value_type;
    typedef TYPE&           reference;
    typedef const TYPE&     const_reference;
    typedef TYPE*           pointer;
    typedef const TYPE*     const_pointer;

    typedef unsigned long   size_type;
    typedef long            difference_type;

    typedef TYPE*           iterator;
    typedef const TYPE*     const_iterator;

//-----------------------------------
//    Initialization/Destruction
//
public:
    ~FixedVector()                           {}

    FixedVector()                            {}

    FixedVector(TYPE def) : mData()
    {
        init(def);
    }

    FixedVector(TYPE value0, TYPE value1, ...);
    // Allows for something resembling C array initialization, eg
    // instead of "int a[3] = {0, 1, 2}" you'd use "FixedVector<int, 3>
    // a(0, 1, 2)". Note that there must be SIZE arguments.

//-----------------------------------
//    API
//
public:
    // ----- Size -----
    bool empty() const { return SIZE == 0; }
    size_t size() const { return SIZE; }

    // ----- Access -----
    TYPE& operator[](unsigned long index)
    {
#ifdef ASSERTS
        if (index >= SIZE)
        {
            // Intentionally printed as signed, it's very, very unlikely we'd
            // have a genuine big number here, but underflows are common.
            die_noline("range check error (%ld / %d)", (signed long)index,
                SIZE);
        }
#endif
        return mData[index];
    }

    const TYPE& operator[](unsigned long index) const
    {
#ifdef ASSERTS
        if (index >= SIZE)
        {
            die_noline("range check error (%ld / %d)", (signed long)index,
                SIZE);
        }
#endif
        return mData[index];
    }

    const TYPE* buffer() const { return mData; }
    TYPE* buffer() { return mData; }

    // ----- Iterating -----
    iterator begin() { return mData; }
    const_iterator begin() const { return mData; }

    iterator end() { return begin() + size(); }
    const_iterator end() const { return begin() + size(); }
    void init(const TYPE& def);

//-----------------------------------
//    Member Data
//
protected:
    TYPE    mData[SIZE];
};

// ==========================================================================
//    Outlined Methods
// ==========================================================================
template <class TYPE, int SIZE>
FixedVector<TYPE, SIZE>::FixedVector(TYPE value0, TYPE value1, ...)
{
    mData[0] = value0;
    mData[1] = value1;

    va_list ap;
    va_start(ap, value1);   // second argument is last fixed parameter

    for (int index = 2; index < SIZE; index++)
    {
        TYPE value = va_arg(ap, TYPE);
        mData[index] = value;
    }

    va_end(ap);
}

template <class TYPE, int SIZE>
void FixedVector<TYPE, SIZE>::init(const TYPE& def)
{
    for (int i = 0; i < SIZE; ++i)
        mData[i] = def;
}

#endif    // FIXVEC_H