Simple Application Framework  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Saf/Collection/Array.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_ARRAY_H
00029 #define SAF_COLLECTION_ARRAY_H
00030 
00031 #include "../Mem/Alloc.h"
00032 #include "../OutOfMemoryException.h"
00033 #include "../OverflowException.h"
00034 #include "../InvalidOperationException.h"
00035 #include "../Math/Algebra/Vector.h"
00036 #include "../Type/Limits.h"
00037 #include "../Algo/Swap.h"
00038 #include "../Algo/Range.h"
00039 
00040 namespace Saf
00041 {
00042     namespace Collection
00043     {
00063         template <Size N, class T>
00064         class Array
00065         {
00066         protected:
00067             typedef Array<N,T> MyType;
00068 
00069         public:
00071             typedef T* Iterator;
00073             typedef const T* ConstIterator;
00074 
00075         private:
00077             Math::Algebra::Vector<N,Size> m_dim;
00079             T *m_data;
00080 
00082             Math::Algebra::Vector<N,Size> m_stride;
00084             Size m_elems;
00085 
00086         public:
00088             Array()
00089                 : m_dim(0), m_data(nullptr), m_stride(0), m_elems(0)
00090             {}
00091 
00099             explicit Array(const Math::Algebra::Vector<N,Size> &dim)
00100                 : m_dim(0), m_data(nullptr), m_stride(0), m_elems(0)
00101             {
00102                 Resize(dim);
00103             }
00104 
00112             Array(const Math::Algebra::Vector<N,Size> &dim, const T& val)
00113                 : m_dim(0), m_data(nullptr), m_stride(0), m_elems(0)
00114             {
00115                 Resize(dim, val);
00116             }
00117 
00125             explicit Array(Size sz)
00126                 : m_dim(0), m_data(nullptr), m_stride(0), m_elems(0)
00127             {
00128                 Resize(sz);
00129             }
00130 
00138             Array(Size sz, const T& val)
00139                 : m_dim(0), m_data(nullptr), m_stride(0), m_elems(0)
00140             {
00141                 Resize(sz, val);
00142             }
00143 
00145             Array(const MyType& v)
00146                 : m_dim(0), m_data(nullptr), m_stride(0), m_elems(0)
00147             {
00148                 *this = v;
00149             }
00150 
00152             ~Array()
00153             {
00154                 Free();
00155             }
00156 
00158             MyType& Free()
00159             {
00160                 if (m_elems > 0)
00161                 {
00162                     Mem::Delete(m_data, m_elems);
00163                     m_dim.Fill(0);
00164                     m_stride.Fill(0);
00165                     m_elems = 0;
00166                 }
00167                     
00168                 return *this;
00169             }
00170 
00172             MyType& operator=(const MyType& a)
00173             {
00174                 if (this != &a)
00175                 {                        
00176                     if (!a.IsEmpty())
00177                     {
00178                         // Resize and copy
00179                         Resize(a.Dimensions());
00180                         Algo::Range::Copy(Begin(), End(), a.Begin());
00181                     }
00182                     else
00183                     {
00184                         Free();
00185                     }
00186                 }
00187 
00188                 return *this;
00189             }
00190 
00196             MyType& Swap(MyType& a)
00197             {
00198                 if (this != &a)
00199                 {
00200                     Algo::Swap(m_dim, a.m_dim);
00201                     Algo::Swap(m_data, a.m_data);
00202                     Algo::Swap(m_stride, a.m_stride);
00203                     Algo::Swap(m_elems, a.m_elems);
00204                 }
00205 
00206                 return *this;
00207             }
00208 
00214             Size Elements() const
00215             {
00216                 return m_elems;
00217             }
00218 
00220             const Math::Algebra::Vector<N,Size>& Dimensions() const
00221             {
00222                 return m_dim;
00223             }
00224 
00226             const Math::Algebra::Vector<N,Size>& Stride() const
00227             {
00228                 return m_stride;
00229             }
00230 
00232             bool IsEmpty() const
00233             {
00234                 return (m_elems == 0);
00235             }
00236 
00245             MyType& Resize(const Math::Algebra::Vector<N,Size> &dim)
00246             {
00247                 if (!Algo::Range::AnyEqualTo(dim.Begin(), dim.End(), Size(0)))
00248                 {
00249                     CheckOverflow(dim);
00250 
00251                     if (dim.Product() != m_elems)
00252                     {                            
00253                         Free();
00254                         m_data = SAF_NEW T[dim.Product()];
00255                     }
00256 
00257                     m_dim = dim;
00258                     UpdateCache();
00259                 }
00260                 else
00261                 {
00262                     throw ArgumentException(SAF_SOURCE_LOCATION, "The size of the array must "
00263                         "be non-zero in all dimensions.");
00264                 }
00265 
00266                 return *this;
00267             }
00268 
00277             MyType& Resize(const Math::Algebra::Vector<N,Size> &dim, const T& val)
00278             {
00279                 Resize(dim);
00280                 Algo::Range::Fill(Begin(), End(), val);
00281                 return *this;
00282             }
00283 
00285             MyType& Resize(Size sz, const T& val)
00286             {
00287                 if (N == 1)
00288                 {
00289                     Resize(Math::Algebra::Vector<N,Size>(sz), val);
00290                 }
00291                 else
00292                 {
00293                     throw InvalidOperationException(SAF_SOURCE_LOCATION, "Method applicable"
00294                         " to one dimensional arrays only.");
00295                 }
00296 
00297                 return *this;
00298             }
00299 
00301             MyType& Resize(Size sz)
00302             {
00303                 if (N == 1)
00304                 {
00305                     Resize(Math::Algebra::Vector<N,Size>(sz));
00306                 }
00307                 else
00308                 {
00309                     throw InvalidOperationException(SAF_SOURCE_LOCATION, "Method applicable"
00310                         " to one dimensional arrays only.");
00311                 }
00312 
00313                 return *this;
00314             }
00315 
00317             T& operator[](Size i)
00318             {
00319                 return m_data[i];
00320             }
00321 
00323             const T& operator[](Size i) const
00324             {
00325                 return m_data[i];
00326             }
00327 
00329             Iterator Begin()
00330             {
00331                 return m_data;
00332             }
00333 
00335             ConstIterator Begin() const
00336             {
00337                 return m_data;
00338             }
00339 
00341             Iterator End()
00342             {
00343                 return m_data + m_elems;
00344             }
00345 
00347             ConstIterator End() const
00348             {
00349                 return m_data + m_elems;
00350             }
00351 
00353             Iterator Front()
00354             {
00355                 return m_data;
00356             }
00357 
00359             ConstIterator Front() const
00360             {
00361                 return m_data;
00362             }
00363 
00365             Iterator Back()
00366             {
00367                 return m_data + (m_elems - 1);
00368             }
00369 
00371             ConstIterator Back() const
00372             {
00373                 return m_data + (m_elems - 1);
00374             }
00375 
00377             bool operator==(const MyType& a) const
00378             {
00379                 if (m_dim != a.m_dim)
00380                 {
00381                     return false;
00382                 }
00383 
00384                 return Algo::Range::Equal(Begin(), End(), a.Begin());
00385             }
00386 
00388             bool operator!=(const MyType& a) const
00389             {
00390                 return !(*this == a);
00391             }
00392 
00397             template <class U>
00398             U Index(const Math::Algebra::Vector<N,U> &ofs) const
00399             {
00400                 Math::Algebra::Vector<N,U> coef = m_stride.template Convert<N,U>(0);
00401                 return (ofs * coef).Sum();
00402             }
00403 
00411             template <class U>
00412             static U Index(const Math::Algebra::Vector<N,Size> &dim, 
00413                 const Math::Algebra::Vector<N,U> &ofs)
00414             {
00415                 Size stride = 1;
00416                 U idx = 0;
00417 
00418                 for (Size i = 0; i < N; i++)
00419                 {
00420                     idx += ofs[i] * U(stride);
00421                     stride *= dim[i];
00422                 }
00423                     
00424                 return idx;
00425             }
00426 
00434             template <class U>
00435             void Indexes(const Collection::Array<1,Math::Algebra::Vector<N,U> > &ofs,
00436                 Collection::Array<1,U> &idx) const
00437             {
00438                 // Calculate offsets
00439                 idx.Resize(ofs.Elements());
00440                 Math::Algebra::Vector<N,U> coef = m_stride.template Convert<N,U>(0);
00441                 for (Size i = 0; i < ofs.Elements(); i++)
00442                 {
00443                     idx[i] = (ofs[i] * coef).Sum();
00444                 }
00445             }
00446 
00457             template <class U>
00458             static void Indexes(const Math::Algebra::Vector<N,Size> &dim, 
00459                 const Collection::Array<1,Math::Algebra::Vector<N,U> > &ofs,
00460                 Collection::Array<1,U> &idx)
00461             {
00462                 Math::Algebra::Vector<N,U> stride;
00463                 stride[0] = 1;
00464                 for (Size i = 1; i < N; i++)
00465                 {
00466                     stride[i] = stride[i-1] * U(dim[i-1]);
00467                 }
00468 
00469                 // Calculate offsets
00470                 idx.Resize(ofs.Elements());
00471                 for (Size i = 0; i < ofs.Elements(); i++)
00472                 {
00473                     idx[i] = (ofs[i] * stride).Sum();
00474                 }
00475             }
00476 
00481             void Coord(Size idx, Math::Algebra::Vector<N,Size> &coord) const
00482             {
00483                 for (Size i = N; i-- > 0; )
00484                 {
00485                     coord[i] = idx / m_stride[i];
00486                     idx = idx % m_stride[i];
00487                 }
00488             }
00489 
00497             void Coords(const Collection::Array<1,Size> &iv,
00498                 Collection::Array<1,Math::Algebra::Vector<N,Size> > &cv) const
00499             {
00500                 cv.Resize(iv.Elements());
00501                 for (Size i = 0; i < cv.Elements(); i++)
00502                 {
00503                     Size idx = iv[i];
00504 
00505                     for (Size j = N; j-- > 0; )
00506                     {
00507                         cv[i][j] = idx / m_stride[j];
00508                         idx -= idx % m_stride[j];
00509                     }
00510                 }
00511             }
00512 
00513         protected:
00515             void CheckOverflow(const Math::Algebra::Vector<N,Size> &dim)
00516             {
00517                 Size max_elems = (Type::Limits<Size>::Max() / sizeof(T)) - 1;
00518 
00519                 for (Size i = 0; i < N; i++)
00520                 {
00521                     max_elems /= dim[i];
00522                 }
00523 
00524                 if (!max_elems)
00525                 {
00526                     throw OverflowException(SAF_SOURCE_LOCATION, "The number of elements is too large "
00527                         "to be stored in the memory.");
00528                 }
00529             }
00530 
00532             void UpdateCache()
00533             {
00534                 // Update number of elements
00535                 m_elems = m_dim.Product();
00536 
00537                 // Compute stride
00538                 m_stride[0] = 1;
00539                 for (Size i = 1; i < N; i++)
00540                 {
00541                     m_stride[i] = m_stride[i-1] * m_dim[i-1];
00542                 }
00543             }
00544         };
00545     }
00546 
00548     namespace Algo
00549     {
00550         // Swap specialization for arrays.
00551         template <Size N, class T>
00552         struct SwapFunc< Collection::Array<N,T> >
00553         {
00554             void operator()(Collection::Array<N,T>& x, Collection::Array<N,T>& y)
00555             {
00556                 x.Swap(y);
00557             }
00558         };
00559     }
00561 }
00562 
00563 #endif