aboutsummaryrefslogtreecommitdiff
path: root/dep/CascLib/src/common/Array.h
blob: 1dc96b7be8e956c5c35152b9d929081da2bc58dc (plain)
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*****************************************************************************/
/* Array.h                                Copyright (c) Ladislav Zezula 2015 */
/*---------------------------------------------------------------------------*/
/* Common array implementation                                               */
/*---------------------------------------------------------------------------*/
/*   Date    Ver   Who  Comment                                              */
/* --------  ----  ---  -------                                              */
/* 30.10.15  1.00  Lad  The first version of DynamicArray.h                  */
/* 10.08.18  1.00  Lad  CLASS-ified, renamed to Array.h                      */
/*****************************************************************************/

#ifndef __CASC_ARRAY_H__
#define __CASC_ARRAY_H__

//-----------------------------------------------------------------------------
// Structures

class CASC_ARRAY
{
    public:

    CASC_ARRAY()
    {
        m_pItemArray = NULL;
        m_ItemCountMax = 0;
        m_ItemCount = 0;
        m_ItemSize = 0;
    }

    ~CASC_ARRAY()
    {
        Free();
    }

    // Creates an array with a custom element type
    template<typename TYPE>
    int Create(size_t ItemCountMax)
    {
        return Create(sizeof(TYPE), ItemCountMax);
    }

    // Creates an array with a custom element size
    int Create(size_t ItemSize, size_t ItemCountMax)
    {
        // Create the array
        if ((m_pItemArray = CASC_ALLOC(BYTE, ItemSize * ItemCountMax)) == NULL)
            return ERROR_NOT_ENOUGH_MEMORY;

        m_ItemCountMax = ItemCountMax;
        m_ItemCount = 0;
        m_ItemSize = ItemSize;
        return ERROR_SUCCESS;
    }

    // Inserts one or more items; returns pointer to the first inserted item
    void * Insert(size_t NewItemCount)
    {
        void * pNewItems;

        // Try to enlarge the buffer, if needed
        if (!EnlargeArray(m_ItemCount + NewItemCount))
            return NULL;
        pNewItems = m_pItemArray + (m_ItemCount * m_ItemSize);

        // Increment the size of the array
        m_ItemCount += NewItemCount;

        // Return pointer to the new item
        return pNewItems;
    }

    // Inserts one or more items; returns pointer to the first inserted item
    void * Insert(const void * NewItems, size_t NewItemCount)
    {
        void * pNewItem = Insert(NewItemCount);

        // Copy the item(s) to the array, if any
        if (pNewItem && NewItems)
            memcpy(pNewItem, NewItems, (NewItemCount * m_ItemSize));
        return pNewItem;
    }

    // Returns an item at a given index
    void * ItemAt(size_t ItemIndex)
    {
        return (ItemIndex < m_ItemCount) ? (m_pItemArray + (ItemIndex * m_ItemSize)) : NULL;
    }

    void * LastItem()
    {
        return m_pItemArray + (m_ItemCount * m_ItemSize);
    }

    // Inserts an item at a given index. If there is not enough items in the array,
    // the array will be enlarged. Should any gaps to be created, the function will zero them
    void * InsertAt(size_t ItemIndex)
    {
        LPBYTE pbLastItem;
        LPBYTE pbNewItem;

        // Make sure we have array large enough
        if(!EnlargeArray(ItemIndex + 1))
            return NULL;
        
        // Get the items range
        pbLastItem = m_pItemArray + (m_ItemCount * m_ItemSize);
        pbNewItem = m_pItemArray + (ItemIndex * m_ItemSize);
        m_ItemCount = CASCLIB_MAX(m_ItemCount, ItemIndex+1);

        // If we inserted an item past the current end, we need to clear the items in-between
        if (pbNewItem > pbLastItem)
        {
            memset(pbLastItem, 0, (pbNewItem - pbLastItem));
            m_ItemCount = ItemIndex + 1;
        }

        return pbNewItem;
    }

    // Returns index of an item
    size_t IndexOf(const void * pItem)
    {
        LPBYTE pbItem = (LPBYTE)pItem;

        assert((m_pItemArray <= pbItem) && (pbItem <= m_pItemArray + (m_ItemCount * m_ItemSize)));
        assert(((pbItem - m_pItemArray) % m_ItemSize) == 0);

        return ((pbItem - m_pItemArray) / m_ItemSize);
     }

    void * ItemArray()
    {
        return m_pItemArray;
    }

    size_t ItemCount()
    {
        return m_ItemCount;
    }

    size_t ItemCountMax()
    {
        return m_ItemCountMax;
    }

    size_t ItemSize()
    {
        return m_ItemSize;
    }

    bool IsInitialized()
    {
        return (m_pItemArray && m_ItemCountMax);
    }

    // Invalidates the entire array, but keeps memory allocated
    void Reset()
    {
        memset(m_pItemArray, 0, m_ItemCountMax * m_ItemSize);
        m_ItemCount = 0;
    }

    // Frees the array
    void Free()
    {
        CASC_FREE(m_pItemArray);
        m_ItemCountMax = m_ItemCount = m_ItemSize = 0;
    }

    protected:

    bool EnlargeArray(size_t NewItemCount)
    {
        LPBYTE NewItemArray;
        size_t ItemCountMax;

        // We expect the array to be already allocated
        assert(m_pItemArray != NULL);
        assert(m_ItemCountMax != 0);

        // Shall we enlarge the table?
        if (NewItemCount > m_ItemCountMax)
        {
            // Calculate new table size
            ItemCountMax = m_ItemCountMax;
            while (ItemCountMax < NewItemCount)
                ItemCountMax = ItemCountMax << 1;

            // Allocate new table
            NewItemArray = CASC_REALLOC(BYTE, m_pItemArray, (ItemCountMax * m_ItemSize));
            if (NewItemArray == NULL)
                return false;

            // Set the new table size
            m_ItemCountMax = ItemCountMax;
            m_pItemArray = NewItemArray;
        }

        return true;
    }

    LPBYTE m_pItemArray;                        // Pointer to item array
    size_t m_ItemCountMax;                      // Maximum item count
    size_t m_ItemCount;                         // Current item count
    size_t m_ItemSize;                          // Size of an item
};

#endif // __CASC_ARRAY__