Simple Application Framework  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Saf/Collection/DynArray.h
Go to the documentation of this file.
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