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