1 /*
2 Copyright (C) 2005-2007 Feeling Software Inc.
3 Portions of the code are:
4 Copyright (C) 2005-2007 Sony Computer Entertainment America
5
6 MIT License: http://www.opensource.org/licenses/mit-license.php
7 */
8
9 /**
10 @file FMArray.h
11 The file contains the vector class, which improves on the standard C++ vector class.
12 */
13
14 #ifndef _FM_ARRAY_H_
15 #define _FM_ARRAY_H_
16
17 #ifndef _FM_ALLOCATOR_H_
18 #include "FMath/FMAllocator.h"
19 #endif // _FM_ALLOCATOR_H_
20 #ifndef _FM_SORT_H_
21 #include "FMath/FMSort.h"
22 #endif // _FM_SORT_H_
23
24 #ifdef WIN32
25 #pragma warning(disable:4127)
26 #endif //WIN32
27
28 /** Namespace that contains the overwritten STL classes. */
29 namespace fm
30 {
31 /**
32 A dynamically-sized array.
33 Intentionally has an interface similar to the standard C++ vector class.
34 It's implement should be very similar yet more lightweight.
35
36 We have also added useful extra functionality, such as a constructor that takes
37 in a constant-sized array, comparison with a constant-sized array, erase and find
38 functions that take in a value, etc.
39
40 @ingroup FMath
41 */
42 template <class T, bool PRIMITIVE=false>
43 class vector
44 {
45 protected:
46 size_t reserved; /**< The capacity of the vector. */
47 size_t sized; /**< The number of values contained in the vector. */
48 T* heapBuffer; /**< The heap buffer that contains the values. */
49
50 public:
51 /** The basic list iterator. */
52 typedef T* iterator;
53
54 /** The non-modifiable list iterator. */
55 typedef const T* const_iterator;
56
57 public:
58 /** Default constructor. */
vector()59 vector() : reserved(0), sized(0), heapBuffer(NULL) {}
60
61 /** Constructor. Builds a dynamically-sized array of the wanted size.
62 @param size The wanted size of the array. */
vector(size_t size)63 vector(size_t size) : reserved(0), sized(0), heapBuffer(NULL)
64 {
65 resize(size);
66 }
67
68 /** Constructor. Builds a dynamically-sized array of the wanted size.
69 @param size The wanted size of the array
70 @param defaultValue The default value to use for all the entries of the array. */
vector(size_t size,const T & defaultValue)71 vector(size_t size, const T& defaultValue) : reserved(0), sized(0), heapBuffer(NULL)
72 {
73 resize(size, defaultValue);
74 }
75
76 /** Copy constructor.
77 @param copy The dynamically-sized array to copy the values from. */
vector(const fm::vector<T,PRIMITIVE> & copy)78 vector(const fm::vector<T,PRIMITIVE>& copy) : reserved(0), sized(0), heapBuffer(NULL)
79 {
80 insert(heapBuffer, copy.begin(), copy.size());
81 }
82
83 /** Constructor. Builds a dynamically-sized array from a constant-sized array.
84 @param values A constant-sized array of floating-point values.
85 @param count The size of the constant-sized array. */
vector(const T * values,size_t count)86 vector(const T* values, size_t count) : reserved(0), sized(0), heapBuffer(NULL)
87 {
88 insert(heapBuffer, values, count);
89 }
90
91 /** Destructor. */
~vector()92 ~vector()
93 {
94 if (!PRIMITIVE)
95 {
96 for (intptr_t i = sized - 1; i >= 0; --i)
97 {
98 heapBuffer[i].~T();
99 }
100 }
101 if (heapBuffer != NULL)
102 {
103 fm::Release(heapBuffer);
104 }
105 }
106
107 /** Retrieves a pointer to our internal buffer.
108 Be very careful when using this.
109 @return A pointer to our internal buffer. */
GetDataPtr()110 inline T** GetDataPtr() { return &heapBuffer; }
GetDataPtr()111 inline const T** GetDataPtr() const { return (const T**) &heapBuffer; } /**< See above. */
112
113 /** Retrieves an iterator for a given element.
114 @param value The value, contained within the list, to search for.
115 @return An iterator to this element. The end() iterator
116 is returned if the value is not found. */
find(const Type2 & value)117 template <class Type2> iterator find(const Type2& value)
118 {
119 T* i = begin(),* e = end();
120 for (; i != e; ++i) if ((*i) == value) break;
121 return i;
122 }
find(const Type2 & value)123 template <class Type2> const_iterator find(const Type2& value) const
124 {
125 const T* i = begin(),* e = end();
126 for (; i != e; ++i) if ((*i) == value) break;
127 return i;
128 } /**< See above. */
129
130 /** Sorts this vector using the default comparisons operator. */
sort()131 inline void sort()
132 {
133 comparator<T> comp;
134 comp.sort(heapBuffer, sized);
135 }
136
137 /** Sorts this vector using the given fm::comparator.
138 @param comparator The comparator used to sort the vector.*/
sort(comparator<T> & comp)139 inline void sort(comparator<T>& comp)
140 {
141 comp.sort(heapBuffer, sized);
142 }
143
144 /** Removes the value at the given position within the list.
145 @param it The list position for the value to remove. */
erase(iterator it)146 iterator erase(iterator it)
147 {
148 FUAssert(it >= begin() && it < end(), return it);
149 if (!PRIMITIVE) (*it).~T();
150 if (end() - it - 1 > 0) memmove(it, it+1, (end() - it - 1) * sizeof(T));
151 --sized;
152 return it;
153 }
154
155 /** Removes a range of values from the list. The range is determined as every value
156 between and including the first value, up to the last value, but not including the
157 last value.
158 @param first An iterator pointing to the first list value to remove.
159 @param last An iterator past the last list value to remove. */
erase(iterator first,iterator last)160 void erase(iterator first, iterator last)
161 {
162 FUAssert(first >= begin() && first < end(), return);
163 FUAssert(last > begin() && last <= end(), return);
164 if (!PRIMITIVE) for (iterator it = first; it != last; ++it) (*it).~T();
165 if (end() - last > 0) memmove(first, last, (end() - last) * sizeof(T));
166 sized -= last - first;
167 }
168
169 /** Removes a range of values from the list.
170 @param first The index of the first value to remove.
171 @param last The index just passed the last value to remove. */
erase(size_t first,size_t last)172 inline void erase(size_t first, size_t last) { erase(begin() + first, begin() + last); }
173
174 /** Removes a value contained within the list, once.
175 @param value The value, contained within the list, to erase from it.
176 @return Whether the value was found and erased from the list. */
erase(const T & value)177 inline bool erase(const T& value) { iterator it = find(value); if (it != end()) { erase(it); return true; } return false; }
178
179 /** Removes an indexed value contained within the list.
180 @param index The index of the value to erase. */
erase(size_t index)181 inline void erase(size_t index) { erase(begin() + index); }
182
183 /** Retrieves whether the list contains a given value.
184 @param value A value that could be contained in the list.
185 @return Whether the list contains this value. */
contains(const T & value)186 inline bool contains(const T& value) const { const_iterator it = find(value); return it != end(); }
187
188 /** Replaces all cases of one value into another value.
189 @param start The iterator at which to start replacing values.
190 @param end The iterator at which to end replacing values.
191 @param oldValue The value to replace.
192 @param newValue The value which replaces the old value. */
193 template <class V2, class V3>
replace(const V2 & oldValue,const V3 & newValue)194 inline void replace(const V2& oldValue, const V3& newValue)
195 {
196 for (iterator start = begin(), stop = end(); start != stop; ++start)
197 {
198 if (*start == (T) oldValue) *start = newValue;
199 }
200 }
201
202 /** Replaces the instances of one value into another value
203 within a given segment of the list.
204 @param start The iterator at which to start replacing values.
205 @param end The iterator at which to end replacing values.
206 @param oldValue The value to replace.
207 @param newValue The value which replaces the old value. */
208 template <class V2, class V3>
replace(iterator start,iterator end,const V2 & oldValue,const V3 & newValue)209 inline void replace(iterator start, iterator end, const V2& oldValue, const V3& newValue)
210 {
211 while (start != end)
212 {
213 if (*start == (T) oldValue) *start = newValue;
214 ++start;
215 }
216 }
217
218 /** Retrieves the number of values contained in the list.
219 @return The number of values contained in the list. */
size()220 inline size_t size() const { return sized; }
221
222 /** Retrieves whether there are any elements in the list. */
empty()223 inline bool empty() const { return sized == 0; }
224
225 /** Sets the number of values contained in the list.
226 @param count The new number of values contained in the list. */
resize(size_t count)227 void resize(size_t count)
228 {
229 reserve(count);
230
231 if (!PRIMITIVE)
232 {
233 T* it = end();
234 for (; sized < count; ++sized)
235 {
236 // For non-primitive types, make sure we call the constructors of all the values.
237 fm::Construct(it++);
238 }
239 }
240 else
241 {
242 sized = reserved;
243 }
244 }
245
246 /** Sets the number of values contained in the list.
247 @param count The new number of values contained in the list.
248 @param value The value to assign to the new entries in the list. */
resize(size_t count,const T & value)249 void resize(size_t count, const T& value)
250 {
251 reserve(count);
252 T* it = end();
253
254 for (; sized < count; ++sized)
255 {
256 // For non-primitive types, make sure we call the constructors of all the values.
257 if (!PRIMITIVE)
258 {
259 fm::Construct(it++, value);
260 }
261 else
262 {
263 *(it++) = value;
264 }
265 }
266 }
267
268 /** Removes all the element in the list. */
clear()269 inline void clear() { reserve(0); }
270
271 /** Pre-allocate the list to a certain number of values.
272 You can use reserve zero values in order to clear the memory
273 used by this list. This function is useful when optimizing.
274 @param count The new number of values pre-allocated in the list. */
reserve(size_t count)275 void reserve(size_t count)
276 {
277 // Basic check for stupidly large allocations;
278 // basically all this is for is to catch (size_t)-1 calls
279 // in debug mode. Ensure release will optimize out this call!
280 FUAssert(count < INT_MAX, ;);
281 if (reserved != count)
282 {
283 // For non-primitives, make sure we destroy all the values individually.
284 if (PRIMITIVE)
285 {
286 if (sized > count) sized = count;
287 }
288 else
289 {
290 while (sized > count) pop_back();
291 }
292
293 // If we are reserving data, re-allocate a new buffer.
294 T* newValues;
295 if (count > 0)
296 {
297 newValues = (T*) fm::Allocate(count * sizeof(T));
298 if (sized > 0)
299 {
300 memcpy(newValues, heapBuffer, sized * sizeof(T));
301 }
302 }
303 else newValues = NULL;
304
305 // Free the old buffer.
306 if (heapBuffer != NULL)
307 {
308 fm::Release(heapBuffer);
309 }
310 heapBuffer = newValues;
311 reserved = count;
312 }
313 }
314
315 /** Retrieves the maximum size the array can grow to without allocating memory
316 size is always less than or equal to capacity
317 @return The number of values the array currently has memory allocated for */
capacity()318 inline size_t capacity() { return reserved; }
capacity()319 inline size_t capacity() const { return reserved; } /**< See above. */
320
321 /** Retrieves the iterator for the first value in the list.
322 @return The iterator for the first value in the list. */
begin()323 inline iterator begin() { return heapBuffer; }
begin()324 inline const_iterator begin() const { return heapBuffer; } /**< See above. */
325
326 /** Retrieves the iterator just past the last value in the list.
327 @return The iterator for just past the last value in the list. */
end()328 inline iterator end() { return heapBuffer + sized; }
end()329 inline const_iterator end() const { return heapBuffer + sized; } /**< See above. */
330
331 /** Inserts a new item at a given position within the list.
332 @param it An iterator pointing to where to insert the item.
333 @param item The item to insert.
334 @return An iterator pointing to the inserted item within the list. */
insert(iterator it,const T & item)335 iterator insert(iterator it, const T& item)
336 {
337 FUAssert(it >= begin() && it <= end(), return it);
338 if (sized == reserved)
339 {
340 size_t offset = it - begin();
341 reserve(sized + (sized > 31 ? 32 : (sized+1)));
342 it = begin() + offset;
343 }
344 if (it < end())
345 {
346 memmove(it + 1, it, (end() - it) * sizeof(T));
347 }
348 if (!PRIMITIVE)
349 {
350 fm::Construct(it, item);
351 }
352 else
353 {
354 *it = item;
355 }
356 ++sized;
357 return it;
358 }
359
360 /** Inserts a new item at a given position within the list.
361 @param index Where to insert the given value.
362 @param item The item to insert. */
insert(size_t index,const T & item)363 inline void insert(size_t index, const T& item) { insert(begin() + index, item); }
364
365 /** Inserts a new item at the end of the list.
366 @param item The item to insert. */
push_back(const T & item)367 inline void push_back(const T& item) { insert(end(), item); }
368
369 /** Inserts a new item at the front of the list.
370 This operation is very expansive and not recommended
371 for real-time operations.
372 @param item The item to insert. */
push_front(const T & item)373 inline void push_front(const T& item) { insert(begin(), item); }
374
375 /** Removes the last item from a list. */
pop_back()376 void pop_back()
377 {
378 FUAssert(sized > 0, return);
379 if (!PRIMITIVE) (*(heapBuffer + sized - 1)).~T();
380 --sized;
381 }
382
383 /** Removes the first item from a list.
384 This operation is very expansive and not recommended
385 for real-time operations. */
pop_front()386 inline void pop_front()
387 {
388 erase(begin());
389 }
390
391 /** Inserts multiple items at a given position within the list.
392 @param it An iterator pointing to where to insert the items.
393 @param first An iterator pointing to the first item to insert.
394 @param last An iterator past the last item to insert. */
insert(iterator it,_IT first,_IT last)395 template <typename _IT> inline void insert(iterator it, _IT first, _IT last)
396 {
397 size_t count = last - first;
398 insert(it, first, count);
399 }
400
401 /** Inserts one item, multiple times at a given position within the list.
402 @param it An iterator pointing to where to insert the item.
403 @param count The number of times to insert the item.
404 @param item The item to insert. */
405 inline void insert(iterator it, size_t count, const T& item, bool noInit=false)
406 {
407 if (count > 0)
408 {
409 FUAssert(it >= begin() && it <= end(), return);
410 if (sized + count > reserved)
411 {
412 size_t offset = it - begin();
413 reserve(sized + count);
414 it = begin() + offset;
415 }
416 if (it < end())
417 {
418 memmove(it + count, it, (end() - it) * sizeof(T));
419 }
420 sized += count;
421
422 if (!noInit)
423 {
424 if (!PRIMITIVE)
425 {
426 do
427 {
428 fm::Construct(it++, item);
429 }
430 while (--count > 0);
431 }
432 else
433 {
434 do
435 {
436 *(it++) = item;
437 }
438 while (--count > 0);
439 }
440 }
441 }
442 }
443
444 /** Inserts one value, multiple times, to this list.
445 @param index Where to insert the value.
446 @param count The number of times to insert this value.
447 @param value The value to insert. */
insert(size_t index,size_t count,const T & value)448 inline void insert(size_t index, size_t count, const T& value) { insert(begin() + index, count, value); }
449
450 /** Inserts multiple items at a given position within the list,
451 from a static list.
452 @param it An iterator pointing to where to insert the items.
453 @param first A pointer to the first item to insert.
454 @param count The number of element within the static list
455 that must be inserted within the list. */
insert(iterator it,const T * first,size_t count)456 void insert(iterator it, const T* first, size_t count)
457 {
458 if (count > 0)
459 {
460 FUAssert(it >= begin() && it <= end(), return);
461 if (sized + count > reserved)
462 {
463 size_t offset = it - begin();
464 reserve((sized + count - reserved) > 32 ? (sized + count) : (reserved + 32));
465 it = begin() + offset;
466 }
467 if (it < end())
468 {
469 memmove(it + count, it, (end() - it) * sizeof(T));
470 }
471 sized += count;
472 if (!PRIMITIVE)
473 {
474 do
475 {
476 fm::Construct(it++, (*first++));
477 }
478 while (--count > 0);
479 }
480 else
481 {
482 memcpy(it, first, count * sizeof(T));
483 }
484 }
485 }
486
487 /** Inserts multiple values to this list.
488 @param index Where to insert the values.
489 @param values A static list of values.
490 @param count The number of values to insert. */
insert(size_t index,const T * values,size_t count)491 inline void insert(size_t index, const T* values, size_t count) { insert(begin() + index, values, count); }
492
493 /** Retrieves the first element of the pointer array.
494 @return The first element in the pointer array. */
front()495 T& front() { FUAssert(sized > 0,); return (*heapBuffer); }
front()496 const T& front() const { FUAssert(sized > 0,); return (*heapBuffer); } /**< See above. */
497
498 /** Retrieves the last element of the pointer array.
499 @return The last element in the pointer array. */
back()500 T& back() { FUAssert(sized > 0,); return *(heapBuffer + sized - 1); }
back()501 const T& back() const { FUAssert(sized > 0,); return *(heapBuffer + sized - 1); } /**< See above. */
502
503 /** Retrieves an indexed object in the pointer array.
504 @param index An index.
505 @return The given object. */
at(size_t index)506 T& at(size_t index) { FUAssert(index < sized,); return heapBuffer[index]; }
at(size_t index)507 const T& at(size_t index) const { FUAssert(index < sized,); return heapBuffer[index]; } /**< See above. */
508 template <class INTEGER> inline T& operator[](INTEGER index) { FUAssert((size_t) index < sized,); return heapBuffer[index]; } /**< See above. */
509 template <class INTEGER> inline const T& operator[](INTEGER index) const { FUAssert((size_t) index < sized,); return heapBuffer[index]; } /**< See above. */
510
511 /** Retrieves whether two lists are equivalent.
512 @param other A second list.
513 @return Whether the two lists are equivalent. */
514 bool operator==(const fm::vector<T,PRIMITIVE>& other) const
515 {
516 bool equals = sized == other.size();
517 const T* e = end();
518 for (const T* it = begin(),* it2 = other.begin(); it != e && equals; ++it, ++it2)
519 {
520 equals = (*it) == (*it2);
521 }
522 return equals;
523 }
524
525 /** Copy operator. Copies the contents of one vector to another.
526 @param rhs The vector to copy (RHS of operation).
527 @return A reference to this (LHS of operation). */
528 vector<T,PRIMITIVE>& operator =(const fm::vector<T,PRIMITIVE>& rhs)
529 {
530 if (this != &rhs)
531 {
532 if (PRIMITIVE)
533 {
534 resize(rhs.size());
535 memcpy(begin(), rhs.begin(), sizeof(T) * rhs.size());
536 }
537 else
538 {
539 reserve(rhs.size());
540 clear();
541 for (const_iterator it = rhs.begin(); it != rhs.end(); ++it)
542 {
543 push_back(*it);
544 }
545 }
546 }
547 return *this;
548 }
549 };
550 };
551
552 /** Returns whether a dynamically-sized array is equivalent to a constant-sized array.
553 @param dl A dynamically-sized array.
554 @param cl A constant-sized array.
555 @param count The size of the constant-sized array.
556 @return Whether the two arrays are equivalent. */
557 template <class T, bool PRIMITIVE>
IsEquivalent(const fm::vector<T,PRIMITIVE> & dl,const T * cl,size_t count)558 inline bool IsEquivalent(const fm::vector<T,PRIMITIVE>& dl, const T* cl, size_t count)
559 {
560 if (dl.size() != count) return false;
561 bool equivalent = true;
562 for (size_t i = 0; i < count && equivalent; ++i)
563 {
564 equivalent = IsEquivalent(dl.at(i), cl[i]);
565 }
566 return equivalent;
567 }
568
569 /** Returns whether two constant-sized arrays are equivalent.
570 @param al A first constant-sized array.
571 @param acount The number of elements in the first array.
572 @param bl A second constant-sized array.
573 @param bcount The number of elements in the second array.
574 @return Whether the two arrays are equivalent. */
575 template <class T>
IsEquivalent(const T * al,size_t acount,const T * bl,size_t bcount)576 inline bool IsEquivalent(const T* al, size_t acount, const T* bl, size_t bcount)
577 {
578 if (acount != bcount) return false;
579 bool equivalent = true;
580 for (size_t i = 0; i < acount && equivalent; ++i)
581 {
582 equivalent = IsEquivalent(al[i], bl[i]);
583 }
584 return equivalent;
585 }
586
587 #ifdef WIN32
588 #pragma warning(default:4127)
589 #endif //WIN32
590 #endif // _FM_ARRAY_H_
591