1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2013 Erwin Coumans  http://bulletphysics.org
4 
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
10 
11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
14 */
15 
16 #ifndef B3_OBJECT_ARRAY__
17 #define B3_OBJECT_ARRAY__
18 
19 #include "b3Scalar.h"  // has definitions like B3_FORCE_INLINE
20 #include "b3AlignedAllocator.h"
21 
22 ///If the platform doesn't support placement new, you can disable B3_USE_PLACEMENT_NEW
23 ///then the b3AlignedObjectArray doesn't support objects with virtual methods, and non-trivial constructors/destructors
24 ///You can enable B3_USE_MEMCPY, then swapping elements in the array will use memcpy instead of operator=
25 ///see discussion here: https://bulletphysics.orgphpBB2/viewtopic.php?t=1231 and
26 ///http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1240
27 
28 #define B3_USE_PLACEMENT_NEW 1
29 //#define B3_USE_MEMCPY 1 //disable, because it is cumbersome to find out for each platform where memcpy is defined. It can be in <memory.h> or <string.h> or otherwise...
30 #define B3_ALLOW_ARRAY_COPY_OPERATOR  // enabling this can accidently perform deep copies of data if you are not careful
31 
32 #ifdef B3_USE_MEMCPY
33 #include <memory.h>
34 #include <string.h>
35 #endif  //B3_USE_MEMCPY
36 
37 #ifdef B3_USE_PLACEMENT_NEW
38 #include <new>  //for placement new
39 #endif          //B3_USE_PLACEMENT_NEW
40 
41 ///The b3AlignedObjectArray template class uses a subset of the stl::vector interface for its methods
42 ///It is developed to replace stl::vector to avoid portability issues, including STL alignment issues to add SIMD/SSE data
43 template <typename T>
44 //template <class T>
45 class b3AlignedObjectArray
46 {
47 	b3AlignedAllocator<T, 16> m_allocator;
48 
49 	int m_size;
50 	int m_capacity;
51 	T* m_data;
52 	//PCK: added this line
53 	bool m_ownsMemory;
54 
55 #ifdef B3_ALLOW_ARRAY_COPY_OPERATOR
56 public:
57 	B3_FORCE_INLINE b3AlignedObjectArray<T>& operator=(const b3AlignedObjectArray<T>& other)
58 	{
59 		copyFromArray(other);
60 		return *this;
61 	}
62 #else   //B3_ALLOW_ARRAY_COPY_OPERATOR
63 private:
64 	B3_FORCE_INLINE b3AlignedObjectArray<T>& operator=(const b3AlignedObjectArray<T>& other);
65 #endif  //B3_ALLOW_ARRAY_COPY_OPERATOR
66 
67 protected:
allocSize(int size)68 	B3_FORCE_INLINE int allocSize(int size)
69 	{
70 		return (size ? size * 2 : 1);
71 	}
copy(int start,int end,T * dest)72 	B3_FORCE_INLINE void copy(int start, int end, T* dest) const
73 	{
74 		int i;
75 		for (i = start; i < end; ++i)
76 #ifdef B3_USE_PLACEMENT_NEW
77 			new (&dest[i]) T(m_data[i]);
78 #else
79 			dest[i] = m_data[i];
80 #endif  //B3_USE_PLACEMENT_NEW
81 	}
82 
init()83 	B3_FORCE_INLINE void init()
84 	{
85 		//PCK: added this line
86 		m_ownsMemory = true;
87 		m_data = 0;
88 		m_size = 0;
89 		m_capacity = 0;
90 	}
destroy(int first,int last)91 	B3_FORCE_INLINE void destroy(int first, int last)
92 	{
93 		int i;
94 		for (i = first; i < last; i++)
95 		{
96 			m_data[i].~T();
97 		}
98 	}
99 
allocate(int size)100 	B3_FORCE_INLINE void* allocate(int size)
101 	{
102 		if (size)
103 			return m_allocator.allocate(size);
104 		return 0;
105 	}
106 
deallocate()107 	B3_FORCE_INLINE void deallocate()
108 	{
109 		if (m_data)
110 		{
111 			//PCK: enclosed the deallocation in this block
112 			if (m_ownsMemory)
113 			{
114 				m_allocator.deallocate(m_data);
115 			}
116 			m_data = 0;
117 		}
118 	}
119 
120 public:
b3AlignedObjectArray()121 	b3AlignedObjectArray()
122 	{
123 		init();
124 	}
125 
~b3AlignedObjectArray()126 	~b3AlignedObjectArray()
127 	{
128 		clear();
129 	}
130 
131 	///Generally it is best to avoid using the copy constructor of an b3AlignedObjectArray, and use a (const) reference to the array instead.
b3AlignedObjectArray(const b3AlignedObjectArray & otherArray)132 	b3AlignedObjectArray(const b3AlignedObjectArray& otherArray)
133 	{
134 		init();
135 
136 		int otherSize = otherArray.size();
137 		resize(otherSize);
138 		otherArray.copy(0, otherSize, m_data);
139 	}
140 
141 	/// return the number of elements in the array
size()142 	B3_FORCE_INLINE int size() const
143 	{
144 		return m_size;
145 	}
146 
at(int n)147 	B3_FORCE_INLINE const T& at(int n) const
148 	{
149 		b3Assert(n >= 0);
150 		b3Assert(n < size());
151 		return m_data[n];
152 	}
153 
at(int n)154 	B3_FORCE_INLINE T& at(int n)
155 	{
156 		b3Assert(n >= 0);
157 		b3Assert(n < size());
158 		return m_data[n];
159 	}
160 
161 	B3_FORCE_INLINE const T& operator[](int n) const
162 	{
163 		b3Assert(n >= 0);
164 		b3Assert(n < size());
165 		return m_data[n];
166 	}
167 
168 	B3_FORCE_INLINE T& operator[](int n)
169 	{
170 		b3Assert(n >= 0);
171 		b3Assert(n < size());
172 		return m_data[n];
173 	}
174 
175 	///clear the array, deallocated memory. Generally it is better to use array.resize(0), to reduce performance overhead of run-time memory (de)allocations.
clear()176 	B3_FORCE_INLINE void clear()
177 	{
178 		destroy(0, size());
179 
180 		deallocate();
181 
182 		init();
183 	}
184 
pop_back()185 	B3_FORCE_INLINE void pop_back()
186 	{
187 		b3Assert(m_size > 0);
188 		m_size--;
189 		m_data[m_size].~T();
190 	}
191 
192 	///resize changes the number of elements in the array. If the new size is larger, the new elements will be constructed using the optional second argument.
193 	///when the new number of elements is smaller, the destructor will be called, but memory will not be freed, to reduce performance overhead of run-time memory (de)allocations.
resizeNoInitialize(int newsize)194 	B3_FORCE_INLINE void resizeNoInitialize(int newsize)
195 	{
196 		int curSize = size();
197 
198 		if (newsize < curSize)
199 		{
200 		}
201 		else
202 		{
203 			if (newsize > size())
204 			{
205 				reserve(newsize);
206 			}
207 			//leave this uninitialized
208 		}
209 		m_size = newsize;
210 	}
211 
212 	B3_FORCE_INLINE void resize(int newsize, const T& fillData = T())
213 	{
214 		int curSize = size();
215 
216 		if (newsize < curSize)
217 		{
218 			for (int i = newsize; i < curSize; i++)
219 			{
220 				m_data[i].~T();
221 			}
222 		}
223 		else
224 		{
225 			if (newsize > size())
226 			{
227 				reserve(newsize);
228 			}
229 #ifdef B3_USE_PLACEMENT_NEW
230 			for (int i = curSize; i < newsize; i++)
231 			{
232 				new (&m_data[i]) T(fillData);
233 			}
234 #endif  //B3_USE_PLACEMENT_NEW
235 		}
236 
237 		m_size = newsize;
238 	}
expandNonInitializing()239 	B3_FORCE_INLINE T& expandNonInitializing()
240 	{
241 		int sz = size();
242 		if (sz == capacity())
243 		{
244 			reserve(allocSize(size()));
245 		}
246 		m_size++;
247 
248 		return m_data[sz];
249 	}
250 
251 	B3_FORCE_INLINE T& expand(const T& fillValue = T())
252 	{
253 		int sz = size();
254 		if (sz == capacity())
255 		{
256 			reserve(allocSize(size()));
257 		}
258 		m_size++;
259 #ifdef B3_USE_PLACEMENT_NEW
260 		new (&m_data[sz]) T(fillValue);  //use the in-place new (not really allocating heap memory)
261 #endif
262 
263 		return m_data[sz];
264 	}
265 
push_back(const T & _Val)266 	B3_FORCE_INLINE void push_back(const T& _Val)
267 	{
268 		int sz = size();
269 		if (sz == capacity())
270 		{
271 			reserve(allocSize(size()));
272 		}
273 
274 #ifdef B3_USE_PLACEMENT_NEW
275 		new (&m_data[m_size]) T(_Val);
276 #else
277 		m_data[size()] = _Val;
278 #endif  //B3_USE_PLACEMENT_NEW
279 
280 		m_size++;
281 	}
282 
283 	/// return the pre-allocated (reserved) elements, this is at least as large as the total number of elements,see size() and reserve()
capacity()284 	B3_FORCE_INLINE int capacity() const
285 	{
286 		return m_capacity;
287 	}
288 
reserve(int _Count)289 	B3_FORCE_INLINE void reserve(int _Count)
290 	{  // determine new minimum length of allocated storage
291 		if (capacity() < _Count)
292 		{  // not enough room, reallocate
293 			T* s = (T*)allocate(_Count);
294 			b3Assert(s);
295 			if (s == 0)
296 			{
297 				b3Error("b3AlignedObjectArray reserve out-of-memory\n");
298 				_Count = 0;
299 				m_size = 0;
300 			}
301 			copy(0, size(), s);
302 
303 			destroy(0, size());
304 
305 			deallocate();
306 
307 			//PCK: added this line
308 			m_ownsMemory = true;
309 
310 			m_data = s;
311 
312 			m_capacity = _Count;
313 		}
314 	}
315 
316 	class less
317 	{
318 	public:
operator()319 		bool operator()(const T& a, const T& b)
320 		{
321 			return (a < b);
322 		}
323 	};
324 
325 	template <typename L>
quickSortInternal(const L & CompareFunc,int lo,int hi)326 	void quickSortInternal(const L& CompareFunc, int lo, int hi)
327 	{
328 		//  lo is the lower index, hi is the upper index
329 		//  of the region of array a that is to be sorted
330 		int i = lo, j = hi;
331 		T x = m_data[(lo + hi) / 2];
332 
333 		//  partition
334 		do
335 		{
336 			while (CompareFunc(m_data[i], x))
337 				i++;
338 			while (CompareFunc(x, m_data[j]))
339 				j--;
340 			if (i <= j)
341 			{
342 				swap(i, j);
343 				i++;
344 				j--;
345 			}
346 		} while (i <= j);
347 
348 		//  recursion
349 		if (lo < j)
350 			quickSortInternal(CompareFunc, lo, j);
351 		if (i < hi)
352 			quickSortInternal(CompareFunc, i, hi);
353 	}
354 
355 	template <typename L>
quickSort(const L & CompareFunc)356 	void quickSort(const L& CompareFunc)
357 	{
358 		//don't sort 0 or 1 elements
359 		if (size() > 1)
360 		{
361 			quickSortInternal(CompareFunc, 0, size() - 1);
362 		}
363 	}
364 
365 	///heap sort from http://www.csse.monash.edu.au/~lloyd/tildeAlgDS/Sort/Heap/
366 	template <typename L>
downHeap(T * pArr,int k,int n,const L & CompareFunc)367 	void downHeap(T* pArr, int k, int n, const L& CompareFunc)
368 	{
369 		/*  PRE: a[k+1..N] is a heap */
370 		/* POST:  a[k..N]  is a heap */
371 
372 		T temp = pArr[k - 1];
373 		/* k has child(s) */
374 		while (k <= n / 2)
375 		{
376 			int child = 2 * k;
377 
378 			if ((child < n) && CompareFunc(pArr[child - 1], pArr[child]))
379 			{
380 				child++;
381 			}
382 			/* pick larger child */
383 			if (CompareFunc(temp, pArr[child - 1]))
384 			{
385 				/* move child up */
386 				pArr[k - 1] = pArr[child - 1];
387 				k = child;
388 			}
389 			else
390 			{
391 				break;
392 			}
393 		}
394 		pArr[k - 1] = temp;
395 	} /*downHeap*/
396 
swap(int index0,int index1)397 	void swap(int index0, int index1)
398 	{
399 #ifdef B3_USE_MEMCPY
400 		char temp[sizeof(T)];
401 		memcpy(temp, &m_data[index0], sizeof(T));
402 		memcpy(&m_data[index0], &m_data[index1], sizeof(T));
403 		memcpy(&m_data[index1], temp, sizeof(T));
404 #else
405 		T temp = m_data[index0];
406 		m_data[index0] = m_data[index1];
407 		m_data[index1] = temp;
408 #endif  //B3_USE_PLACEMENT_NEW
409 	}
410 
411 	template <typename L>
heapSort(const L & CompareFunc)412 	void heapSort(const L& CompareFunc)
413 	{
414 		/* sort a[0..N-1],  N.B. 0 to N-1 */
415 		int k;
416 		int n = m_size;
417 		for (k = n / 2; k > 0; k--)
418 		{
419 			downHeap(m_data, k, n, CompareFunc);
420 		}
421 
422 		/* a[1..N] is now a heap */
423 		while (n >= 1)
424 		{
425 			swap(0, n - 1); /* largest of a[0..n-1] */
426 
427 			n = n - 1;
428 			/* restore a[1..i-1] heap */
429 			downHeap(m_data, 1, n, CompareFunc);
430 		}
431 	}
432 
433 	///non-recursive binary search, assumes sorted array
findBinarySearch(const T & key)434 	int findBinarySearch(const T& key) const
435 	{
436 		int first = 0;
437 		int last = size() - 1;
438 
439 		//assume sorted array
440 		while (first <= last)
441 		{
442 			int mid = (first + last) / 2;  // compute mid point.
443 			if (key > m_data[mid])
444 				first = mid + 1;  // repeat search in top half.
445 			else if (key < m_data[mid])
446 				last = mid - 1;  // repeat search in bottom half.
447 			else
448 				return mid;  // found it. return position /////
449 		}
450 		return size();  // failed to find key
451 	}
452 
findLinearSearch(const T & key)453 	int findLinearSearch(const T& key) const
454 	{
455 		int index = size();
456 		int i;
457 
458 		for (i = 0; i < size(); i++)
459 		{
460 			if (m_data[i] == key)
461 			{
462 				index = i;
463 				break;
464 			}
465 		}
466 		return index;
467 	}
468 
findLinearSearch2(const T & key)469 	int findLinearSearch2(const T& key) const
470 	{
471 		int index = -1;
472 		int i;
473 
474 		for (i = 0; i < size(); i++)
475 		{
476 			if (m_data[i] == key)
477 			{
478 				index = i;
479 				break;
480 			}
481 		}
482 		return index;
483 	}
484 
remove(const T & key)485 	void remove(const T& key)
486 	{
487 		int findIndex = findLinearSearch(key);
488 		if (findIndex < size())
489 		{
490 			swap(findIndex, size() - 1);
491 			pop_back();
492 		}
493 	}
494 
495 	//PCK: whole function
initializeFromBuffer(void * buffer,int size,int capacity)496 	void initializeFromBuffer(void* buffer, int size, int capacity)
497 	{
498 		clear();
499 		m_ownsMemory = false;
500 		m_data = (T*)buffer;
501 		m_size = size;
502 		m_capacity = capacity;
503 	}
504 
copyFromArray(const b3AlignedObjectArray & otherArray)505 	void copyFromArray(const b3AlignedObjectArray& otherArray)
506 	{
507 		int otherSize = otherArray.size();
508 		resize(otherSize);
509 		otherArray.copy(0, otherSize, m_data);
510 	}
511 
removeAtIndex(int index)512 	void removeAtIndex(int index)
513 	{
514 		if (index < size())
515 		{
516 			swap(index, size() - 1);
517 			pop_back();
518 		}
519 	}
520 };
521 
522 #endif  //B3_OBJECT_ARRAY__
523