Simple Application Framework
1
|
00001 /* 00002 This file is part of Simple Application Framework (Saf) library. 00003 Copyright (C) 2010 - 2012 Ondrej Danek <ondrej.danek@gmail.com> 00004 00005 This library is free software: you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published 00007 by the Free Software Foundation, either version 3 of the License, or 00008 (at your option) any later version. 00009 00010 Saf is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with Simple Application Framework library. If not, 00017 see <http://www.gnu.org/licenses/>. 00018 */ 00019 00028 #ifndef SAF_COLLECTION_DYNARRAY_H 00029 #define SAF_COLLECTION_DYNARRAY_H 00030 00031 #include "../Type.h" 00032 #include "../Mem/Alloc.h" 00033 #include "../IndexOutOfRangeException.h" 00034 #include "../OverflowException.h" 00035 #include "../ArgumentException.h" 00036 #include "../Algo/Swap.h" 00037 #include "../Algo/Selection/MinMax.h" 00038 #include "../Type/Limits.h" 00039 00040 namespace Saf 00041 { 00042 namespace Collection 00043 { 00065 template <class T> 00066 class DynArray 00067 { 00068 protected: 00069 typedef DynArray<T> MyType; 00070 00071 public: 00073 typedef T* Iterator; 00075 typedef const T* ConstIterator; 00076 00077 protected: 00081 static Size MinCapacity() 00082 { 00083 return 16; 00084 } 00085 00086 private: 00088 Size m_elems; 00090 Size m_cap; 00092 T *m_data; 00093 00094 public: 00096 DynArray() 00097 : m_elems(0), m_cap(0), m_data(nullptr) 00098 {} 00099 00105 explicit DynArray(Size initSize, const T& initVal = T()) 00106 : m_elems(0), m_cap(0), m_data(nullptr) 00107 { 00108 Resize(initSize, initVal); 00109 } 00110 00112 DynArray(const MyType& a) 00113 : m_elems(0), m_cap(0), m_data(nullptr) 00114 { 00115 *this = a; 00116 } 00117 00119 MyType& operator=(const MyType& a) 00120 { 00121 if (&a != this) 00122 { 00123 Resize(a.Elements()); 00124 Algo::Range::Copy(a.Begin(), a.End(), Begin()); 00125 } 00126 00127 return *this; 00128 } 00129 00131 ~DynArray() 00132 { 00133 Free(); 00134 } 00135 00141 MyType& Free() 00142 { 00143 if (m_cap > 0) 00144 { 00145 while (m_elems > 0) 00146 { 00147 m_data[--m_elems].~T(); 00148 } 00149 00150 Mem::OperatorDelete(m_data, m_cap); 00151 m_cap = 0; 00152 } 00153 00154 return *this; 00155 } 00156 00162 MyType& Swap(MyType& da) 00163 { 00164 if (this != &da) 00165 { 00166 Algo::Swap(m_elems, da.m_elems); 00167 Algo::Swap(m_cap, da.m_cap); 00168 Algo::Swap(m_data, da.m_data); 00169 } 00170 00171 return *this; 00172 } 00173 00179 Size Elements() const 00180 { 00181 return m_elems; 00182 } 00183 00185 Size Capacity() const 00186 { 00187 return m_cap; 00188 } 00189 00195 bool IsEmpty() const 00196 { 00197 return m_elems == 0; 00198 } 00199 00201 T& operator[](Size i) 00202 { 00203 return m_data[i]; 00204 } 00205 00207 const T& operator[](Size i) const 00208 { 00209 return m_data[i]; 00210 } 00211 00219 MyType& PushBack(const T& val) 00220 { 00221 Resize(m_elems + 1, val); 00222 return *this; 00223 } 00224 00234 MyType& PushFront(const T& val) 00235 { 00236 Resize(m_elems + 1); 00237 00238 // @todo Is this safe? 00239 for (Size i = m_elems - 1; i > 0; --i) 00240 { 00241 m_data[i] = m_data[i - 1]; 00242 } 00243 00244 m_data[0] = val; 00245 00246 return *this; 00247 } 00248 00256 MyType& PopBack() 00257 { 00258 if (m_elems > 0) 00259 { 00260 --m_elems; 00261 m_data[m_elems].~T(); 00262 } 00263 00264 return *this; 00265 } 00266 00276 MyType& PopFront() 00277 { 00278 if (m_elems > 0) 00279 { 00280 Erase(Begin()); 00281 } 00282 00283 return *this; 00284 } 00285 00301 Iterator Erase(Iterator it) 00302 { 00303 return Erase(it, it + 1); 00304 } 00305 00323 Iterator Erase(Iterator itBegin, Iterator itEnd) 00324 { 00325 if (itBegin > itEnd) 00326 { 00327 throw ArgumentException(SAF_SOURCE_LOCATION, "Invalid range specification."); 00328 } 00329 00330 if (itBegin < Begin() || itEnd > End()) 00331 { 00332 throw IndexOutOfRangeException(SAF_SOURCE_LOCATION); 00333 } 00334 00335 // Number of removed elements 00336 Size num = itEnd - itBegin; 00337 00338 if (num) 00339 { 00340 // @todo Is this safe? 00341 if (itEnd < End()) 00342 { 00343 Algo::Range::Copy(itEnd, End(), itBegin); 00344 } 00345 00346 while (num-- > 0) 00347 { 00348 End()->~T(); 00349 --m_elems; 00350 } 00351 } 00352 00353 return itBegin; 00354 } 00355 00376 MyType& Resize(Size newSize, const T& initVal = T()) 00377 { 00378 if (newSize > m_cap) 00379 { 00380 Grow(OptimalCapacityIncrease(newSize)); 00381 } 00382 00383 if (newSize > m_elems) 00384 { 00385 // Add elements 00386 while (m_elems < newSize) 00387 { 00388 new (&m_data[m_elems]) T(initVal); 00389 m_elems++; 00390 } 00391 } 00392 else if (newSize < m_elems) 00393 { 00394 // Remove elements 00395 while (m_elems > newSize) 00396 { 00397 m_data[--m_elems].~T(); 00398 } 00399 } 00400 00401 return *this; 00402 } 00403 00415 MyType& Reserve(Size cap) 00416 { 00417 if (cap > m_cap) 00418 { 00419 Grow(cap); 00420 } 00421 00422 return *this; 00423 } 00424 00431 MyType& Shrink() 00432 { 00433 if (!m_elems) 00434 { 00435 Free(); 00436 } 00437 else if (m_elems != m_cap) 00438 { 00439 Grow(Algo::Selection::Max(MinCapacity(), m_elems)); 00440 } 00441 } 00442 00444 Iterator Begin() 00445 { 00446 return m_data; 00447 } 00448 00450 ConstIterator Begin() const 00451 { 00452 return m_data; 00453 } 00454 00456 Iterator End() 00457 { 00458 return m_data + m_elems; 00459 } 00460 00462 ConstIterator End() const 00463 { 00464 return m_data + m_elems; 00465 } 00466 00468 Iterator Front() 00469 { 00470 return m_data; 00471 } 00472 00474 ConstIterator Front() const 00475 { 00476 return m_data; 00477 } 00478 00480 Iterator Back() 00481 { 00482 return m_data + (m_elems - 1); 00483 } 00484 00486 ConstIterator Back() const 00487 { 00488 return m_data + (m_elems - 1); 00489 } 00490 00491 protected: 00497 void Grow(Size cap) 00498 { 00499 if (!cap) 00500 { 00501 throw ArgumentException(SAF_SOURCE_LOCATION, "Capacity must be nonzero."); 00502 } 00503 00504 if (cap < m_elems) 00505 { 00506 throw ArgumentException(SAF_SOURCE_LOCATION, "Capacity must be at least equal to the number of elements."); 00507 } 00508 00509 // Alloc new array 00510 T *newData; 00511 Mem::OperatorNew(newData, cap, SAF_SOURCE_LOCATION); 00512 00513 // Copy data 00514 Size newSize = 0; 00515 00516 try 00517 { 00518 while (newSize < m_elems) 00519 { 00520 new (&newData[newSize]) T(m_data[newSize]); 00521 ++newSize; 00522 } 00523 } 00524 catch (...) 00525 { 00526 // Exception, deallocate temporary array 00527 while (newSize > 0) 00528 { 00529 newData[newSize].~T(); 00530 --newSize; 00531 } 00532 00533 Mem::OperatorDelete(newData, cap); 00534 throw; // Re-throw 00535 } 00536 00537 // Deallocate old and swap pointers 00538 Free(); 00539 00540 m_data = newData; 00541 m_cap = cap; 00542 m_elems = newSize; 00543 } 00544 00550 Size OptimalCapacityIncrease(Size reqSize) 00551 { 00552 Size maxElems = (Type::Limits<Size>::Max() / sizeof(T)) - 1; 00553 00554 if (reqSize > maxElems) 00555 { 00556 throw OverflowException(SAF_SOURCE_LOCATION, "Requested number of elements " 00557 "exceeds the maximum possible."); 00558 } 00559 00560 // Ideally grow by half of the old capacity 00561 Size newCap = (maxElems - m_cap < m_cap / 2) ? maxElems : (m_cap + m_cap / 2); 00562 00563 return Algo::Selection::Max(MinCapacity(), reqSize, newCap); 00564 } 00565 }; 00566 } 00567 00569 namespace Algo 00570 { 00571 // Swap specialization for dynamic arrays. 00572 template <class T> 00573 struct SwapFunc< Collection::DynArray<T> > 00574 { 00575 void operator()(Collection::DynArray<T>& x, Collection::DynArray<T>& y) 00576 { 00577 x.Swap(y); 00578 } 00579 }; 00580 } 00582 } 00583 00584 #endif