-
Notifications
You must be signed in to change notification settings - Fork 1
/
vector.h
269 lines (209 loc) · 8.33 KB
/
vector.h
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/*
* Vector.h
*
* Created on: 05/04/2012
* Author: tom
* Purpose: To play the part of a mutable array in the absence of the STL.
*/
#ifndef VECTOR_H
#define VECTOR_H
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
#define SWAP(type, a, b) type tmp ## a = a; a = b; b = tmp ## a;
template <class ParameterType> class Predicate
{
public:
virtual void operator() (ParameterType ¶m) = 0;
};
template <class VectorType> class Vector
{
// The address of the first element of the vector
VectorType *begin;
// The address one after the last allocated entry in the underlying array
VectorType *storage;
// The index of the most recent element put in the underlying array - the head
int head;
public:
// The value that is returned when the caller asks for an element that is out of the bounds of the vector
VectorType OB;
// We can save a few re-sizings if we know how large the array is likely to grow to be
Vector(int initialSize = 0)
{
begin = new VectorType[initialSize]; //points to the beginning of the new array
head = initialSize - 1;
storage = begin + initialSize; //points to the element one outside of the array (such that end - begin = capacity)
}
Vector(Vector &obj)
{
begin = new VectorType[0]; // Points to the beginning of the new array, it's zero but this line keeps malloc from seg faulting should we delete begin before resizing it
head = -1;
storage = begin; //points to the element one outside of the array (such that end - begin = capacity)
*this = obj;
}
// If there's anything in the vector then delete the array, if there's no array then doing will will cause seg faults
virtual ~Vector() { delete[] begin; }
Vector &operator=(Vector &obj)
{
// Reallocate the underlying buffer to the same size as the
Resize(obj.Size());
for(int i = 0; i < obj.Size(); i++)
(*this)[i] = obj[i];
head = obj.head;
return *this;
}
void ForEach(Predicate<VectorType> &functor)
{
for(int i = 0; i < Size(); i++)
functor(begin[i]);
}
// Swaps the underlying array and characteristics of this vector with another of the same type, very quickly
void Swap(Vector &obj)
{
SWAP(int, head, obj.head);
SWAP(VectorType*, begin, obj.begin);
SWAP(VectorType*, storage, obj.storage);
}
// Checks the entire Vector to see whether a matching item exists. Bear in mind that the VectorType might need to implement
// equality operator (operator==) for this to work properly.
bool Contains(VectorType element)
{
for(int i = 0; i < Size(); i++)
if(operator [](i) == element)
return true;
return false;
}
int Find(VectorType element)
{
for(int i = 0; i < Size(); i++)
if(operator [](i) == element)
return i;
return -1;
}
void PushBack(VectorType element) { PushBack(&element, 1); }
void PushBack(const VectorType *elements, int len)
{
// If the length plus this's size is greater than the capacity, reallocate to that size.
if(len + Size() > Capacity())
ReAllocate(MAX(Size() + len, Size() * 2));
int append = MIN(storage - begin - head - 1, len), prepend = len - append;
// memcpy the data starting at the head all the way up to the last element *(storage - 1)
memcpy((begin + head + 1), elements, sizeof(VectorType) * append);
// If there's still data to copy memcpy whatever remains, starting at the first element *(begin) until the end of data. The first step will have ensured
// that we don't crash into the tail during this process.
memcpy(begin,(elements + append), sizeof(VectorType) * prepend);
// Re-recalculate head and size.
head += len;
}
void Erase(unsigned int position) { Erase(position, position + 1); }
// Erase an arbitrary section of the vector from first up to last minus one. Like the stl counterpart, this is pretty labour intensive so go easy on it.
void Erase(int first, int last)
{
// For this we'll set the value of the array at first to the value of the array at last plus one. We'll do that all the way up to toIndex
for(int i = 0; i < (Size() - first); i++)
{
// If by trying to fill in the next element with the ones ahead of it we'll be running off the end of the vector, stop.
if((i + last) > (Size() - 1))
break;
begin[first + i] = begin[last + i];
}
// Adjust the head to reflect the new size
head -= last - first;
}
// Remove the most recent element in the array
void PopBack()
{
if(Size() > 0)
head--;
}
// Empty the vector, or to be precise - forget the fact that there was ever anything in there.
void Clear() { head = -1; }
// Returns a bool indicating whether or not there are any elements in the array
bool Empty() { return head == -1; }
// Returns the oldest element in the array (the one added before any other)
VectorType const &Back() { return *begin; }
// Returns the newest element in the array (the one added after every other)
VectorType const &Front() { return begin[head]; }
// Returns the nth element in the vector
VectorType &operator[](int n)
{
if(n < Size())
return begin[n];
else
return OB;
}
// Returns a pointer such that the vector's data is laid out between ret to ret + size
VectorType *Data() { return begin; }
// Recreates the vector to hold len elements, all being copies of val
void Assign(int len, const VectorType &val)
{
delete[] begin;
// Allocate an array the same size as the one passed in
begin = new VectorType[len];
storage = begin + len;
// Refresh the head and tail, assuming the array is in order, which it really has to be
head = len - 1;
for(int i = 0 ; i < Size(); i++)
begin[i] = val;
}
// Recreates the vector using an external array
void Assign(VectorType *array, int len)
{
delete[] begin;
// Allocate an array the same size as the one passed in
begin = new VectorType[len];
storage = begin + len;
// Refresh the head and tail, assuming the array is in order, which it really has to be
head = len - 1;
// Copy over the memory
memcpy(begin, array, sizeof(VectorType) * len);
}
// Returns the number of elements that the vector will support before needing resizing
int Capacity() { return (storage - begin); }
// Returns the number of elements in vector
int Size() { return head + 1; }
// Requests that the capacity of the allocated storage space for the elements
// of the vector be at least enough to hold size elements.
void Reserve(unsigned int size)
{
if(size > Capacity())
ReAllocate(size);
}
// Resizes the vector
void Resize(unsigned int size)
{
// If necessary, resize the underlying array to fit the new size
if(size > Capacity())
ReAllocate(size);
// Now revise the head and size (tail needn't change) to reflect the new size
head = size - 1;
}
private:
void ReAllocate(unsigned int size)
{
// Just in case we're re-allocating less room than we had before, make sure that we don't overrun the buffer by trying to write more elements than
// are now possible for this vector to hold.
if(Size() > (int)size)
head = size - 1;
// Allocate an array twice the size of that of the old
VectorType *_begin = new VectorType[size];
VectorType *_storage = _begin + size;
int _head = Size() - 1;
// Copy across all the old array's data and rearrange it!
for(int i = 0; i < Size(); i++)
_begin[i] = (*this)[i];
// Free the old memory
delete[] begin;
// Redirect the old array to point to the new one
begin = _begin;
storage = _storage;
head = _head;
}
};
#endif // VECTOR_H