TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Array.h
Go to the documentation of this file.
1 
14 #ifndef G3D_Array_h
15 #define G3D_Array_h
16 
17 #include "G3D/platform.h"
18 #include "G3D/debug.h"
19 #include "G3D/MemoryManager.h"
20 #include "G3D/System.h"
21 #ifdef G3D_DEBUG
22 // For formatting error messages
23 # include "G3D/format.h"
24 #endif
25 #include <vector>
26 #include <algorithm>
27 
28 #ifdef _MSC_VER
29 # include <new>
30 
31 # pragma warning (push)
32  // debug information too long
33 # pragma warning( disable : 4312)
34 # pragma warning( disable : 4786)
35 #endif
36 
37 
38 namespace G3D {
39 
43 const bool DONT_SHRINK_UNDERLYING_ARRAY = false;
44 
46 const int SORT_INCREASING = 1;
48 const int SORT_DECREASING = -1;
49 
50 
51 
94 template <class T, size_t MIN_ELEMENTS = 10>
95 class Array {
96 
97 private:
100  static const size_t MIN_BYTES = 32;
101 
103  T* data;
104 
105  size_t num;
106  size_t numAllocated;
107 
109 
112  void init(size_t n, const MemoryManager::Ref& m) {
113  m_memoryManager = m;
114  this->num = 0;
115  this->numAllocated = 0;
116  data = NULL;
117  if (n > 0) {
118  resize(n);
119  } else {
120  data = NULL;
121  }
122  }
123 
124  void _copy(const Array &other) {
125  init(other.num, MemoryManager::create());
126  for (size_t i = 0; i < num; ++i) {
127  data[i] = other.data[i];
128  }
129  }
130 
135  inline bool inArray(const T* address) {
136  return (address >= data) && (address < data + num);
137  }
138 
139 
141  static bool __cdecl compareGT(const T& a, const T& b) {
142  return a > b;
143  }
144 
145 
151  void realloc(size_t oldNum) {
152  T* oldData = data;
153 
154  // The allocation is separate from the constructor invocation because we don't want
155  // to pay for the cost of constructors until the newly allocated
156  // elements are actually revealed to the application. They
157  // will be constructed in the resize() method.
158 
159  data = (T*)m_memoryManager->alloc(sizeof(T) * numAllocated);
160  alwaysAssertM(data, "Memory manager returned NULL: out of memory?");
161 
162  // Call the copy constructors
163  {const size_t N = G3D::min(oldNum, numAllocated);
164  const T* end = data + N;
165  T* oldPtr = oldData;
166  for (T* ptr = data; ptr < end; ++ptr, ++oldPtr) {
167 
168  // Use placement new to invoke the constructor at the location
169  // that we determined. Use the copy constructor to make the assignment.
170  const T* constructed = new (ptr) T(*oldPtr);
171 
172  (void)constructed;
173  debugAssertM(constructed == ptr,
174  "new returned a different address than the one provided by Array.");
175  }}
176 
177  // Call destructors on the old array (if there is no destructor, this will compile away)
178  {const T* end = oldData + oldNum;
179  for (T* ptr = oldData; ptr < end; ++ptr) {
180  ptr->~T();
181  }}
182 
183  m_memoryManager->free(oldData);
184  }
185 
186 public:
191  Array& operator=(const Array& other) {
192  resize(other.num);
193  for (int i = 0; i < (int)num; ++i) {
194  data[i] = other[i];
195  }
196  return *this;
197  }
198 
199  Array& operator=(const std::vector<T>& other) {
200  resize(other.size());
201  for (size_t i = 0; i < num; ++i) {
202  data[i] = other[i];
203  }
204  return *this;
205  }
206 
207 public:
208 
214  typedef T* Iterator;
216  typedef const T* ConstIterator;
217 
219  typedef Iterator iterator;
221  typedef ConstIterator const_iterator;
223  typedef T value_type;
225  typedef int size_type;
227  typedef int difference_type;
228 
233  Iterator begin() {
234  return data;
235  }
236 
237  ConstIterator begin() const {
238  return data;
239  }
244  ConstIterator end() const {
245  return data + num;
246  }
247 
248  Iterator end() {
249  return data + num;
250  }
251 
256  T* getCArray() {
257  return data;
258  }
259 
266  alwaysAssertM(a.memoryManager() == b.memoryManager(), "The arrays are required to have the same memory manager");
267  std::swap(a.data, b.data);
268  std::swap(a.num, b.num);
269  std::swap(a.numAllocated, b.numAllocated);
270  }
271 
276  const T* getCArray() const {
277  return data;
278  }
279 
281  Array() : num(0) {
283  }
284 
285 
287  explicit Array(const T& v0) {
289  (*this)[0] = v0;
290  }
291 
293  Array(const T& v0, const T& v1) {
295  (*this)[0] = v0;
296  (*this)[1] = v1;
297  }
298 
300  Array(const T& v0, const T& v1, const T& v2) {
302  (*this)[0] = v0;
303  (*this)[1] = v1;
304  (*this)[2] = v2;
305  }
306 
308  Array(const T& v0, const T& v1, const T& v2, const T& v3) {
310  (*this)[0] = v0;
311  (*this)[1] = v1;
312  (*this)[2] = v2;
313  (*this)[3] = v3;
314  }
315 
317  Array(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) {
319  (*this)[0] = v0;
320  (*this)[1] = v1;
321  (*this)[2] = v2;
322  (*this)[3] = v3;
323  (*this)[4] = v4;
324  }
325 
326 
330  //TODO: patch rest of the API to prevent returning Arrays by value, then make explicit
331  Array(const Array& other) : num(0) {
332  _copy(other);
333  }
334 
335  explicit Array(const std::vector<T>& other) : num(0), data(NULL) {
336  *this = other;
337  }
338 
339 
340  /* Sets this to hold the same contents as other, with num = numAllocated (no unused allocated space) */
341  void copyFrom(const Array<T>& other) {
342  resize(0);
343  append(other);
344  }
345 
346 
348  void copyPOD(const Array<T>& other) {
349  if (numAllocated < other.num) {
350  m_memoryManager->free(data);
351  data = NULL;
352  if (other.data) {
353  data = (T*)m_memoryManager->alloc(sizeof(T) * other.num);
354  }
355  numAllocated = other.num;
356  }
357 
358  num = other.num;
359  if (other.data && (num > 0)) {
360  System::memcpy(data, other.data, sizeof(T) * num);
361  }
362  }
363 
366  void appendPOD(const Array<T>& other) {
367  const size_t oldSize = num;
368  num += other.num;
369  if (numAllocated < num) {
370  alwaysAssertM(other.data, "non-zero array with no allocated space");
371  T* old = data;
372  data = (T*)m_memoryManager->alloc(sizeof(T) * num);
373  System::memcpy(data, old, sizeof(T) * oldSize);
374  m_memoryManager->free(old);
375  numAllocated = num;
376  }
377  if (other.data) {
378  System::memcpy((data + oldSize), other.data, sizeof(T) * other.num);
379  }
380  }
381 
389  ~Array() {
390  // Invoke the destructors on the elements
391  for (size_t i = 0; i < num; ++i) {
392  (data + i)->~T();
393  }
394 
395  m_memoryManager->free(data);
396  // Set to 0 in case this Array is global and gets referenced during app exit
397  data = NULL;
398  num = 0;
399  numAllocated = 0;
400  }
401 
407  void clear(bool shrink = true) {
408  resize(0, shrink);
409  }
410 
412  clear();
413  debugAssert(data == NULL);
414  m_memoryManager = m;
415  }
416 
419  void fastClear() {
420  clear(false);
421  }
422 
424  return m_memoryManager;
425  }
426 
430  inline int size() const {
431  return (int)num;
432  }
433 
438  inline int length() const {
439  return size();
440  }
441 
446  void fastRemove(int index, bool shrinkIfNecessary = false) {
447  debugAssert(index < (int)num);
448  data[index] = data[num - 1];
449  resize(size() - 1, shrinkIfNecessary);
450  }
451 
452 
456  void insert(int n, const T& value) {
457  // Add space for the extra element
458  resize(num + 1, false);
459 
460  for (size_t i = (size_t)(num - 1); i > (size_t)n; --i) {
461  data[i] = data[i - 1];
462  }
463  data[n] = value;
464  }
465 
467  void setAll(const T& value) {
468  for (size_t i = 0; i < num; ++i) {
469  data[i] = value;
470  }
471  }
472 
476  void trimToSize() {
477  if (size() != capacity()) {
478  size_t oldNum = numAllocated;
479  numAllocated = size();
480  realloc(oldNum);
481  }
482  }
483 
490  void resize(size_t n, bool shrinkIfNecessary = true) {
491  alwaysAssertM(n < 0xFFFFFFFF, "This implementation does not support arrays with more than 2^32 elements, although the size in memory may be larger.");
492  if (num == n) {
493  return;
494  }
495 
496  size_t oldNum = num;
497  num = n;
498 
499  // Call the destructors on newly hidden elements if there are any
500  for (size_t i = num; i < oldNum; ++i) {
501  (data + i)->~T();
502  }
503 
504  // Once allocated, always maintain MIN_ELEMENTS elements or 32 bytes, whichever is higher.
505  const size_t minSize = G3D::max(MIN_ELEMENTS, (size_t)(MIN_BYTES / sizeof(T)));
506 
507  if ((MIN_ELEMENTS == 0) && (MIN_BYTES == 0) && (n == 0) && shrinkIfNecessary) {
508  // Deallocate the array completely
509  numAllocated = 0;
510  m_memoryManager->free(data);
511  data = NULL;
512  return;
513  }
514 
515  if (num > numAllocated) {
516  // Grow the underlying array
517 
518  if (numAllocated == 0) {
519  // First allocation; grow to exactly the size requested to avoid wasting space.
520  numAllocated = n;
521  debugAssert(oldNum == 0);
522  realloc(oldNum);
523  } else {
524 
525  if (num < minSize) {
526  // Grow to at least the minimum size
527  numAllocated = minSize;
528 
529  } else {
530 
531  // Increase the underlying size of the array. Grow aggressively
532  // up to 64k, less aggressively up to 400k, and then grow relatively
533  // slowly (1.5x per resize) to avoid excessive space consumption.
534  //
535  // These numbers are tweaked according to performance tests.
536 
537  double growFactor = 3.0f;
538 
539  size_t oldSizeBytes = numAllocated * sizeof(T);
540  if (oldSizeBytes > 10000000) {
541  // Conserve memory more tightly above 10 MB
542  growFactor = 1.2f;
543  } else if (oldSizeBytes > 400000) {
544  // Avoid bloat above 400k
545  growFactor = 1.5f;
546  } else if (oldSizeBytes > 64000) {
547  // This is what std:: uses at all times
548  growFactor = 2.0f;
549  }
550 
551  numAllocated = (num - numAllocated) + (size_t)(numAllocated * growFactor);
552 
553  if (numAllocated < minSize) {
554  numAllocated = minSize;
555  }
556  }
557 
558  realloc(oldNum);
559  }
560 
561  } else if ((num <= numAllocated / 3) && shrinkIfNecessary && (num > minSize)) {
562  // Shrink the underlying array
563 
564  // Only copy over old elements that still remain after resizing
565  // (destructors were called for others if we're shrinking)
566  realloc(min(num, oldNum));
567 
568  }
569 
570  // Call the constructors on newly revealed elements.
571  // Do not use parens because we don't want the intializer
572  // invoked for POD types.
573  for (size_t i = oldNum; i < num; ++i) {
574  new (data + i) T;
575  }
576  }
577 
583  inline void append(const T& value) {
584 
585  if (num < numAllocated) {
586  // This is a simple situation; just stick it in the next free slot using
587  // the copy constructor.
588  new (data + num) T(value);
589  ++num;
590  } else if (inArray(&value)) {
591  // The value was in the original array; resizing
592  // is dangerous because it may move the value
593  // we have a reference to.
594  T tmp = value;
595  append(tmp);
596  } else {
597  // Here we run the empty initializer where we don't have to, but
598  // this simplifies the computation.
599  resize(num + 1, DONT_SHRINK_UNDERLYING_ARRAY);
600  data[num - 1] = value;
601  }
602  }
603 
604 
605  inline void append(const T& v1, const T& v2) {
606  if (inArray(&v1) || inArray(&v2)) {
607  // Copy into temporaries so that the references won't break when
608  // the array resizes.
609  T t1 = v1;
610  T t2 = v2;
611  append(t1, t2);
612  } else if (num + 1 < numAllocated) {
613  // This is a simple situation; just stick it in the next free slot using
614  // the copy constructor.
615  new (data + num) T(v1);
616  new (data + num + 1) T(v2);
617  num += 2;
618  } else {
619  // Resize the array. Note that neither value is already in the array.
620  resize(num + 2, DONT_SHRINK_UNDERLYING_ARRAY);
621  data[num - 2] = v1;
622  data[num - 1] = v2;
623  }
624  }
625 
626 
627  inline void append(const T& v1, const T& v2, const T& v3) {
628  if (inArray(&v1) || inArray(&v2) || inArray(&v3)) {
629  T t1 = v1;
630  T t2 = v2;
631  T t3 = v3;
632  append(t1, t2, t3);
633  } else if (num + 2 < numAllocated) {
634  // This is a simple situation; just stick it in the next free slot using
635  // the copy constructor.
636  new (data + num) T(v1);
637  new (data + num + 1) T(v2);
638  new (data + num + 2) T(v3);
639  num += 3;
640  } else {
641  resize(num + 3, DONT_SHRINK_UNDERLYING_ARRAY);
642  data[num - 3] = v1;
643  data[num - 2] = v2;
644  data[num - 1] = v3;
645  }
646  }
647 
648 
649  inline void append(const T& v1, const T& v2, const T& v3, const T& v4) {
650  if (inArray(&v1) || inArray(&v2) || inArray(&v3) || inArray(&v4)) {
651  T t1 = v1;
652  T t2 = v2;
653  T t3 = v3;
654  T t4 = v4;
655  append(t1, t2, t3, t4);
656  } else if (num + 3 < numAllocated) {
657  // This is a simple situation; just stick it in the next free slot using
658  // the copy constructor.
659  new (data + num) T(v1);
660  new (data + num + 1) T(v2);
661  new (data + num + 2) T(v3);
662  new (data + num + 3) T(v4);
663  num += 4;
664  } else {
665  resize(num + 4, DONT_SHRINK_UNDERLYING_ARRAY);
666  data[num - 4] = v1;
667  data[num - 3] = v2;
668  data[num - 2] = v3;
669  data[num - 1] = v4;
670  }
671  }
672 
673  void append(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) {
674  if (inArray(&v1) || inArray(&v2) || inArray(&v3) || inArray(&v4) || inArray(&v5)) {
675  T t1 = v1;
676  T t2 = v2;
677  T t3 = v3;
678  T t4 = v4;
679  T t5 = v5;
680  append(t1, t2, t3, t4, t5);
681  } else if (num + 4 < numAllocated) {
682  // This is a simple situation; just stick it in the next free slot using
683  // the copy constructor.
684  new (data + num) T(v1);
685  new (data + num + 1) T(v2);
686  new (data + num + 2) T(v3);
687  new (data + num + 3) T(v4);
688  new (data + num + 4) T(v5);
689  num += 5;
690  } else {
691  resize(num + 5, DONT_SHRINK_UNDERLYING_ARRAY);
692  data[num - 5] = v1;
693  data[num - 4] = v2;
694  data[num - 3] = v3;
695  data[num - 2] = v4;
696  data[num - 1] = v5;
697  }
698  }
699 
700  void append(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6) {
701  if (inArray(&v1) || inArray(&v2) || inArray(&v3) || inArray(&v4) || inArray(&v5) || inArray(&v6)) {
702  T t1 = v1;
703  T t2 = v2;
704  T t3 = v3;
705  T t4 = v4;
706  T t5 = v5;
707  T t6 = v6;
708  append(t1, t2, t3, t4, t5, t6);
709  } else if (num + 5 < numAllocated) {
710  // This is a simple situation; just stick it in the next free slot using
711  // the copy constructor.
712  new (data + num) T(v1);
713  new (data + num + 1) T(v2);
714  new (data + num + 2) T(v3);
715  new (data + num + 3) T(v4);
716  new (data + num + 4) T(v5);
717  new (data + num + 5) T(v6);
718  num += 6;
719  } else {
720  resize(num + 6, DONT_SHRINK_UNDERLYING_ARRAY);
721  data[num - 6] = v1;
722  data[num - 5] = v2;
723  data[num - 4] = v3;
724  data[num - 3] = v4;
725  data[num - 2] = v5;
726  data[num - 1] = v6;
727  }
728  }
732  bool contains(const T& e) const {
733  for (int i = 0; i < size(); ++i) {
734  if ((*this)[i] == e) {
735  return true;
736  }
737  }
738 
739  return false;
740  }
741 
746  void append(const Array<T>& array) {
747  debugAssert(this != &array);
748  size_t oldNum = num;
749  size_t arrayLength = array.length();
750 
751  resize(num + arrayLength, false);
752 
753  for (size_t i = 0; i < arrayLength; ++i) {
754  data[oldNum + i] = array.data[i];
755  }
756  }
757 
762  inline T& next() {
763  resize(num + 1, false);
764  return last();
765  }
766 
770  inline void push(const T& value) {
771  append(value);
772  }
773 
774  inline void push(const Array<T>& array) {
775  append(array);
776  }
777 
779  inline void push_back(const T& v) {
780  push(v);
781  }
782 
785  inline void pop_back() {
786  pop();
787  }
788 
794  int capacity() const {
795  return (int)numAllocated;
796  }
797 
803  T& front() {
804  return (*this)[0];
805  }
806 
812  const T& front() const {
813  return (*this)[0];
814  }
815 
821  T& back() {
822  return (*this)[size()-1];
823  }
824 
830  const T& back() const {
831  return (*this)[size()-1];
832  }
833 
837  inline T pop(bool shrinkUnderlyingArrayIfNecessary = true) {
838  debugAssert(num > 0);
839  T temp = data[num - 1];
840  resize(num - 1, shrinkUnderlyingArrayIfNecessary);
841  return temp;
842  }
843 
846  inline void popDiscard(bool shrinkUnderlyingArrayIfNecessary = false) {
847  debugAssert(num > 0);
848  resize(num - 1, shrinkUnderlyingArrayIfNecessary);
849  }
850 
851 
858  void swap(Array<T>& str) {
859  Array<T> temp = str;
860  str = *this;
861  *this = temp;
862  }
863 
864 
868  inline T& operator[](int n) {
869  debugAssertM((n >= 0) && (n < (int)num),
870  format("Array index out of bounds. n = %d, size() = %d", (int)n, (int)num));
871  debugAssert(data!=NULL);
872  return data[n];
873  }
874 
875  inline T& operator[](uint32 n) {
876  debugAssertM(n < (uint32)num, format("Array index out of bounds. n = %d, size() = %d",
877  (int)n, (int)num));
878  return data[n];
879  }
880 
881  inline T& operator[](uint64 n) {
882  debugAssertM(n < (uint64)num, format("Array index out of bounds. n = %d, size() = %d", (int)n, (int)num));
883  return data[n];
884  }
885 
889  inline const T& operator[](int n) const {
890  debugAssert((n >= 0) && (n < (int)num));
891  debugAssert(data != NULL);
892  return data[n];
893  }
894 
895  inline const T& operator[](uint32 n) const {
896  debugAssert((n < (uint32)num));
897  debugAssert(data!=NULL);
898  return data[n];
899  }
900 
901  inline const T& operator[](uint64 n) const {
902  debugAssert((n < (uint64)num));
903  debugAssert(data!=NULL);
904  return data[n];
905  }
906 
907  inline T& randomElement() {
908  debugAssert(num > 0);
909  debugAssert(data!=NULL);
910  return data[iRandom(0, (int)num - 1)];
911  }
912 
913  inline const T& randomElement() const {
914  debugAssert(num > 0);
915  debugAssert(data!=NULL);
916  return data[iRandom(0, num - 1)];
917  }
918 
923  inline const T& last() const {
924  debugAssert(num > 0);
925  debugAssert(data!=NULL);
926  return data[num - 1];
927  }
928 
930  inline T& last() {
931  debugAssert(num > 0);
932  debugAssert(data!=NULL);
933  return data[num - 1];
934  }
935 
937  inline int lastIndex() const {
938  debugAssertM(num > 0, "Array is empty");
939  return num - 1;
940  }
941 
942  inline int firstIndex() const {
943  debugAssertM(num > 0, "Array is empty");
944  return 0;
945  }
946 
948  inline T& first() {
949  debugAssertM(num > 0, "Array is empty");
950  return data[0];
951  }
952 
953  inline const T& first() const {
954  debugAssertM(num > 0, "Array is empty");
955  return data[0];
956  }
957 
959  inline int middleIndex() const {
960  debugAssertM(num > 0, "Array is empty");
961  return num >> 1;
962  }
963 
965  inline const T& middle() const {
966  debugAssertM(num > 0, "Array is empty");
967  return data[num >> 1];
968  }
969 
971  inline T& middle() {
972  debugAssertM(num > 0, "Array is empty");
973  return data[num >> 1];
974  }
975 
981  for (size_t i = 0; i < num; ++i) {
982  delete data[i];
983  }
984  resize(0);
985  }
986 
988  void G3D_DEPRECATED deleteAll() {
990  }
991 
996  int rfindIndex(const T& value) const {
997  for (int i = num -1 ; i >= 0; --i) {
998  if (data[i] == value) {
999  return i;
1000  }
1001  }
1002  return -1;
1003  }
1004 
1009  int findIndex(const T& value) const {
1010  for (size_t i = 0; i < num; ++i) {
1011  if (data[i] == value) {
1012  return (int)i;
1013  }
1014  }
1015  return -1;
1016  }
1017 
1022  Iterator find(const T& value) {
1023  for (int i = 0; i < num; ++i) {
1024  if (data[i] == value) {
1025  return data + i;
1026  }
1027  }
1028  return end();
1029  }
1030 
1031  ConstIterator find(const T& value) const {
1032  for (int i = 0; i < num; ++i) {
1033  if (data[i] == value) {
1034  return data + i;
1035  }
1036  }
1037  return end();
1038  }
1039 
1044  void remove(Iterator element, int count = 1) {
1045  debugAssert((element >= begin()) && (element < end()));
1046  debugAssert((count > 0) && (element + count) <= end());
1047  Iterator last = end() - count;
1048 
1049  while(element < last) {
1050  element[0] = element[count];
1051  ++element;
1052  }
1053 
1054  resize(num - count);
1055  }
1056 
1057  void remove(int index, int count = 1) {
1058  debugAssert((index >= 0) && (index < (int)num));
1059  debugAssert((count > 0) && (index + count <= (int)num));
1060 
1061  remove(begin() + index, count);
1062  }
1063 
1067  void reverse() {
1068  T temp;
1069 
1070  size_t n2 = num / 2;
1071  for (size_t i = 0; i < n2; ++i) {
1072  temp = data[num - 1 - i];
1073  data[num - 1 - i] = data[i];
1074  data[i] = temp;
1075  }
1076  }
1077 
1105  // void sort(bool (__cdecl *lessThan)(const T& elem1, const T& elem2)) {
1106  // std::sort(data, data + num, lessThan);
1107  //}
1108  template<class LessThan>
1109  void sort(const LessThan& lessThan) {
1110  // Using std::sort, which according to http://www.open-std.org/JTC1/SC22/WG21/docs/D_4.cpp
1111  // was 2x faster than qsort for arrays around size 2000 on intel core2 with gcc
1112  std::sort(data, data + num, lessThan);
1113  }
1114 
1128  void sort(int direction = SORT_INCREASING) {
1129  if (direction == SORT_INCREASING) {
1130  std::sort(data, data + num);
1131  } else {
1132  std::sort(data, data + num, compareGT);
1133  }
1134  }
1135 
1139  void sortSubArray(int beginIndex, int endIndex, int direction = SORT_INCREASING) {
1140  if (direction == SORT_INCREASING) {
1141  std::sort(data + beginIndex, data + endIndex + 1);
1142  } else {
1143  std::sort(data + beginIndex, data + endIndex + 1, compareGT);
1144  }
1145  }
1146 
1147  void sortSubArray(int beginIndex, int endIndex, bool (__cdecl *lessThan)(const T& elem1, const T& elem2)) {
1148  std::sort(data + beginIndex, data + endIndex + 1, lessThan);
1149  }
1150 
1155  template<typename StrictWeakOrdering>
1156  void sortSubArray(int beginIndex, int endIndex, StrictWeakOrdering& lessThan) {
1157  std::sort(data + beginIndex, data + endIndex + 1, lessThan);
1158  }
1159 
1162  public:
1163  inline int operator()(const T& A, const T& B) const {
1164  if (A < B) {
1165  return 1;
1166  } else if (A == B) {
1167  return 0;
1168  } else {
1169  return -1;
1170  }
1171  }
1172  };
1173 
1193  template<typename Comparator>
1195  const T& partitionElement,
1196  Array<T>& ltArray,
1197  Array<T>& eqArray,
1198  Array<T>& gtArray,
1199  const Comparator& comparator) const {
1200 
1201  // Make sure all arrays are independent
1202  debugAssert(&ltArray != this);
1203  debugAssert(&eqArray != this);
1204  debugAssert(&gtArray != this);
1205  debugAssert(&ltArray != &eqArray);
1206  debugAssert(&ltArray != &gtArray);
1207  debugAssert(&eqArray != &gtArray);
1208 
1209  // Clear the arrays
1210  ltArray.fastClear();
1211  eqArray.fastClear();
1212  gtArray.fastClear();
1213 
1214  // Form a table of buckets for lt, eq, and gt
1215  Array<T>* bucket[3] = {&ltArray, &eqArray, &gtArray};
1216 
1217  for (size_t i = 0; i < num; ++i) {
1218  int c = comparator(partitionElement, data[i]);
1219  debugAssertM(c >= -1 && c <= 1, "Comparator returned an illegal value.");
1220 
1221  // Insert into the correct bucket, 0, 1, or 2
1222  bucket[c + 1]->append(data[i]);
1223  }
1224  }
1225 
1230  const T& partitionElement,
1231  Array<T>& ltArray,
1232  Array<T>& eqArray,
1233  Array<T>& gtArray) const {
1234 
1235  partition(partitionElement, ltArray, eqArray, gtArray, typename Array<T>::DefaultComparator());
1236  }
1237 
1246  template<typename Comparator>
1248  Array<T>& ltMedian,
1249  Array<T>& eqMedian,
1250  Array<T>& gtMedian,
1251  Array<T>& tempArray,
1252  const Comparator& comparator) const {
1253 
1254  ltMedian.fastClear();
1255  eqMedian.fastClear();
1256  gtMedian.fastClear();
1257 
1258  // Handle trivial cases first
1259  switch (size()) {
1260  case 0:
1261  // Array is empty; no parition is possible
1262  return;
1263 
1264  case 1:
1265  // One element
1266  eqMedian.append(first());
1267  return;
1268 
1269  case 2:
1270  {
1271  // Two element array; median is the smaller
1272  int c = comparator(first(), last());
1273 
1274  switch (c) {
1275  case -1:
1276  // first was bigger
1277  eqMedian.append(last());
1278  gtMedian.append(first());
1279  break;
1280 
1281  case 0:
1282  // Both equal to the median
1283  eqMedian.append(first(), last());
1284  break;
1285 
1286  case 1:
1287  // Last was bigger
1288  eqMedian.append(first());
1289  gtMedian.append(last());
1290  break;
1291  }
1292  }
1293  return;
1294  }
1295 
1296  // All other cases use a recursive randomized median
1297 
1298  // Number of values less than all in the current arrays
1299  int ltBoost = 0;
1300 
1301  // Number of values greater than all in the current arrays
1302  int gtBoost = 0;
1303 
1304  // For even length arrays, force the gt array to be one larger than the
1305  // lt array:
1306  // [1 2 3] size = 3, choose half = (s + 1) /2
1307  //
1308  int lowerHalfSize, upperHalfSize;
1309  if (isEven(size())) {
1310  lowerHalfSize = size() / 2;
1311  upperHalfSize = lowerHalfSize + 1;
1312  } else {
1313  lowerHalfSize = upperHalfSize = (size() + 1) / 2;
1314  }
1315  const T* xPtr = NULL;
1316 
1317  // Maintain pointers to the arrays; we'll switch these around during sorting
1318  // to avoid copies.
1319  const Array<T>* source = this;
1320  Array<T>* lt = &ltMedian;
1321  Array<T>* eq = &eqMedian;
1322  Array<T>* gt = &gtMedian;
1323  Array<T>* extra = &tempArray;
1324 
1325  while (true) {
1326  // Choose a random element -- choose the middle element; this is theoretically
1327  // suboptimal, but for loosly sorted array is actually the best strategy
1328 
1329  xPtr = &(source->middle());
1330  if (source->size() == 1) {
1331  // Done; there's only one element left
1332  break;
1333  }
1334  const T& x = *xPtr;
1335 
1336  // Note: partition (fast) clears the arrays for us
1337  source->partition(x, *lt, *eq, *gt, comparator);
1338 
1339  int L = lt->size() + ltBoost + eq->size();
1340  int U = gt->size() + gtBoost + eq->size();
1341  if ((L >= lowerHalfSize) &&
1342  (U >= upperHalfSize)) {
1343 
1344  // x must be the partition median
1345  break;
1346 
1347  } else if (L < lowerHalfSize) {
1348 
1349  // x must be smaller than the median. Recurse into the 'gt' array.
1350  ltBoost += lt->size() + eq->size();
1351 
1352  // The new gt array will be the old source array, unless
1353  // that was the this pointer (i.e., unless we are on the
1354  // first iteration)
1355  Array<T>* newGt = (source == this) ? extra : const_cast<Array<T>*>(source);
1356 
1357  // Now set up the gt array as the new source
1358  source = gt;
1359  gt = newGt;
1360 
1361  } else {
1362 
1363  // x must be bigger than the median. Recurse into the 'lt' array.
1364  gtBoost += gt->size() + eq->size();
1365 
1366  // The new lt array will be the old source array, unless
1367  // that was the this pointer (i.e., unless we are on the
1368  // first iteration)
1369  Array<T>* newLt = (source == this) ? extra : const_cast<Array<T>*>(source);
1370 
1371  // Now set up the lt array as the new source
1372  source = lt;
1373  lt = newLt;
1374  }
1375  }
1376 
1377  // Now that we know the median, make a copy of it (since we're about to destroy the array that it
1378  // points into).
1379  T median = *xPtr;
1380  xPtr = NULL;
1381 
1382  // Partition the original array (note that this fast clears for us)
1383  partition(median, ltMedian, eqMedian, gtMedian, comparator);
1384  }
1385 
1392  Array<T>& ltMedian,
1393  Array<T>& eqMedian,
1394  Array<T>& gtMedian) const {
1395 
1396  Array<T> temp;
1397  medianPartition(ltMedian, eqMedian, gtMedian, temp, DefaultComparator());
1398  }
1399 
1400 
1401 
1402 
1405  void randomize() {
1406  T temp;
1407 
1408  for (int i = size() - 1; i >= 0; --i) {
1409  int x = iRandom(0, i);
1410 
1411  temp = data[i];
1412  data[i] = data[x];
1413  data[x] = temp;
1414  }
1415  }
1416 
1417 
1419  void reserve(int n) {
1420  debugAssert(n >= size());
1421  const int oldSize = size();
1422  resize(n);
1423  resize(oldSize, false);
1424  }
1425 
1428  size_t sizeInMemory() const {
1429  return sizeof(Array<T>) + (sizeof(T) * numAllocated);
1430  }
1431 
1433  void removeNulls() {
1434  int nextNull = 0;
1435  for (int i = 0; i < size(); ++i) {
1436  if (notNull(data[i])) {
1437  if (i > nextNull) {
1438  // Move value i down to squeeze out NULLs
1439  data[nextNull] = data[i];
1440  }
1441  ++nextNull;
1442  }
1443  }
1444 
1445  resize(nextNull, false);
1446  }
1447 };
1448 
1449 
1451 template<class T> bool contains(const T* array, int len, const T& e) {
1452  for (int i = len - 1; i >= 0; --i) {
1453  if (array[i] == e) {
1454  return true;
1455  }
1456  }
1457  return false;
1458 }
1459 
1460 } // namespace
1461 
1462 #ifdef _MSC_VER
1463 # pragma warning (pop)
1464 #endif
1465 
1466 #endif
T * Iterator
Definition: Array.h:214
Iterator end()
Definition: Array.h:248
const T & randomElement() const
Definition: Array.h:913
void insert(int n, const T &value)
Definition: Array.h:456
void randomize()
Definition: Array.h:1405
void push(const T &value)
Definition: Array.h:770
T pop(bool shrinkUnderlyingArrayIfNecessary=true)
Definition: Array.h:837
int size_type
Definition: Array.h:225
bool notNull(const Pointer< T > &p)
Definition: Pointer.h:350
static MemoryManager::Ref create()
Definition: MemoryManager.cpp:35
void push_back(const T &v)
Definition: Array.h:779
void fastClear()
Definition: Array.h:419
void copyFrom(const Array< T > &other)
Definition: Array.h:341
void resize(size_t n, bool shrinkIfNecessary=true)
Definition: Array.h:490
static void memcpy(void *dst, const void *src, size_t numBytes)
Definition: System.cpp:643
T & operator[](int n)
Definition: Array.h:868
void reverse()
Definition: Array.h:1067
ConstIterator end() const
Definition: Array.h:244
T & randomElement()
Definition: Array.h:907
Array(const T &v0)
Definition: Array.h:287
T & middle()
Definition: Array.h:971
bool inArray(const T *address)
Definition: Array.h:135
void append(const T &v1, const T &v2, const T &v3, const T &v4)
Definition: Array.h:649
void push(const Array< T > &array)
Definition: Array.h:774
Definition: Array.h:1161
Array(const Array &other)
Definition: Array.h:331
ConstIterator const_iterator
Definition: Array.h:221
void sort(const LessThan &lessThan)
Definition: Array.h:1109
T value_type
Definition: Array.h:223
int capacity() const
Definition: Array.h:794
void pop_back()
Definition: Array.h:785
const T & operator[](uint32 n) const
Definition: Array.h:895
T * getCArray()
Definition: Array.h:256
Definition: AABox.h:25
Dynamic 1D array tuned for performance.
Definition: Array.h:95
const T & last() const
Definition: Array.h:923
arena_t NULL
Definition: jemalloc_internal.h:624
int length() const
Definition: Array.h:438
uint64_t uint64
Definition: g3dmath.h:170
shared_ptr< class MemoryManager > Ref
Definition: MemoryManager.h:31
void append(const T &v1, const T &v2, const T &v3)
Definition: Array.h:627
int middleIndex() const
Definition: Array.h:959
void popDiscard(bool shrinkUnderlyingArrayIfNecessary=false)
Definition: Array.h:846
#define debugAssertM(exp, message)
Definition: debugAssert.h:161
T max(const T &x, const T &y)
Definition: g3dmath.h:320
bool contains(const T *array, int len, const T &e)
Definition: Array.h:1451
void reserve(int n)
Definition: Array.h:1419
T & next()
Definition: Array.h:762
static void swap(Array< T, MIN_ELEMENTS > &a, Array< T, MIN_ELEMENTS > &b)
Definition: Array.h:265
void trimToSize()
Definition: Array.h:476
const T & operator[](uint64 n) const
Definition: Array.h:901
int comparator(const void *ke1, const void *ke2)
Definition: WatcherKqueue.cpp:28
void medianPartition(Array< T > &ltMedian, Array< T > &eqMedian, Array< T > &gtMedian, Array< T > &tempArray, const Comparator &comparator) const
Definition: Array.h:1247
const T & operator[](int n) const
Definition: Array.h:889
void append(const Array< T > &array)
Definition: Array.h:746
void sort(int direction=SORT_INCREASING)
Definition: Array.h:1128
const T * ConstIterator
Definition: Array.h:216
ConstIterator find(const T &value) const
Definition: Array.h:1031
size_t sizeInMemory() const
Definition: Array.h:1428
Iterator find(const T &value)
Definition: Array.h:1022
void append(const T &v1, const T &v2, const T &v3, const T &v4, const T &v5)
Definition: Array.h:673
T min(const T &x, const T &y)
Definition: g3dmath.h:305
void setAll(const T &value)
Definition: Array.h:467
void fastRemove(int index, bool shrinkIfNecessary=false)
Definition: Array.h:446
ConstIterator begin() const
Definition: Array.h:237
Array(const T &v0, const T &v1)
Definition: Array.h:293
const T * getCArray() const
Definition: Array.h:276
Iterator begin()
Definition: Array.h:233
const bool DONT_SHRINK_UNDERLYING_ARRAY
Definition: Array.h:43
int operator()(const T &A, const T &B) const
Definition: Array.h:1163
MemoryManager::Ref m_memoryManager
Definition: Array.h:108
T & front()
Definition: Array.h:803
#define debugAssert(exp)
Definition: debugAssert.h:160
void G3D_DEPRECATED deleteAll()
Definition: Array.h:988
Array & operator=(const std::vector< T > &other)
Definition: Array.h:199
void partition(const T &partitionElement, Array< T > &ltArray, Array< T > &eqArray, Array< T > &gtArray) const
Definition: Array.h:1229
size_t numAllocated
Definition: Array.h:106
const int SORT_DECREASING
Definition: Array.h:48
Array(const std::vector< T > &other)
Definition: Array.h:335
~Array()
Definition: Array.h:389
void copyPOD(const Array< T > &other)
Definition: Array.h:348
void init(size_t n, const MemoryManager::Ref &m)
Definition: Array.h:112
int difference_type
Definition: Array.h:227
T * data
Definition: Array.h:103
void clear(bool shrink=true)
Definition: Array.h:407
bool isEven(int num)
Definition: g3dmath.h:794
std::string __cdecl format(const char *fmt...) G3D_CHECK_PRINTF_ARGS
void clearAndSetMemoryManager(const MemoryManager::Ref &m)
Definition: Array.h:411
T & back()
Definition: Array.h:821
int size() const
Definition: Array.h:430
void medianPartition(Array< T > &ltMedian, Array< T > &eqMedian, Array< T > &gtMedian) const
Definition: Array.h:1391
int lastIndex() const
Definition: Array.h:937
const T & first() const
Definition: Array.h:953
Array(const T &v0, const T &v1, const T &v2, const T &v3, const T &v4)
Definition: Array.h:317
T & operator[](uint32 n)
Definition: Array.h:875
bool contains(const T &e) const
Definition: Array.h:732
void swap(Array< T > &str)
Definition: Array.h:858
MemoryManager::Ref memoryManager() const
Definition: Array.h:423
Array()
Definition: Array.h:281
int findIndex(const T &value) const
Definition: Array.h:1009
static const size_t MIN_BYTES
Definition: Array.h:100
void sortSubArray(int beginIndex, int endIndex, int direction=SORT_INCREASING)
Definition: Array.h:1139
size_t num
Definition: Array.h:105
const int SORT_INCREASING
Definition: Array.h:46
void append(const T &v1, const T &v2)
Definition: Array.h:605
void append(const T &v1, const T &v2, const T &v3, const T &v4, const T &v5, const T &v6)
Definition: Array.h:700
void _copy(const Array &other)
Definition: Array.h:124
const T & middle() const
Definition: Array.h:965
const T & front() const
Definition: Array.h:812
Array(const T &v0, const T &v1, const T &v2, const T &v3)
Definition: Array.h:308
int rfindIndex(const T &value) const
Definition: Array.h:996
int firstIndex() const
Definition: Array.h:942
void appendPOD(const Array< T > &other)
Definition: Array.h:366
Array & operator=(const Array &other)
Definition: Array.h:191
void partition(const T &partitionElement, Array< T > &ltArray, Array< T > &eqArray, Array< T > &gtArray, const Comparator &comparator) const
Definition: Array.h:1194
void realloc(size_t oldNum)
Definition: Array.h:151
void sortSubArray(int beginIndex, int endIndex, StrictWeakOrdering &lessThan)
Definition: Array.h:1156
const T & back() const
Definition: Array.h:830
T & first()
Definition: Array.h:948
const FieldDescriptor value
Definition: descriptor.h:1522
uint32_t uint32
Definition: g3dmath.h:168
void invokeDeleteOnAllElements()
Definition: Array.h:980
G3D::int16 x
Definition: Vector2int16.h:37
void removeNulls()
Definition: Array.h:1433
void append(const T &value)
Definition: Array.h:583
#define alwaysAssertM(exp, message)
Definition: debugAssert.h:165
int iRandom(int low, int hi)
Definition: g3dmath.cpp:110
T & last()
Definition: Array.h:930
Array(const T &v0, const T &v1, const T &v2)
Definition: Array.h:300
void sortSubArray(int beginIndex, int endIndex, bool(__cdecl *lessThan)(const T &elem1, const T &elem2))
Definition: Array.h:1147
static bool __cdecl compareGT(const T &a, const T &b)
Definition: Array.h:141
T & operator[](uint64 n)
Definition: Array.h:881
Iterator iterator
Definition: Array.h:219