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