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_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