2017-08-01 12:30:58 +00:00
/*
Bullet Continuous Collision Detection and Physics Library
Copyright ( c ) 2003 - 2013 Erwin Coumans http : //bulletphysics.org
This software is provided ' as - is ' , without any express or implied warranty .
In no event will the authors be held liable for any damages arising from the use of this software .
Permission is granted to anyone to use this software for any purpose ,
including commercial applications , and to alter it and redistribute it freely ,
subject to the following restrictions :
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 .
2. Altered source versions must be plainly marked as such , and must not be misrepresented as being the original software .
3. This notice may not be removed or altered from any source distribution .
*/
# ifndef B3_OBJECT_ARRAY__
# define B3_OBJECT_ARRAY__
2019-01-03 13:26:51 +00:00
# include "b3Scalar.h" // has definitions like B3_FORCE_INLINE
2017-08-01 12:30:58 +00:00
# include "b3AlignedAllocator.h"
///If the platform doesn't support placement new, you can disable B3_USE_PLACEMENT_NEW
///then the b3AlignedObjectArray doesn't support objects with virtual methods, and non-trivial constructors/destructors
///You can enable B3_USE_MEMCPY, then swapping elements in the array will use memcpy instead of operator=
2022-01-06 22:37:49 +00:00
///see discussion here: https://bulletphysics.orgphpBB2/viewtopic.php?t=1231 and
2017-08-01 12:30:58 +00:00
///http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1240
# define B3_USE_PLACEMENT_NEW 1
//#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...
2019-01-03 13:26:51 +00:00
# define B3_ALLOW_ARRAY_COPY_OPERATOR // enabling this can accidently perform deep copies of data if you are not careful
2017-08-01 12:30:58 +00:00
# ifdef B3_USE_MEMCPY
# include <memory.h>
# include <string.h>
2019-01-03 13:26:51 +00:00
# endif //B3_USE_MEMCPY
2017-08-01 12:30:58 +00:00
# ifdef B3_USE_PLACEMENT_NEW
2019-01-03 13:26:51 +00:00
# include <new> //for placement new
# endif //B3_USE_PLACEMENT_NEW
2017-08-01 12:30:58 +00:00
///The b3AlignedObjectArray template class uses a subset of the stl::vector interface for its methods
///It is developed to replace stl::vector to avoid portability issues, including STL alignment issues to add SIMD/SSE data
2019-01-03 13:26:51 +00:00
template < typename T >
//template <class T>
2017-08-01 12:30:58 +00:00
class b3AlignedObjectArray
{
2019-01-03 13:26:51 +00:00
b3AlignedAllocator < T , 16 > m_allocator ;
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
int m_size ;
int m_capacity ;
T * m_data ;
2017-08-01 12:30:58 +00:00
//PCK: added this line
2019-01-03 13:26:51 +00:00
bool m_ownsMemory ;
2017-08-01 12:30:58 +00:00
# ifdef B3_ALLOW_ARRAY_COPY_OPERATOR
public :
2019-01-03 13:26:51 +00:00
B3_FORCE_INLINE b3AlignedObjectArray < T > & operator = ( const b3AlignedObjectArray < T > & other )
2017-08-01 12:30:58 +00:00
{
copyFromArray ( other ) ;
return * this ;
}
2019-01-03 13:26:51 +00:00
# else //B3_ALLOW_ARRAY_COPY_OPERATOR
2017-08-01 12:30:58 +00:00
private :
2019-01-03 13:26:51 +00:00
B3_FORCE_INLINE b3AlignedObjectArray < T > & operator = ( const b3AlignedObjectArray < T > & other ) ;
# endif //B3_ALLOW_ARRAY_COPY_OPERATOR
2017-08-01 12:30:58 +00:00
protected :
2019-01-03 13:26:51 +00:00
B3_FORCE_INLINE int allocSize ( int size )
{
return ( size ? size * 2 : 1 ) ;
}
B3_FORCE_INLINE void copy ( int start , int end , T * dest ) const
{
int i ;
for ( i = start ; i < end ; + + i )
2017-08-01 12:30:58 +00:00
# ifdef B3_USE_PLACEMENT_NEW
2019-01-03 13:26:51 +00:00
new ( & dest [ i ] ) T ( m_data [ i ] ) ;
2017-08-01 12:30:58 +00:00
# else
2019-01-03 13:26:51 +00:00
dest [ i ] = m_data [ i ] ;
# endif //B3_USE_PLACEMENT_NEW
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
B3_FORCE_INLINE void init ( )
{
//PCK: added this line
m_ownsMemory = true ;
m_data = 0 ;
m_size = 0 ;
m_capacity = 0 ;
}
B3_FORCE_INLINE void destroy ( int first , int last )
{
int i ;
for ( i = first ; i < last ; i + + )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
m_data [ i ] . ~ T ( ) ;
2017-08-01 12:30:58 +00:00
}
2019-01-03 13:26:51 +00:00
}
B3_FORCE_INLINE void * allocate ( int size )
{
if ( size )
return m_allocator . allocate ( size ) ;
return 0 ;
}
B3_FORCE_INLINE void deallocate ( )
{
if ( m_data )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
//PCK: enclosed the deallocation in this block
if ( m_ownsMemory )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
m_allocator . deallocate ( m_data ) ;
2017-08-01 12:30:58 +00:00
}
2019-01-03 13:26:51 +00:00
m_data = 0 ;
2017-08-01 12:30:58 +00:00
}
2019-01-03 13:26:51 +00:00
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
public :
b3AlignedObjectArray ( )
{
init ( ) ;
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
~ b3AlignedObjectArray ( )
{
clear ( ) ;
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
///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 )
{
init ( ) ;
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
int otherSize = otherArray . size ( ) ;
resize ( otherSize ) ;
2022-05-16 22:02:51 +00:00
//don't use otherArray.copy, it can leak memory
for ( int i = 0 ; i < otherSize ; i + + )
{
m_data [ i ] = otherArray [ i ] ;
}
2019-01-03 13:26:51 +00:00
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
/// return the number of elements in the array
B3_FORCE_INLINE int size ( ) const
{
return m_size ;
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
B3_FORCE_INLINE const T & at ( int n ) const
{
b3Assert ( n > = 0 ) ;
b3Assert ( n < size ( ) ) ;
return m_data [ n ] ;
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
B3_FORCE_INLINE T & at ( int n )
{
b3Assert ( n > = 0 ) ;
b3Assert ( n < size ( ) ) ;
return m_data [ n ] ;
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
B3_FORCE_INLINE const T & operator [ ] ( int n ) const
{
b3Assert ( n > = 0 ) ;
b3Assert ( n < size ( ) ) ;
return m_data [ n ] ;
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
B3_FORCE_INLINE T & operator [ ] ( int n )
{
b3Assert ( n > = 0 ) ;
b3Assert ( n < size ( ) ) ;
return m_data [ n ] ;
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
///clear the array, deallocated memory. Generally it is better to use array.resize(0), to reduce performance overhead of run-time memory (de)allocations.
B3_FORCE_INLINE void clear ( )
{
destroy ( 0 , size ( ) ) ;
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
deallocate ( ) ;
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
init ( ) ;
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
B3_FORCE_INLINE void pop_back ( )
{
b3Assert ( m_size > 0 ) ;
m_size - - ;
m_data [ m_size ] . ~ T ( ) ;
}
///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.
///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.
B3_FORCE_INLINE void resizeNoInitialize ( int newsize )
{
int curSize = size ( ) ;
if ( newsize < curSize )
2017-08-01 12:30:58 +00:00
{
}
2019-01-03 13:26:51 +00:00
else
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
if ( newsize > size ( ) )
{
reserve ( newsize ) ;
}
//leave this uninitialized
2017-08-01 12:30:58 +00:00
}
2019-01-03 13:26:51 +00:00
m_size = newsize ;
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
B3_FORCE_INLINE void resize ( int newsize , const T & fillData = T ( ) )
{
int curSize = size ( ) ;
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
if ( newsize < curSize )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
for ( int i = newsize ; i < curSize ; i + + )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
m_data [ i ] . ~ T ( ) ;
2017-08-01 12:30:58 +00:00
}
}
2019-01-03 13:26:51 +00:00
else
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
if ( newsize > size ( ) )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
reserve ( newsize ) ;
2017-08-01 12:30:58 +00:00
}
2019-01-03 13:26:51 +00:00
# ifdef B3_USE_PLACEMENT_NEW
for ( int i = curSize ; i < newsize ; i + + )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
new ( & m_data [ i ] ) T ( fillData ) ;
2017-08-01 12:30:58 +00:00
}
2019-01-03 13:26:51 +00:00
# endif //B3_USE_PLACEMENT_NEW
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
m_size = newsize ;
}
B3_FORCE_INLINE T & expandNonInitializing ( )
{
int sz = size ( ) ;
if ( sz = = capacity ( ) )
{
reserve ( allocSize ( size ( ) ) ) ;
2017-08-01 12:30:58 +00:00
}
2019-01-03 13:26:51 +00:00
m_size + + ;
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
return m_data [ sz ] ;
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
B3_FORCE_INLINE T & expand ( const T & fillValue = T ( ) )
{
int sz = size ( ) ;
if ( sz = = capacity ( ) )
{
reserve ( allocSize ( size ( ) ) ) ;
}
m_size + + ;
2017-08-01 12:30:58 +00:00
# ifdef B3_USE_PLACEMENT_NEW
2019-01-03 13:26:51 +00:00
new ( & m_data [ sz ] ) T ( fillValue ) ; //use the in-place new (not really allocating heap memory)
2017-08-01 12:30:58 +00:00
# endif
2019-01-03 13:26:51 +00:00
return m_data [ sz ] ;
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
B3_FORCE_INLINE void push_back ( const T & _Val )
{
int sz = size ( ) ;
if ( sz = = capacity ( ) )
{
reserve ( allocSize ( size ( ) ) ) ;
}
2017-08-01 12:30:58 +00:00
# ifdef B3_USE_PLACEMENT_NEW
2019-01-03 13:26:51 +00:00
new ( & m_data [ m_size ] ) T ( _Val ) ;
2017-08-01 12:30:58 +00:00
# else
2019-01-03 13:26:51 +00:00
m_data [ size ( ) ] = _Val ;
# endif //B3_USE_PLACEMENT_NEW
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
m_size + + ;
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
/// return the pre-allocated (reserved) elements, this is at least as large as the total number of elements,see size() and reserve()
B3_FORCE_INLINE int capacity ( ) const
{
return m_capacity ;
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
B3_FORCE_INLINE void reserve ( int _Count )
{ // determine new minimum length of allocated storage
if ( capacity ( ) < _Count )
{ // not enough room, reallocate
T * s = ( T * ) allocate ( _Count ) ;
b3Assert ( s ) ;
if ( s = = 0 )
{
b3Error ( " b3AlignedObjectArray reserve out-of-memory \n " ) ;
_Count = 0 ;
m_size = 0 ;
2017-08-01 12:30:58 +00:00
}
2019-01-03 13:26:51 +00:00
copy ( 0 , size ( ) , s ) ;
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
destroy ( 0 , size ( ) ) ;
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
deallocate ( ) ;
//PCK: added this line
m_ownsMemory = true ;
m_data = s ;
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
m_capacity = _Count ;
}
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
class less
{
public :
bool operator ( ) ( const T & a , const T & b )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
return ( a < b ) ;
2017-08-01 12:30:58 +00:00
}
2019-01-03 13:26:51 +00:00
} ;
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
template < typename L >
void quickSortInternal ( const L & CompareFunc , int lo , int hi )
{
// lo is the lower index, hi is the upper index
// of the region of array a that is to be sorted
int i = lo , j = hi ;
T x = m_data [ ( lo + hi ) / 2 ] ;
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
// partition
do
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
while ( CompareFunc ( m_data [ i ] , x ) )
i + + ;
while ( CompareFunc ( x , m_data [ j ] ) )
j - - ;
if ( i < = j )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
swap ( i , j ) ;
i + + ;
j - - ;
2017-08-01 12:30:58 +00:00
}
2019-01-03 13:26:51 +00:00
} while ( i < = j ) ;
// recursion
if ( lo < j )
quickSortInternal ( CompareFunc , lo , j ) ;
if ( i < hi )
quickSortInternal ( CompareFunc , i , hi ) ;
}
template < typename L >
void quickSort ( const L & CompareFunc )
{
//don't sort 0 or 1 elements
if ( size ( ) > 1 )
{
quickSortInternal ( CompareFunc , 0 , size ( ) - 1 ) ;
2017-08-01 12:30:58 +00:00
}
2019-01-03 13:26:51 +00:00
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
///heap sort from http://www.csse.monash.edu.au/~lloyd/tildeAlgDS/Sort/Heap/
template < typename L >
void downHeap ( T * pArr , int k , int n , const L & CompareFunc )
{
/* PRE: a[k+1..N] is a heap */
/* POST: a[k..N] is a heap */
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
T temp = pArr [ k - 1 ] ;
/* k has child(s) */
while ( k < = n / 2 )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
int child = 2 * k ;
if ( ( child < n ) & & CompareFunc ( pArr [ child - 1 ] , pArr [ child ] ) )
{
child + + ;
}
/* pick larger child */
if ( CompareFunc ( temp , pArr [ child - 1 ] ) )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
/* move child up */
pArr [ k - 1 ] = pArr [ child - 1 ] ;
k = child ;
2017-08-01 12:30:58 +00:00
}
2019-01-03 13:26:51 +00:00
else
{
break ;
}
}
pArr [ k - 1 ] = temp ;
} /*downHeap*/
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
void swap ( int index0 , int index1 )
{
2017-08-01 12:30:58 +00:00
# ifdef B3_USE_MEMCPY
2019-01-03 13:26:51 +00:00
char temp [ sizeof ( T ) ] ;
memcpy ( temp , & m_data [ index0 ] , sizeof ( T ) ) ;
memcpy ( & m_data [ index0 ] , & m_data [ index1 ] , sizeof ( T ) ) ;
memcpy ( & m_data [ index1 ] , temp , sizeof ( T ) ) ;
2017-08-01 12:30:58 +00:00
# else
2019-01-03 13:26:51 +00:00
T temp = m_data [ index0 ] ;
m_data [ index0 ] = m_data [ index1 ] ;
m_data [ index1 ] = temp ;
# endif //B3_USE_PLACEMENT_NEW
}
2017-08-01 12:30:58 +00:00
template < typename L >
void heapSort ( const L & CompareFunc )
{
/* sort a[0..N-1], N.B. 0 to N-1 */
int k ;
int n = m_size ;
2019-01-03 13:26:51 +00:00
for ( k = n / 2 ; k > 0 ; k - - )
2017-08-01 12:30:58 +00:00
{
downHeap ( m_data , k , n , CompareFunc ) ;
}
/* a[1..N] is now a heap */
2019-01-03 13:26:51 +00:00
while ( n > = 1 )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
swap ( 0 , n - 1 ) ; /* largest of a[0..n-1] */
2017-08-01 12:30:58 +00:00
n = n - 1 ;
/* restore a[1..i-1] heap */
downHeap ( m_data , 1 , n , CompareFunc ) ;
2019-01-03 13:26:51 +00:00
}
2017-08-01 12:30:58 +00:00
}
///non-recursive binary search, assumes sorted array
2019-01-03 13:26:51 +00:00
int findBinarySearch ( const T & key ) const
2017-08-01 12:30:58 +00:00
{
int first = 0 ;
2019-01-03 13:26:51 +00:00
int last = size ( ) - 1 ;
2017-08-01 12:30:58 +00:00
//assume sorted array
2019-01-03 13:26:51 +00:00
while ( first < = last )
{
2017-08-01 12:30:58 +00:00
int mid = ( first + last ) / 2 ; // compute mid point.
2019-01-03 13:26:51 +00:00
if ( key > m_data [ mid ] )
2017-08-01 12:30:58 +00:00
first = mid + 1 ; // repeat search in top half.
2019-01-03 13:26:51 +00:00
else if ( key < m_data [ mid ] )
last = mid - 1 ; // repeat search in bottom half.
2017-08-01 12:30:58 +00:00
else
2019-01-03 13:26:51 +00:00
return mid ; // found it. return position /////
2017-08-01 12:30:58 +00:00
}
2019-01-03 13:26:51 +00:00
return size ( ) ; // failed to find key
2017-08-01 12:30:58 +00:00
}
2019-01-03 13:26:51 +00:00
int findLinearSearch ( const T & key ) const
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
int index = size ( ) ;
2017-08-01 12:30:58 +00:00
int i ;
2019-01-03 13:26:51 +00:00
for ( i = 0 ; i < size ( ) ; i + + )
2017-08-01 12:30:58 +00:00
{
if ( m_data [ i ] = = key )
{
index = i ;
break ;
}
}
return index ;
}
2019-01-03 13:26:51 +00:00
int findLinearSearch2 ( const T & key ) const
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
int index = - 1 ;
int i ;
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
for ( i = 0 ; i < size ( ) ; i + + )
{
if ( m_data [ i ] = = key )
{
index = i ;
break ;
}
}
return index ;
}
void remove ( const T & key )
{
2017-08-01 12:30:58 +00:00
int findIndex = findLinearSearch ( key ) ;
2019-01-03 13:26:51 +00:00
if ( findIndex < size ( ) )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
swap ( findIndex , size ( ) - 1 ) ;
2017-08-01 12:30:58 +00:00
pop_back ( ) ;
}
}
//PCK: whole function
2019-01-03 13:26:51 +00:00
void initializeFromBuffer ( void * buffer , int size , int capacity )
2017-08-01 12:30:58 +00:00
{
clear ( ) ;
m_ownsMemory = false ;
m_data = ( T * ) buffer ;
m_size = size ;
m_capacity = capacity ;
}
void copyFromArray ( const b3AlignedObjectArray & otherArray )
{
int otherSize = otherArray . size ( ) ;
2019-01-03 13:26:51 +00:00
resize ( otherSize ) ;
2022-05-16 22:02:51 +00:00
//don't use otherArray.copy, it can leak memory
for ( int i = 0 ; i < otherSize ; i + + )
{
m_data [ i ] = otherArray [ i ] ;
}
2017-08-01 12:30:58 +00:00
}
2018-09-07 14:11:04 +00:00
void removeAtIndex ( int index )
2019-01-03 13:26:51 +00:00
{
if ( index < size ( ) )
{
swap ( index , size ( ) - 1 ) ;
pop_back ( ) ;
}
}
2017-08-01 12:30:58 +00:00
} ;
2019-01-03 13:26:51 +00:00
# endif //B3_OBJECT_ARRAY__