csutil/array.h
Go to the documentation of this file.00001 /* 00002 Crystal Space Generic Array Template 00003 Copyright (C) 2003 by Matze Braun 00004 Copyright (C) 2003 by Jorrit Tyberghein 00005 Copyright (C) 2003,2004 by Eric Sunshine 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public 00018 License along with this library; if not, write to the Free 00019 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00020 */ 00021 #ifndef __CSUTIL_ARRAY_H__ 00022 #define __CSUTIL_ARRAY_H__ 00023 00028 #include "comparator.h" 00029 00030 // Hack: Work around problems caused by #defining 'new'. 00031 #if defined(CS_EXTENSIVE_MEMDEBUG) || defined(CS_MEMORY_TRACKER) 00032 # undef new 00033 #endif 00034 #include <new> 00035 00036 #if defined(CS_MEMORY_TRACKER) 00037 #include "csutil/memdebug.h" 00038 #include "csutil/snprintf.h" 00039 #include <typeinfo> 00040 #endif 00041 00045 // Define CSARRAY_INHIBIT_TYPED_KEYS if the compiler is too old or too buggy to 00046 // properly support templated functions within a templated class. When this is 00047 // defined, rather than using a properly typed "key" argument, search methods 00048 // fall back to dealing with opaque void* for the "key" argument. Note, 00049 // however, that this fact is completely hidden from the client; the client 00050 // simply creates csArrayCmp<> functors using correct types for the keys 00051 // regardless of whether the compiler actually supports this feature. (The 00052 // MSVC6 compiler, for example, does support templated functions within a 00053 // template class but crashes and burns horribly when a function pointer or 00054 // functor is thrown into the mix; thus this should be defined for MSVC6.) 00055 #if !defined(CSARRAY_INHIBIT_TYPED_KEYS) 00056 00066 template <class T, class K> 00067 class csArrayCmp 00068 { 00069 public: 00075 typedef int(*CF)(T const&, K const&); 00077 csArrayCmp(K const& k, CF c = DefaultCompare) : key(k), cmp(c) {} 00079 csArrayCmp(csArrayCmp const& o) : key(o.key), cmp(o.cmp) {} 00081 csArrayCmp& operator=(csArrayCmp const& o) 00082 { key = o.key; cmp = o.cmp; return *this; } 00091 int operator()(T const& r) const { return cmp(r, key); } 00093 operator CF() const { return cmp; } 00095 operator K const&() const { return key; } 00106 static int DefaultCompare(T const& r, K const& k) 00107 { return csComparator<T,K>::Compare(r,k); } 00108 private: 00109 K key; 00110 CF cmp; 00111 }; 00112 00113 #define csArrayTemplate(K) template <class K> 00114 #define csArrayCmpDecl(T1,T2) csArrayCmp<T1,T2> 00115 #define csArrayCmpInvoke(C,R) C(R) 00116 00117 #else // CSARRAY_INHIBIT_TYPED_KEYS 00118 00119 class csArrayCmpAbstract 00120 { 00121 public: 00122 typedef int(*CF)(void const*, void const*); 00123 virtual int operator()(void const*) const = 0; 00124 virtual operator CF() const = 0; 00125 }; 00126 00127 template <class T, class K> 00128 class csArrayCmp : public csArrayCmpAbstract 00129 { 00130 public: 00131 typedef int(*CFTyped)(T const&, K const&); 00132 csArrayCmp(K const& k, CFTyped c = DefaultCompare) : key(k), cmp(CF(c)) {} 00133 csArrayCmp(csArrayCmp const& o) : key(o.key), cmp(o.cmp) {} 00134 csArrayCmp& operator=(csArrayCmp const& o) 00135 { key = o.key; cmp = o.cmp; return *this; } 00136 virtual int operator()(void const* p) const { return cmp(p, &key); } 00137 virtual operator CF() const { return cmp; } 00138 operator K const&() const { return key; } 00139 static int DefaultCompare(T const& r, K const& k) 00140 { return csComparator<T,K>::Compare(r,k); } 00141 private: 00142 K key; 00143 CF cmp; 00144 }; 00145 00146 #define csArrayTemplate(K) 00147 #define csArrayCmpDecl(T1,T2) csArrayCmpAbstract const& 00148 #define csArrayCmpInvoke(C,R) C(&(R)) 00149 00150 #endif // CSARRAY_INHIBIT_TYPED_KEYS 00151 00155 template <class T> 00156 class csArrayElementHandler 00157 { 00158 public: 00159 static void Construct (T* address) 00160 { 00161 new (CS_STATIC_CAST(void*,address)) T(); 00162 } 00163 00164 static void Construct (T* address, T const& src) 00165 { 00166 new (CS_STATIC_CAST(void*,address)) T(src); 00167 } 00168 00169 static void Destroy (T* address) 00170 { 00171 address->~T(); 00172 } 00173 00174 static void InitRegion (T* address, size_t count) 00175 { 00176 for (size_t i = 0 ; i < count ; i++) 00177 Construct (address + i); 00178 } 00179 }; 00180 00184 template <class T> 00185 class csArrayMemoryAllocator 00186 { 00187 public: 00188 static T* Alloc (size_t count) 00189 { 00190 return (T*)malloc (count * sizeof(T)); 00191 } 00192 00193 static void Free (T* mem) 00194 { 00195 free (mem); 00196 } 00197 00198 // The 'relevantcount' parameter should be the number of items 00199 // in the old array that are initialized. 00200 static T* Realloc (T* mem, size_t relevantcount, size_t oldcount, 00201 size_t newcount) 00202 { 00203 (void)relevantcount; (void)oldcount; 00204 return (T*)realloc (mem, newcount * sizeof(T)); 00205 } 00206 00207 // Move memory. 00208 static void MemMove (T* mem, size_t dest, size_t src, size_t count) 00209 { 00210 memmove (mem + dest, mem + src, count * sizeof(T)); 00211 } 00212 }; 00213 00222 template <class T, class ElementHandler = csArrayElementHandler<T> > 00223 class csSafeCopyArrayMemoryAllocator 00224 { 00225 public: 00226 static T* Alloc (size_t count) 00227 { 00228 return (T*)malloc (count * sizeof(T)); 00229 } 00230 00231 static void Free (T* mem) 00232 { 00233 free (mem); 00234 } 00235 00236 static T* Realloc (T* mem, size_t relevantcount, size_t oldcount, 00237 size_t newcount) 00238 { 00239 if (newcount <= oldcount) 00240 { 00241 // Realloc is safe. 00242 T* newmem = (T*)realloc (mem, newcount * sizeof (T)); 00243 CS_ASSERT (newmem == mem); 00244 return newmem; 00245 } 00246 00247 T* newmem = Alloc (newcount); 00248 size_t i; 00249 for (i = 0 ; i < relevantcount ; i++) 00250 { 00251 ElementHandler::Construct (newmem + i, mem[i]); 00252 ElementHandler::Destroy (mem + i); 00253 } 00254 Free (mem); 00255 return newmem; 00256 } 00257 00258 static void MemMove (T* mem, size_t dest, size_t src, size_t count) 00259 { 00260 size_t i; 00261 if (dest < src) 00262 { 00263 for (i = 0 ; i < count ; i++) 00264 { 00265 ElementHandler::Construct (mem + dest + i, mem[src + i]); 00266 ElementHandler::Destroy (mem + src + i); 00267 } 00268 } 00269 else 00270 { 00271 i = count; 00272 while (i > 0) 00273 { 00274 i--; 00275 ElementHandler::Construct (mem + dest + i, mem[src + i]); 00276 ElementHandler::Destroy (mem + src + i); 00277 } 00278 } 00279 } 00280 }; 00281 00286 const size_t csArrayItemNotFound = (size_t)-1; 00287 00296 template <class T, 00297 class ElementHandler = csArrayElementHandler<T>, 00298 class MemoryAllocator = csArrayMemoryAllocator<T> > 00299 class csArray 00300 { 00301 private: 00302 size_t count; 00303 size_t capacity; 00304 size_t threshold; 00305 T* root; 00306 #ifdef CS_MEMORY_TRACKER 00307 csMemTrackerInfo* mti; 00308 void UpdateMti (int dn, int curcapacity) 00309 { 00310 if (!mti) 00311 { 00312 if (!curcapacity) return; 00313 char buf[1024]; 00314 strcpy (buf, "csArray<"); 00315 size_t l = strlen (typeid (T).name ()); 00316 if (l > 1000) l = 1000; 00317 strncat (buf, typeid (T).name (), l); 00318 strcat (buf, ">"); 00319 mti = mtiRegisterAlloc (1 * sizeof (T), buf); 00320 if (!mti) return; 00321 curcapacity--; 00322 if (curcapacity) 00323 mtiUpdateAmount (mti, curcapacity, curcapacity * sizeof (T)); 00324 return; 00325 } 00326 mtiUpdateAmount (mti, dn, dn * sizeof (T)); 00327 } 00328 #endif 00329 00330 protected: 00335 void InitRegion (size_t start, size_t count) 00336 { 00337 ElementHandler::InitRegion (root+start, count); 00338 } 00339 00340 private: 00342 void CopyFrom (const csArray& source) 00343 { 00344 if (&source != this) 00345 { 00346 DeleteAll (); 00347 threshold = source.threshold; 00348 SetSizeUnsafe (source.Length ()); 00349 for (size_t i=0 ; i<source.Length() ; i++) 00350 ElementHandler::Construct (root + i, source[i]); 00351 } 00352 } 00353 00355 void InternalSetCapacity (size_t n) 00356 { 00357 if (root == 0) 00358 { 00359 root = MemoryAllocator::Alloc (n); 00360 #ifdef CS_MEMORY_TRACKER 00361 UpdateMti (n, n); 00362 #endif 00363 } 00364 else 00365 { 00366 root = MemoryAllocator::Realloc (root, count, capacity, n); 00367 #ifdef CS_MEMORY_TRACKER 00368 UpdateMti (n-capacity, n); 00369 #endif 00370 } 00371 capacity = n; 00372 } 00373 00378 void AdjustCapacity (size_t n) 00379 { 00380 if (n > capacity || (capacity > threshold && n < capacity - threshold)) 00381 { 00382 InternalSetCapacity (((n + threshold - 1) / threshold ) * threshold); 00383 } 00384 } 00385 00392 void SetSizeUnsafe (size_t n) 00393 { 00394 if (n > capacity) 00395 AdjustCapacity (n); 00396 count = n; 00397 } 00398 00399 public: 00411 static int DefaultCompare(T const& r1, T const& r2) 00412 { 00413 return csComparator<T,T>::Compare(r1,r2); 00414 } 00415 00421 csArray (size_t in_capacity = 0, size_t in_threshold = 0) 00422 { 00423 #ifdef CS_MEMORY_TRACKER 00424 mti = 0; 00425 #endif 00426 count = 0; 00427 capacity = (in_capacity > 0 ? in_capacity : 0); 00428 threshold = (in_threshold > 0 ? in_threshold : 16); 00429 if (capacity != 0) 00430 { 00431 root = MemoryAllocator::Alloc (capacity); 00432 #ifdef CS_MEMORY_TRACKER 00433 UpdateMti (capacity, capacity); 00434 #endif 00435 } 00436 else 00437 { 00438 root = 0; 00439 } 00440 } 00441 00443 ~csArray () 00444 { 00445 DeleteAll (); 00446 } 00447 00449 csArray (const csArray& source) 00450 { 00451 #ifdef CS_MEMORY_TRACKER 00452 mti = 0; 00453 #endif 00454 root = 0; 00455 capacity = 0; 00456 count = 0; 00457 CopyFrom (source); 00458 } 00459 00461 csArray<T,ElementHandler>& operator= (const csArray& other) 00462 { 00463 CopyFrom (other); 00464 return *this; 00465 } 00466 00468 size_t GetSize () const 00469 { 00470 return count; 00471 } 00472 00477 size_t Length () const 00478 { 00479 return GetSize(); 00480 } 00481 00483 size_t Capacity () const 00484 { 00485 return capacity; 00486 } 00487 00494 void TransferTo (csArray& destination) 00495 { 00496 if (&destination != this) 00497 { 00498 destination.DeleteAll (); 00499 destination.root = root; 00500 destination.count = count; 00501 destination.capacity = capacity; 00502 destination.threshold = threshold; 00503 #ifdef CS_MEMORY_TRACKER 00504 destination.mti = mti; 00505 mti = 0; 00506 #endif 00507 root = 0; 00508 capacity = count = 0; 00509 } 00510 } 00511 00521 void SetSize (size_t n, T const& what) 00522 { 00523 if (n <= count) 00524 { 00525 Truncate (n); 00526 } 00527 else 00528 { 00529 size_t old_len = Length (); 00530 SetSizeUnsafe (n); 00531 for (size_t i = old_len ; i < n ; i++) 00532 ElementHandler::Construct (root + i, what); 00533 } 00534 } 00535 00543 void SetSize (size_t n) 00544 { 00545 if (n <= count) 00546 { 00547 Truncate (n); 00548 } 00549 else 00550 { 00551 size_t old_len = Length (); 00552 SetSizeUnsafe (n); 00553 ElementHandler::InitRegion (root + old_len, n-old_len); 00554 } 00555 } 00556 00562 void SetLength (size_t n, T const& what) { SetSize(n, what); } 00563 void SetLength (size_t n) { SetSize(n); } 00566 00567 T& Get (size_t n) 00568 { 00569 CS_ASSERT (n < count); 00570 return root[n]; 00571 } 00572 00574 T const& Get (size_t n) const 00575 { 00576 CS_ASSERT (n < count); 00577 return root[n]; 00578 } 00579 00585 T& GetExtend (size_t n) 00586 { 00587 if (n >= count) 00588 SetSize (n+1); 00589 return root[n]; 00590 } 00591 00593 T& operator [] (size_t n) 00594 { 00595 return Get(n); 00596 } 00597 00599 T const& operator [] (size_t n) const 00600 { 00601 return Get(n); 00602 } 00603 00605 void Put (size_t n, T const& what) 00606 { 00607 if (n >= count) 00608 SetSize (n+1); 00609 ElementHandler::Destroy (root + n); 00610 ElementHandler::Construct (root + n, what); 00611 } 00612 00620 csArrayTemplate(K) 00621 size_t FindKey (csArrayCmpDecl(T,K) comparekey) const 00622 { 00623 for (size_t i = 0 ; i < Length () ; i++) 00624 if (csArrayCmpInvoke(comparekey, root[i]) == 0) 00625 return i; 00626 return csArrayItemNotFound; 00627 } 00628 00633 size_t Push (T const& what) 00634 { 00635 if (((&what >= root) && (&what < root + Length())) && 00636 (capacity < count + 1)) 00637 { 00638 /* 00639 Special case: An element from this very array is pushed, and a 00640 reallocation is needed. This could cause the passed ref to the 00641 element to be pushed to be read from deleted memory. Work 00642 around this. 00643 */ 00644 size_t whatIndex = &what - root; 00645 SetSizeUnsafe (count + 1); 00646 ElementHandler::Construct (root + count - 1, root[whatIndex]); 00647 } 00648 else 00649 { 00650 SetSizeUnsafe (count + 1); 00651 ElementHandler::Construct (root + count - 1, what); 00652 } 00653 return count - 1; 00654 } 00655 00660 size_t PushSmart (T const& what) 00661 { 00662 size_t const n = Find (what); 00663 return (n == csArrayItemNotFound) ? Push (what) : n; 00664 } 00665 00667 T Pop () 00668 { 00669 CS_ASSERT (count > 0); 00670 T ret(root [count - 1]); 00671 ElementHandler::Destroy (root + count - 1); 00672 SetSizeUnsafe (count - 1); 00673 return ret; 00674 } 00675 00677 T const& Top () const 00678 { 00679 CS_ASSERT (count > 0); 00680 return root [count - 1]; 00681 } 00682 00684 T& Top () 00685 { 00686 CS_ASSERT (count > 0); 00687 return root [count - 1]; 00688 } 00689 00691 bool Insert (size_t n, T const& item) 00692 { 00693 if (n <= count) 00694 { 00695 SetSizeUnsafe (count + 1); // Increments 'count' as a side-effect. 00696 size_t const nmove = (count - n - 1); 00697 if (nmove > 0) 00698 MemoryAllocator::MemMove (root, n+1, n, nmove); 00699 ElementHandler::Construct (root + n, item); 00700 return true; 00701 } 00702 else 00703 return false; 00704 } 00705 00709 csArray<T> Section (size_t low, size_t high) const 00710 { 00711 CS_ASSERT (high < count && high >= low); 00712 csArray<T> sect (high - low + 1); 00713 for (size_t i = low; i <= high; i++) sect.Push (root[i]); 00714 return sect; 00715 } 00716 00722 csArrayTemplate(K) 00723 size_t FindSortedKey (csArrayCmpDecl(T,K) comparekey, 00724 size_t* candidate = 0) const 00725 { 00726 size_t m = 0, l = 0, r = Length (); 00727 while (l < r) 00728 { 00729 m = (l + r) / 2; 00730 int cmp = csArrayCmpInvoke(comparekey, root[m]); 00731 if (cmp == 0) 00732 { 00733 if (candidate) *candidate = csArrayItemNotFound; 00734 return m; 00735 } 00736 else if (cmp < 0) 00737 l = m + 1; 00738 else 00739 r = m; 00740 } 00741 if (candidate) *candidate = m; 00742 return csArrayItemNotFound; 00743 } 00744 00751 size_t InsertSorted (const T& item, 00752 int (*compare)(T const&, T const&) = DefaultCompare, 00753 size_t* equal_index = 0) 00754 { 00755 size_t m = 0, l = 0, r = Length (); 00756 while (l < r) 00757 { 00758 m = (l + r) / 2; 00759 int cmp = compare (root [m], item); 00760 00761 if (cmp == 0) 00762 { 00763 if (equal_index) *equal_index = m; 00764 Insert (++m, item); 00765 return m; 00766 } 00767 else if (cmp < 0) 00768 l = m + 1; 00769 else 00770 r = m; 00771 } 00772 if ((m + 1) == r) 00773 m++; 00774 if (equal_index) *equal_index = csArrayItemNotFound; 00775 Insert (m, item); 00776 return m; 00777 } 00778 00785 size_t Find (T const& which) const 00786 { 00787 for (size_t i = 0 ; i < Length () ; i++) 00788 if (root[i] == which) 00789 return i; 00790 return csArrayItemNotFound; 00791 } 00792 00794 size_t Contains(T const& which) const 00795 { return Find(which); } 00796 00803 size_t GetIndex (const T* which) const 00804 { 00805 CS_ASSERT (which >= root); 00806 CS_ASSERT (which < (root + count)); 00807 return which-root; 00808 } 00809 00813 void Sort (int (*compare)(T const&, T const&) = DefaultCompare) 00814 { 00815 qsort (root, Length(), sizeof(T), 00816 (int (*)(void const*, void const*))compare); 00817 } 00818 00822 void DeleteAll () 00823 { 00824 if (root) 00825 { 00826 size_t i; 00827 for (i = 0 ; i < count ; i++) 00828 ElementHandler::Destroy (root + i); 00829 MemoryAllocator::Free (root); 00830 # ifdef CS_MEMORY_TRACKER 00831 UpdateMti (-capacity, 0); 00832 # endif 00833 root = 0; 00834 capacity = count = 0; 00835 } 00836 } 00837 00849 void Truncate (size_t n) 00850 { 00851 CS_ASSERT(n <= count); 00852 if (n < count) 00853 { 00854 for (size_t i = n; i < count; i++) 00855 ElementHandler::Destroy (root + i); 00856 SetSizeUnsafe(n); 00857 } 00858 } 00859 00865 void Empty () 00866 { 00867 Truncate (0); 00868 } 00869 00875 bool IsEmpty() const 00876 { 00877 return GetSize() == 0; 00878 } 00879 00886 void SetCapacity (size_t n) 00887 { 00888 if (n > Length ()) 00889 InternalSetCapacity (n); 00890 } 00891 00899 void SetMinimalCapacity (size_t n) 00900 { 00901 if (n < Capacity ()) return; 00902 if (n > Length ()) 00903 InternalSetCapacity (n); 00904 } 00905 00911 void ShrinkBestFit () 00912 { 00913 if (count == 0) 00914 { 00915 DeleteAll (); 00916 } 00917 else if (count != capacity) 00918 { 00919 root = MemoryAllocator::Realloc (root, count, capacity, count); 00920 #ifdef CS_MEMORY_TRACKER 00921 UpdateMti (count-capacity, count); 00922 #endif 00923 capacity = count; 00924 } 00925 } 00926 00935 bool DeleteIndex (size_t n) 00936 { 00937 if (n < count) 00938 { 00939 size_t const ncount = count - 1; 00940 size_t const nmove = ncount - n; 00941 ElementHandler::Destroy (root + n); 00942 if (nmove > 0) 00943 MemoryAllocator::MemMove (root, n, n+1, nmove); 00944 SetSizeUnsafe (ncount); 00945 return true; 00946 } 00947 else 00948 return false; 00949 } 00950 00960 bool DeleteIndexFast (size_t n) 00961 { 00962 if (n < count) 00963 { 00964 size_t const ncount = count - 1; 00965 size_t const nmove = ncount - n; 00966 ElementHandler::Destroy (root + n); 00967 if (nmove > 0) 00968 MemoryAllocator::MemMove (root, n, ncount, 1); 00969 SetSizeUnsafe (ncount); 00970 return true; 00971 } 00972 else 00973 return false; 00974 } 00975 00980 void DeleteRange (size_t start, size_t end) 00981 { 00982 if (start >= count) return; 00983 // Treat 'csArrayItemNotFound' as invalid indices, do nothing. 00984 // @@@ Assert that? 00985 if (end == csArrayItemNotFound) return; 00986 if (start == csArrayItemNotFound) return;//start = 0; 00987 if (end >= count) end = count - 1; 00988 size_t i; 00989 for (i = start ; i <= end ; i++) 00990 ElementHandler::Destroy (root + i); 00991 00992 size_t const range_size = end - start + 1; 00993 size_t const ncount = count - range_size; 00994 size_t const nmove = count - end - 1; 00995 if (nmove > 0) 00996 MemoryAllocator::MemMove (root, start, start + range_size, nmove); 00997 SetSizeUnsafe (ncount); 00998 } 00999 01005 bool Delete (T const& item) 01006 { 01007 size_t const n = Find (item); 01008 if (n != csArrayItemNotFound) 01009 return DeleteIndex (n); 01010 return false; 01011 } 01012 01026 bool DeleteFast (T const& item) 01027 { 01028 size_t const n = Find (item); 01029 if (n != csArrayItemNotFound) 01030 return DeleteIndexFast (n); 01031 return false; 01032 } 01033 01035 class Iterator 01036 { 01037 public: 01039 Iterator(Iterator const& r) : 01040 currentelem(r.currentelem), array(r.array) {} 01041 01043 Iterator& operator=(Iterator const& r) 01044 { currentelem = r.currentelem; array = r.array; return *this; } 01045 01047 bool HasNext() 01048 { return currentelem < array.Length(); } 01049 01051 const T& Next() 01052 { return array.Get(currentelem++); } 01053 01055 void Reset() 01056 { currentelem = 0; } 01057 01058 protected: 01059 Iterator(const csArray<T, ElementHandler>& newarray) 01060 : currentelem(0), array(newarray) {} 01061 friend class csArray<T, ElementHandler>; 01062 01063 private: 01064 size_t currentelem; 01065 const csArray<T, ElementHandler>& array; 01066 }; 01067 01069 Iterator GetIterator() const 01070 { return Iterator(*this); } 01071 01073 bool operator== (const csArray& other) const 01074 { 01075 if (other.GetSize() != GetSize()) return false; 01076 for (size_t i = 0; i < GetSize(); i++) 01077 if (Get (i) != other[i]) return false; 01078 return true; 01079 } 01080 }; 01081 01087 template <class T> 01088 class csSafeCopyArray 01089 : public csArray<T, 01090 csArrayElementHandler<T>, 01091 csSafeCopyArrayMemoryAllocator<T> > 01092 { 01093 public: 01098 csSafeCopyArray (size_t limit = 0, size_t threshold = 0) 01099 : csArray<T, csArrayElementHandler<T>, 01100 csSafeCopyArrayMemoryAllocator<T> > (limit, threshold) 01101 { 01102 } 01103 }; 01104 01105 #if defined(CS_EXTENSIVE_MEMDEBUG) || defined(CS_MEMORY_TRACKER) 01106 # define new CS_EXTENSIVE_MEMDEBUG_NEW 01107 #endif 01108 01111 #endif
Generated for Crystal Space by doxygen 1.4.6