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