Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
Array.inl
1 /*
2 Copyright (c) 2011, Michael Kazhdan and Ming Chuang
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7 
8 Redistributions of source code must retain the above copyright notice, this list of
9 conditions and the following disclaimer. Redistributions in binary form must reproduce
10 the above copyright notice, this list of conditions and the following disclaimer
11 in the documentation and/or other materials provided with the distribution.
12 
13 Neither the name of the Johns Hopkins University nor the names of its contributors
14 may be used to endorse or promote products derived from this software without specific
15 prior written permission.
16 
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
18 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES
19 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
20 SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26 DAMAGE.
27 */
28 #define FULL_ARRAY_DEBUG 0 // Note that this is not thread-safe
29 
30 #include <stdio.h>
31 #include <emmintrin.h>
32 #include <vector>
33 #ifdef _WIN32
34 #include <windows.h>
35 #endif // _WIN32
36 #include <stddef.h>
37 
38 inline bool isfinitef( float fp ){ float f=fp; return ((*(unsigned *)&f)&0x7f800000)!=0x7f800000; }
39 
40 
41 template< class C > bool IsValid( const C& c );
42 #if _DEBUG
43 template< > inline bool IsValid< float >( const float& f ) { return isfinitef( f ) && ( f==0.f || abs(f)>1e-31f ); }
44 #else // !_DEBUG
45 template< > inline bool IsValid< float >( const float& f ) { return isfinitef( f ); }
46 #endif // _DEBUG
47 template< > inline bool IsValid< __m128 >( const __m128& m )
48 {
49  const __m128* addr = &m;
50  if( size_t(addr) & 15 ) return false;
51  else return true;
52 }
53 template< class C > inline bool IsValid( const C& c ){ return true; }
54 
55 
56 #if FULL_ARRAY_DEBUG
57 class DebugMemoryInfo
58 {
59 public:
60  const void* address;
61  char name[512];
62 };
63 static std::vector< DebugMemoryInfo > memoryInfo;
64 #endif // FULL_ARRAY_DEBUG
65 
66 template< class C >
67 class Array
68 {
69  void _assertBounds( long long idx ) const
70  {
71  if( idx<min || idx>=max )
72  {
73  fprintf( stderr , "Array index out-of-bounds: %lld <= %lld < %lld\n" , min , idx , max );
74  ASSERT( 0 );
75  exit( 0 );
76  }
77  }
78 protected:
79  C *data , *_data;
80  long long min , max;
81 #if FULL_ARRAY_DEBUG
82  static void _AddMemoryInfo( const void* ptr , const char* name )
83  {
84  size_t sz = memoryInfo.size();
85  memoryInfo.resize( sz + 1 );
86  memoryInfo[sz].address = ptr;
87  if( name ) strcpy( memoryInfo[sz].name , name );
88  else memoryInfo[sz].name[0] = 0;
89  }
90  static void _RemoveMemoryInfo( const void* ptr )
91  {
92  {
93  size_t idx;
94  for( idx=0 ; idx<memoryInfo.size( ) ; idx++ ) if( memoryInfo[idx].address==ptr ) break;
95  if( idx==memoryInfo.size() )
96  {
97  fprintf( stderr , "Could not find memory in address table\n" );
98  ASSERT( 0 );
99  }
100  else
101  {
102  memoryInfo[idx] = memoryInfo[memoryInfo.size()-1];
103  memoryInfo.pop_back( );
104  }
105  }
106  }
107 #endif // FULL_ARRAY_DEBUG
108 
109 public:
110  long long minimum( void ) const { return min; }
111  long long maximum( void ) const { return max; }
112 
113  static inline Array New( size_t size , const char* name=NULL )
114  {
115  Array a;
116  a._data = a.data = new C[size];
117  a.min = 0;
118 #pragma message( "[WARNING] Casting unsigned to signed" )
119  a.max = ( long long ) size;
120 #if FULL_ARRAY_DEBUG
121  _AddMemoryInfo( a._data , name );
122 #endif // FULL_ARRAY_DEBUG
123  return a;
124  }
125  static inline Array Alloc( size_t size , bool clear , const char* name=NULL )
126  {
127  Array a;
128  a._data = a.data = ( C* ) malloc( size * sizeof( C ) );
129  if( clear ) memset( a.data , 0 , size * sizeof( C ) );
130 // else memset( a.data , -1 , size * sizeof( C ) );
131  a.min = 0;
132 #pragma message( "[WARNING] Casting unsigned to signed" )
133  a.max = ( long long ) size;
134 #if FULL_ARRAY_DEBUG
135  _AddMemoryInfo( a._data , name );
136 #endif // FULL_ARRAY_DEBUG
137  return a;
138  }
139  static inline Array AlignedAlloc( size_t size , size_t alignment , bool clear , const char* name=NULL )
140  {
141  Array a;
142  a.data = ( C* ) aligned_malloc( sizeof(C) * size , alignment );
143  a._data = ( C* )( ( ( void** )a.data )[-1] );
144  if( clear ) memset( a.data , 0 , size * sizeof( C ) );
145 // else memset( a.data , -1 , size * sizeof( C ) );
146  a.min = 0;
147 #pragma message( "[WARNING] Casting unsigned to signed" )
148  a.max = ( long long ) size;
149 #if FULL_ARRAY_DEBUG
150  _AddMemoryInfo( a._data , name );
151 #endif // FULL_ARRAY_DEBUG
152  return a;
153  }
154  static inline Array ReAlloc( Array& a , size_t size , bool clear , const char* name=NULL )
155  {
156  Array _a;
157  _a._data = _a.data = ( C* ) realloc( a.data , size * sizeof( C ) );
158  if( clear ) memset( _a.data , 0 , size * sizeof( C ) );
159 #if FULL_ARRAY_DEBUG
160  _RemoveMemoryInfo( a._data );
161 #endif // FULL_ARRAY_DEBUG
162  a._data = NULL;
163  _a.min = 0;
164 #pragma message( "[WARNING] Casting unsigned to signed" )
165  _a.max = ( long long ) size;
166 #if FULL_ARRAY_DEBUG
167  _AddMemoryInfo( _a._data , name );
168 #endif // FULL_ARRAY_DEBUG
169  return _a;
170  }
171 
172  Array( void )
173  {
174  data = _data = NULL;
175  min = max = 0;
176  }
177  template< class D >
178  Array( Array< D >& a )
179  {
180  _data = NULL;
181  if( !a )
182  {
183  data = NULL;
184  min = max = 0;
185  }
186  else
187  {
188  // [WARNING] Chaning szC and szD to size_t causes some really strange behavior.
189  long long szC = sizeof( C );
190  long long szD = sizeof( D );
191  data = (C*)&a[0];
192  min = ( a.minimum() * szD ) / szC;
193  max = ( a.maximum() * szD ) / szC;
194  if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD )
195  {
196  fprintf( stderr , "Could not convert array [ %lld , %lld ] * %lld => [ %lld , %lld ] * %lld\n" , a.minimum() , a.maximum() , szD , min , max , szC );
197  ASSERT( 0 );
198  exit( 0 );
199  }
200  }
201  }
202  static Array FromPointer( C* data , long long max )
203  {
204  Array a;
205  a._data = NULL;
206  a.data = data;
207  a.min = 0;
208  a.max = max;
209  return a;
210  }
211  static Array FromPointer( C* data , long long min , long long max )
212  {
213  Array a;
214  a._data = NULL;
215  a.data = data;
216  a.min = min;
217  a.max = max;
218  return a;
219  }
220  inline bool operator == ( const Array< C >& a ) const { return data==a.data; }
221  inline bool operator != ( const Array< C >& a ) const { return data!=a.data; }
222  inline bool operator == ( const C* c ) const { return data==c; }
223  inline bool operator != ( const C* c ) const { return data!=c; }
224  inline C* operator -> ( void )
225  {
226  _assertBounds( 0 );
227  return data;
228  }
229  inline const C* operator -> ( ) const
230  {
231  _assertBounds( 0 );
232  return data;
233  }
234  inline C& operator[]( long long idx )
235  {
236  _assertBounds( idx );
237  return data[idx];
238  }
239  inline const C& operator[]( long long idx ) const
240  {
241  _assertBounds( idx );
242  return data[idx];
243  }
244  inline Array operator + ( int idx ) const
245  {
246  Array a;
247  a._data = _data;
248  a.data = data+idx;
249  a.min = min-idx;
250  a.max = max-idx;
251  return a;
252  }
253  inline Array operator + ( long long idx ) const
254  {
255  Array a;
256  a._data = _data;
257  a.data = data+idx;
258  a.min = min-idx;
259  a.max = max-idx;
260  return a;
261  }
262  inline Array operator + ( unsigned int idx ) const
263  {
264  Array a;
265  a._data = _data;
266  a.data = data+idx;
267  a.min = min-idx;
268  a.max = max-idx;
269  return a;
270  }
271  inline Array operator + ( unsigned long long idx ) const
272  {
273  Array a;
274  a._data = _data;
275  a.data = data+idx;
276  a.min = min-idx;
277  a.max = max-idx;
278  return a;
279  }
280  inline Array& operator += ( int idx )
281  {
282  min -= idx;
283  max -= idx;
284  data += idx;
285  return (*this);
286  }
287  inline Array& operator += ( long long idx )
288  {
289  min -= idx;
290  max -= idx;
291  data += idx;
292  return (*this);
293  }
294  inline Array& operator += ( unsigned int idx )
295  {
296  min -= idx;
297  max -= idx;
298  data += idx;
299  return (*this);
300  }
301  inline Array& operator += ( unsigned long long idx )
302  {
303  min -= idx;
304  max -= idx;
305  data += idx;
306  return (*this);
307  }
308  inline Array& operator ++ ( void ) { return (*this) += 1; }
309  Array operator - ( int idx ) const { return (*this) + (-idx); }
310  Array operator - ( long long idx ) const { return (*this) + (-idx); }
311  Array operator - ( unsigned int idx ) const { return (*this) + (-idx); }
312  Array operator - ( unsigned long long idx ) const { return (*this) + (-idx); }
313  Array& operator -= ( int idx ) { return (*this) += (-idx); }
314  Array& operator -= ( long long idx ) { return (*this) += (-idx); }
315  Array& operator -= ( unsigned int idx ) { return (*this) += (-idx); }
316  Array& operator -= ( unsigned long long idx ) { return (*this) += (-idx); }
317  Array& operator -- ( void ) { return (*this) -= 1; }
318  long long operator - ( const Array& a ) const { return ( long long )( data - a.data ); }
319 
320  void Free( void )
321  {
322  if( _data )
323  {
324  free( _data );
325 #if FULL_ARRAY_DEBUG
326  _RemoveMemoryInfo( _data );
327 #endif // FULL_ARRAY_DEBUG
328  }
329  (*this) = Array( );
330  }
331  void Delete( void )
332  {
333  if( _data )
334  {
335  delete[] _data;
336 #if FULL_ARRAY_DEBUG
337  _RemoveMemoryInfo( _data );
338 #endif // FULL_ARRAY_DEBUG
339  }
340  (*this) = Array( );
341  }
342  C* pointer( void ){ return data; }
343  const C* pointer( void ) const { return data; }
344  bool operator !( void ) const { return data==NULL; }
345  operator bool( ) const { return data!=NULL; }
346 };
347 
348 template< class C >
350 {
351  void _assertBounds( long long idx ) const
352  {
353  if( idx<min || idx>=max )
354  {
355  fprintf( stderr , "ConstArray index out-of-bounds: %lld <= %lld < %lld\n" , min , idx , max );
356  ASSERT( 0 );
357  exit( 0 );
358  }
359  }
360 protected:
361  const C *data;
362  long long min , max;
363 public:
364  long long minimum( void ) const { return min; }
365  long long maximum( void ) const { return max; }
366 
367  inline ConstArray( void )
368  {
369  data = NULL;
370  min = max = 0;
371  }
372  inline ConstArray( const Array< C >& a )
373  {
374  // [WARNING] Changing szC and szD to size_t causes some really strange behavior.
375  data = ( const C* )a.pointer( );
376  min = a.minimum();
377  max = a.maximum();
378  }
379  template< class D >
380  inline ConstArray( const Array< D >& a )
381  {
382  // [WARNING] Changing szC and szD to size_t causes some really strange behavior.
383  long long szC = ( long long ) sizeof( C );
384  long long szD = ( long long ) sizeof( D );
385  data = ( const C* )a.pointer( );
386  min = ( a.minimum() * szD ) / szC;
387  max = ( a.maximum() * szD ) / szC;
388  if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD )
389  {
390 // fprintf( stderr , "Could not convert const array [ %lld , %lld ] * %lld => [ %lld , %lld ] * %lld\n" , a.minimum() , a.maximum() , szD , min , max , szC );
391  fprintf( stderr , "Could not convert const array [ %lld , %lld ] * %lld => [ %lld , %lld ] * %lld\n %lld %lld %lld\n" , a.minimum() , a.maximum() , szD , min , max , szC , a.minimum() , a.minimum()*szD , (a.minimum()*szD)/szC );
392  ASSERT( 0 );
393  exit( 0 );
394  }
395  }
396  template< class D >
397  inline ConstArray( const ConstArray< D >& a )
398  {
399  // [WARNING] Chaning szC and szD to size_t causes some really strange behavior.
400  long long szC = sizeof( C );
401  long long szD = sizeof( D );
402  data = ( const C*)a.pointer( );
403  min = ( a.minimum() * szD ) / szC;
404  max = ( a.maximum() * szD ) / szC;
405  if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD )
406  {
407  fprintf( stderr , "Could not convert array [ %lld , %lld ] * %lld => [ %lld , %lld ] * %lld\n" , a.minimum() , a.maximum() , szD , min , max , szC );
408  ASSERT( 0 );
409  exit( 0 );
410  }
411  }
412  static ConstArray FromPointer( const C* data , long long max )
413  {
414  ConstArray a;
415  a.data = data;
416  a.min = 0;
417  a.max = max;
418  return a;
419  }
420  static ConstArray FromPointer( const C* data , long long min , long long max )
421  {
422  ConstArray a;
423  a.data = data;
424  a.min = min;
425  a.max = max;
426  return a;
427  }
428 
429  inline bool operator == ( const ConstArray< C >& a ) const { return data==a.data; }
430  inline bool operator != ( const ConstArray< C >& a ) const { return data!=a.data; }
431  inline bool operator == ( const C* c ) const { return data==c; }
432  inline bool operator != ( const C* c ) const { return data!=c; }
433  inline const C* operator -> ( void )
434  {
435  _assertBounds( 0 );
436  return data;
437  }
438  inline const C& operator[]( long long idx ) const
439  {
440  _assertBounds( idx );
441  return data[idx];
442  }
443  inline ConstArray operator + ( int idx ) const
444  {
445  ConstArray a;
446  a.data = data+idx;
447  a.min = min-idx;
448  a.max = max-idx;
449  return a;
450  }
451  inline ConstArray operator + ( long long idx ) const
452  {
453  ConstArray a;
454  a.data = data+idx;
455  a.min = min-idx;
456  a.max = max-idx;
457  return a;
458  }
459  inline ConstArray operator + ( unsigned int idx ) const
460  {
461  ConstArray a;
462  a.data = data+idx;
463  a.min = min-idx;
464  a.max = max-idx;
465  return a;
466  }
467  inline ConstArray operator + ( unsigned long long idx ) const
468  {
469  ConstArray a;
470  a.data = data+idx;
471  a.min = min-idx;
472  a.max = max-idx;
473  return a;
474  }
475  inline ConstArray& operator += ( int idx )
476  {
477  min -= idx;
478  max -= idx;
479  data += idx;
480  return (*this);
481  }
482  inline ConstArray& operator += ( long long idx )
483  {
484  min -= idx;
485  max -= idx;
486  data += idx;
487  return (*this);
488  }
489  inline ConstArray& operator += ( unsigned int idx )
490  {
491  min -= idx;
492  max -= idx;
493  data += idx;
494  return (*this);
495  }
496  inline ConstArray& operator += ( unsigned long long idx )
497  {
498  min -= idx;
499  max -= idx;
500  data += idx;
501  return (*this);
502  }
503  inline ConstArray& operator ++ ( void ) { return (*this) += 1; }
504  ConstArray operator - ( int idx ) const { return (*this) + (-idx); }
505  ConstArray operator - ( long long idx ) const { return (*this) + (-idx); }
506  ConstArray operator - ( unsigned int idx ) const { return (*this) + (-idx); }
507  ConstArray operator - ( unsigned long long idx ) const { return (*this) + (-idx); }
508  ConstArray& operator -= ( int idx ) { return (*this) += (-idx); }
509  ConstArray& operator -= ( long long idx ) { return (*this) += (-idx); }
510  ConstArray& operator -= ( unsigned int idx ) { return (*this) += (-idx); }
511  ConstArray& operator -= ( unsigned long long idx ) { return (*this) += (-idx); }
512  ConstArray& operator -- ( void ) { return (*this) -= 1; }
513  long long operator - ( const ConstArray& a ) const { return ( long long )( data - a.data ); }
514  long long operator - ( const Array< C >& a ) const { return ( long long )( data - a.pointer() ); }
515 
516  const C* pointer( void ) const { return data; }
517  bool operator !( void ) { return data==NULL; }
518  operator bool( ) { return data!=NULL; }
519 };
520 
521 #if FULL_ARRAY_DEBUG
522 inline void PrintMemoryInfo( void ){ for( size_t i=0 ; i<memoryInfo.size() ; i++ ) printf( "%d] %s\n" , i , memoryInfo[i].name ); }
523 #endif // FULL_ARRAY_DEBUG
524 template< class C >
525 Array< C > memcpy( Array< C > destination , const void* source , size_t size )
526 {
527  if( size>destination.maximum()*sizeof(C) )
528  {
529  fprintf( stderr , "Size of copy exceeds destination maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( destination.maximum()*sizeof( C ) ) );
530  ASSERT( 0 );
531  exit( 0 );
532  }
533  if( size ) memcpy( &destination[0] , source , size );
534  return destination;
535 }
536 template< class C , class D >
537 Array< C > memcpy( Array< C > destination , Array< D > source , size_t size )
538 {
539  if( size>destination.maximum()*sizeof( C ) )
540  {
541  fprintf( stderr , "Size of copy exceeds destination maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( destination.maximum()*sizeof( C ) ) );
542  ASSERT( 0 );
543  exit( 0 );
544  }
545  if( size>source.maximum()*sizeof( D ) )
546  {
547  fprintf( stderr , "Size of copy exceeds source maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( source.maximum()*sizeof( D ) ) );
548  ASSERT( 0 );
549  exit( 0 );
550  }
551  if( size ) memcpy( &destination[0] , &source[0] , size );
552  return destination;
553 }
554 template< class C , class D >
555 Array< C > memcpy( Array< C > destination , ConstArray< D > source , size_t size )
556 {
557  if( size>destination.maximum()*sizeof( C ) )
558  {
559  fprintf( stderr , "Size of copy exceeds destination maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( destination.maximum()*sizeof( C ) ) );
560  ASSERT( 0 );
561  exit( 0 );
562  }
563  if( size>source.maximum()*sizeof( D ) )
564  {
565  fprintf( stderr , "Size of copy exceeds source maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( source.maximum()*sizeof( D ) ) );
566  ASSERT( 0 );
567  exit( 0 );
568  }
569  if( size ) memcpy( &destination[0] , &source[0] , size );
570  return destination;
571 }
572 template< class D >
573 void* memcpy( void* destination , Array< D > source , size_t size )
574 {
575  if( size>source.maximum()*sizeof( D ) )
576  {
577  fprintf( stderr , "Size of copy exceeds source maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( source.maximum()*sizeof( D ) ) );
578  ASSERT( 0 );
579  exit( 0 );
580  }
581  if( size ) memcpy( destination , &source[0] , size );
582  return destination;
583 }
584 template< class D >
585 void* memcpy( void* destination , ConstArray< D > source , size_t size )
586 {
587  if( size>source.maximum()*sizeof( D ) )
588  {
589  fprintf( stderr , "Size of copy exceeds source maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( source.maximum()*sizeof( D ) ) );
590  ASSERT( 0 );
591  exit( 0 );
592  }
593  if( size ) memcpy( destination , &source[0] , size );
594  return destination;
595 }
596 template< class C >
597 Array< C > memset( Array< C > destination , int value , size_t size )
598 {
599  if( size>destination.maximum()*sizeof( C ) )
600  {
601  fprintf( stderr , "Size of set exceeds destination maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( destination.maximum()*sizeof( C ) ) );
602  ASSERT( 0 );
603  exit( 0 );
604  }
605  if( size ) memset( &destination[0] , value , size );
606  return destination;
607 }
608 
609 template< class C >
610 size_t fread( Array< C > destination , size_t eSize , size_t count , FILE* fp )
611 {
612  if( count*eSize>destination.maximum()*sizeof( C ) )
613  {
614  fprintf( stderr , "Size of read exceeds source maximum: %lld > %lld\n" , ( long long )( count*eSize ) , ( long long )( destination.maximum()*sizeof( C ) ) );
615  ASSERT( 0 );
616  exit( 0 );
617  }
618  return fread( &destination[0] , eSize , count , fp );
619 }
620 template< class C >
621 size_t fwrite( Array< C > source , size_t eSize , size_t count , FILE* fp )
622 {
623  if( count*eSize>source.maximum()*sizeof( C ) )
624  {
625  fprintf( stderr , "Size of write exceeds source maximum: %lld > %lld\n" , ( long long )( count*eSize ) , ( long long )( source.maximum()*sizeof( C ) ) );
626  ASSERT( 0 );
627  exit( 0 );
628  }
629  return fwrite( &source[0] , eSize , count , fp );
630 }
631 template< class C >
632 size_t fwrite( ConstArray< C > source , size_t eSize , size_t count , FILE* fp )
633 {
634  if( count*eSize>source.maximum()*sizeof( C ) )
635  {
636  fprintf( stderr , "Size of write exceeds source maximum: %lld > %lld\n" , ( long long )( count*eSize ) , ( long long )( source.maximum()*sizeof( C ) ) );
637  ASSERT( 0 );
638  exit( 0 );
639  }
640  return fwrite( &source[0] , eSize , count , fp );
641 }
642 template< class C >
643 void qsort( Array< C > base , size_t numElements , size_t elementSize , int (*compareFunction)( const void* , const void* ) )
644 {
645  if( sizeof(C)!=elementSize )
646  {
647  fprintf( stderr , "Element sizes differ: %lld != %lld\n" , ( long long )( sizeof(C) ) , ( long long )( elementSize ) );
648  ASSERT( 0 );
649  exit( 0 );
650  }
651  if( base.minimum()>0 || base.maximum()<numElements )
652  {
653  fprintf( stderr , "Array access out of bounds: %lld <= 0 <= %lld <= %lld\n" , base.minimum() , base.maximum() , ( long long )( numElements ) );
654  ASSERT( 0 );
655  exit( 0 );
656  }
657  qsort( base.pointer() , numElements , elementSize , compareFunction );
658 }
Definition: Array.inl:67