1 /* -*- c++ -*- */ 2 #ifndef ARRAY_NOPARTIALSPECIALIZATION_H 3 #define ARRAY_NOPARTIALSPECIALIZATION_H 4 5 #include <algorithm> 6 #include <vector> 7 #include <assert.h> 8 #include <cstddef> // for std::ptrdiff_t 9 10 namespace ProtoMol { 11 12 //***************************************************************************** 13 // Class Template for a Generic Resizable N Dimensional Array (for N>=2) 14 // By Giovanni Bavestrelli Copyright 1999 Giovanni Bavestrelli 15 // Any feedback is welcome, you can contact me at gbavestrelli@yahoo.com 16 // 17 // This is the version for Microsoft Visual C++ 6.0, and perhaps for other 18 // compilers which do not support partial specialization. 19 // To make my classes work, I had to use a trick. I moved the RefArray classes 20 // as nested classes withing class Array, removing template parameter T from 21 // them, allowing me to use full specialization for class RefArray. 22 // I don't think this is up to standard C++. If your compiler supports partial 23 // specialization, be sure to use the other version of these classes. 24 // Thanks to Andrei Alexandrescu for suggesting this trick, which makes my 25 // classes work well with Visual C++, although the solution is not standard. 26 //***************************************************************************** 27 28 29 //============================================================================= 30 // Classes for passing a typesafe vector of dimensions to the Array constructor 31 //============================================================================= 32 33 template <unsigned int N> 34 class ArraySize 35 { 36 std::vector<unsigned int> & Vector; 37 38 ArraySize<N>(std::vector<unsigned int> & v) Vector(v)39 :Vector(v) 40 {} 41 42 public: 43 operator()44 ArraySize<N+1> operator () (unsigned int dim) 45 { 46 if (Vector.size()>N) Vector.resize(N); 47 Vector.push_back(dim); 48 return ArraySize<N+1>(Vector); 49 } 50 Vect()51 const std::vector<unsigned int> & Vect() const 52 { 53 assert(Vector.size()==N); 54 return Vector; 55 } 56 57 friend class ArraySizes; 58 friend class ArraySize<N-1>; 59 }; 60 61 class ArraySizes 62 { 63 std::vector<unsigned int> Vector; 64 65 public: 66 ArraySizes(unsigned int dim)67 explicit ArraySizes(unsigned int dim) 68 { 69 Vector.push_back(dim); 70 } 71 operator()72 ArraySize<2> operator () (unsigned int dim) 73 { 74 if (Vector.size()>1) Vector.resize(1); 75 Vector.push_back(dim); 76 return ArraySize<2>(Vector); 77 } 78 }; 79 80 //============================================================================= 81 // Class Template for a Generic Resizable N Dimensional Array 82 //============================================================================= 83 84 template <typename T, unsigned int N> 85 class Array 86 { 87 public: 88 89 //----------------------------------------------------------------------------- 90 // Class Template for N Dimensional SubArrays within an Array 91 //----------------------------------------------------------------------------- 92 93 template <unsigned int N> 94 class RefArray 95 { 96 public: 97 98 // STL-like types 99 typedef T value_type; 100 typedef T & reference; 101 typedef const T & const_reference; 102 typedef T * pointer; 103 typedef const T * const_pointer; 104 typedef T * iterator; 105 typedef const T * const_iterator; 106 typedef size_t size_type; 107 typedef ptrdiff_t difference_type; 108 109 // Give access to number of dimensions 110 enum { array_dims = N }; 111 112 private: 113 114 const size_type * const m_pNDimensions; // Array dimensions 115 const size_type * const m_pSubArrayLen; // SubArray dimensions 116 117 T * const m_pElements; // Point to SubArray with elements within Array 118 119 RefArray<N>(T * pElements, const size_type * pNDimensions, 120 const size_type * pSubArrayLen) m_pElements(pElements)121 :m_pElements(pElements),m_pNDimensions(pNDimensions), 122 m_pSubArrayLen(pSubArrayLen) 123 { 124 assert(m_pElements && m_pNDimensions && m_pSubArrayLen); 125 assert(m_pNDimensions[0]>0 && m_pSubArrayLen[0]>0); 126 } 127 128 public: 129 130 RefArray<N-1> operator [](size_type Index) 131 { 132 assert(m_pElements); 133 assert(Index<m_pNDimensions[0]); 134 return RefArray<N-1>(&m_pElements[Index*m_pSubArrayLen[0]], 135 m_pNDimensions+1,m_pSubArrayLen+1); 136 } 137 138 const RefArray<N-1> operator [](size_type Index) const 139 { 140 assert(m_pElements); 141 assert(Index<m_pNDimensions[0]); 142 return RefArray<N-1>(&m_pElements[Index*m_pSubArrayLen[0]], 143 m_pNDimensions+1,m_pSubArrayLen+1); 144 } 145 146 // Return STL-like iterators begin()147 iterator begin() { return m_pElements; } begin()148 const_iterator begin() const { return m_pElements; } end()149 iterator end() { return m_pElements+size(); } end()150 const_iterator end() const { return m_pElements+size(); } 151 152 // Return size of array size()153 size_type size() const { return m_pNDimensions[0]*m_pSubArrayLen[0]; } 154 155 // Return size of subdimensions size(unsigned int Dim)156 size_type size(unsigned int Dim) const 157 { 158 assert(Dim>=1 && Dim<=N); 159 return m_pNDimensions[Dim-1]; 160 } 161 162 // Return number of dimensions dimensions()163 unsigned int dimensions() const { return N; } 164 165 protected: 166 167 // The following are protected mainly because they are not exception-safe 168 // but the way they are used in the rest of the class is exception-safe 169 170 // Copy the elements of another subarray on this one where possible 171 // Where not possible, initialize them to a specified value Init 172 void copy(const RefArray<N> & SA, const T & Init=T()) 173 { 174 size_type below=std::min(size(1),SA.size(1)); 175 size_type above=size(1); 176 177 // Copy the elements we can copy 178 for (size_type i=0;i<below;++i) 179 (*this)[i].copy(SA[i],Init); 180 181 // Reset the elements we can't copy 182 for (size_type j=below;j<above;++j) 183 (*this)[j].initialize(Init); 184 } 185 186 // Reset all the elements 187 void initialize(const T & Init=T()) 188 { 189 std::fill(begin(),end(),Init); 190 } 191 192 friend class Array<T,N>; 193 friend class Array<T,N+1>; 194 friend class RefArray<N+1>; 195 }; 196 197 198 //----------------------------------------------------------------------------- 199 // Partial Specialization for Monodimensional SubArray within an Array 200 //----------------------------------------------------------------------------- 201 202 template <> 203 class RefArray<1> 204 { 205 public: 206 207 // STL-like types 208 typedef T value_type; 209 typedef T & reference; 210 typedef const T & const_reference; 211 typedef T * pointer; 212 typedef const T * const_pointer; 213 typedef T * iterator; 214 typedef const T * const_iterator; 215 typedef size_t size_type; 216 typedef ptrdiff_t difference_type; 217 218 // Give access to number of dimensions 219 enum { array_dims = 1 }; 220 221 private: 222 223 const size_type * const m_pNDimensions; // Array dimension 224 225 T * const m_pElements; // Point to elements within Array 226 227 RefArray<1>(T * pElements, const size_type * pNDimensions, 228 const size_type * pSubArrayLen) m_pElements(pElements)229 :m_pElements(pElements),m_pNDimensions(pNDimensions) 230 { 231 assert(m_pElements && m_pNDimensions && pSubArrayLen); 232 assert(m_pNDimensions[0]>0 && pSubArrayLen[0]==1); // We found the elements 233 } 234 235 public: 236 237 reference operator [](size_type Index) 238 { 239 assert(m_pElements); 240 assert(Index<m_pNDimensions[0]); 241 return m_pElements[Index]; 242 } 243 244 const_reference operator [](size_type Index) const 245 { 246 assert(m_pElements); 247 assert(Index<m_pNDimensions[0]); 248 return m_pElements[Index]; 249 } 250 251 // Return STL-like iterators begin()252 iterator begin() { return m_pElements; } begin()253 const_iterator begin() const { return m_pElements; } end()254 iterator end() { return m_pElements+size(); } end()255 const_iterator end() const { return m_pElements+size(); } 256 257 // Return size of array size()258 size_type size() const { return m_pNDimensions[0]; } 259 260 // Return size of subdimensions size(unsigned int Dim)261 size_type size(unsigned int Dim) const 262 { 263 assert(Dim==1); 264 return m_pNDimensions[0]; 265 } 266 267 // Return number of dimensions dimensions()268 unsigned int dimensions() const { return 1; } 269 270 protected: 271 272 // The following are protected mainly because they are not exception-safe 273 // but the way they are used in the rest of the class is exception-safe 274 275 // Copy the elements of another subarray on this one where possible 276 // Where not possible, initialize them to a specified value Init 277 void copy(const RefArray<1> & SA, const T & Init=T()) 278 { 279 size_type below=std::min(size(1),SA.size(1)); 280 size_type above=size(1); 281 282 // Copy the elements we can copy 283 for (size_type i=0;i<below;++i) 284 m_pElements[i]=SA.m_pElements[i]; 285 286 // Reset the elements we can't copy 287 for (size_type j=below;j<above;++j) 288 m_pElements[j]=Init; 289 } 290 291 // Reset all the elements 292 void initialize(const T & Init=T()) 293 { 294 std::fill(begin(),end(),Init); 295 } 296 297 friend class Array<T,1>; 298 friend class Array<T,2>; 299 friend class RefArray<2>; 300 }; 301 302 303 //----------------------------------------------------------------------------- 304 // Class Template for a Generic Resizable N Dimensional Array 305 //----------------------------------------------------------------------------- 306 307 public: 308 309 // STL-like types 310 typedef T value_type; 311 typedef T & reference; 312 typedef const T & const_reference; 313 typedef T * pointer; 314 typedef const T * const_pointer; 315 typedef T * iterator; 316 typedef const T * const_iterator; 317 typedef size_t size_type; 318 typedef ptrdiff_t difference_type; 319 320 // Give access to number of dimensions 321 enum { array_dims = N }; 322 323 private: 324 325 T * m_pArrayElements; // Pointer to actual array elements 326 size_type m_nArrayElements; // Total number of array elements 327 328 size_type m_NDimensions[N]; // Size of the N array dimensions 329 size_type m_SubArrayLen[N]; // Size of each subarray 330 331 public: 332 333 // Default constructor 334 Array<T,N>() m_pArrayElements(NULL)335 :m_pArrayElements(NULL),m_nArrayElements(0) 336 { 337 std::fill(m_NDimensions,m_NDimensions+N,0); 338 std::fill(m_SubArrayLen,m_SubArrayLen+N,0); 339 } 340 341 // This takes an array of N values representing the size of the N dimensions 342 explicit Array<T,N>(const unsigned int * Dimensions, const T & Init=T()) m_pArrayElements(NULL)343 :m_pArrayElements(NULL),m_nArrayElements(0) 344 { 345 std::fill(m_NDimensions,m_NDimensions+N,0); 346 std::fill(m_SubArrayLen,m_SubArrayLen+N,0); 347 348 resize(Dimensions,Init); 349 } 350 351 // This takes an ArraySize object with the N dimensions 352 explicit Array<T,N>(const ArraySize<N> & Dimensions, const T & Init=T()) m_pArrayElements(NULL)353 :m_pArrayElements(NULL),m_nArrayElements(0) 354 { 355 std::fill(m_NDimensions,m_NDimensions+N,0); 356 std::fill(m_SubArrayLen,m_SubArrayLen+N,0); 357 358 resize(Dimensions,Init); 359 } 360 361 // Copy constructor 362 Array<T,N>(const Array<T,N> & A) m_pArrayElements(NULL)363 :m_pArrayElements(NULL),m_nArrayElements(0) 364 { 365 std::fill(m_NDimensions,m_NDimensions+N,0); 366 std::fill(m_SubArrayLen,m_SubArrayLen+N,0); 367 368 Array<T,N> Temp; 369 if (!A.empty() && Temp.resize(A.m_NDimensions)) 370 std::copy(A.begin(),A.end(),Temp.begin()); 371 swap(Temp); 372 } 373 374 // Destructor 375 ~Array<T,N>() 376 { 377 delete [] m_pArrayElements; 378 } 379 380 // Indexing Array 381 RefArray<N-1> operator [](size_type Index) 382 { 383 assert(m_pArrayElements); 384 assert(Index<m_NDimensions[0]); 385 return RefArray<N-1>(&m_pArrayElements[Index*m_SubArrayLen[0]], 386 m_NDimensions+1,m_SubArrayLen+1); 387 } 388 389 // Indexing Constant Array 390 const RefArray<N-1> operator [](size_type Index) const 391 { 392 assert(m_pArrayElements); 393 assert(Index<m_NDimensions[0]); 394 return RefArray<N-1>(&m_pArrayElements[Index*m_SubArrayLen[0]], 395 m_NDimensions+1,m_SubArrayLen+1); 396 } 397 398 // Return RefArray referencing entire Array GetRefArray()399 RefArray<N> GetRefArray() 400 { 401 assert(m_pArrayElements); 402 return RefArray<N>(m_pArrayElements,m_NDimensions,m_SubArrayLen); 403 } 404 405 // Return constant RefArray referencing entire Array GetRefArray()406 const RefArray<N> GetRefArray() const 407 { 408 assert(m_pArrayElements); 409 return RefArray<N>(m_pArrayElements,m_NDimensions,m_SubArrayLen); 410 } 411 412 // Set the size of each array dimension 413 // Visual C++ does not accept parameter defined so: const unsigned int (&)[N] 414 // so I accepted a solution which is not type-safe: use it judiciously 415 bool resize(const unsigned int * Dimensions, const T & Init=T(), bool PreserveElems=false) 416 { 417 assert(Dimensions); 418 419 Array<T,N> Temp; 420 421 // Calculate all the information you need to use the array 422 Temp.m_nArrayElements=1; 423 for (int i=0;i<N;++i) 424 { 425 if (Dimensions[i]==0) 426 return false; // Check that no dimension was zero 427 Temp.m_nArrayElements*=Dimensions[i]; 428 Temp.m_NDimensions[i]=Dimensions[i]; 429 Temp.m_SubArrayLen[i]=1; 430 for (int k=N-1;k>i;k--) 431 Temp.m_SubArrayLen[i]*=Dimensions[k]; 432 } 433 434 // Allocate new elements, let exception propagate 435 Temp.m_pArrayElements=new T[Temp.m_nArrayElements]; 436 437 // Some compilers might not throw exception if allocation fails 438 if (!Temp.m_pArrayElements) 439 return false; 440 441 // Copy the elements from the previous array if requested 442 if (PreserveElems && !empty()) 443 Temp.copy(*this,Init); 444 // Otherwise initialize them to the specified value 445 else 446 Temp.initialize(Init); 447 448 // Now swap this object with the temporary 449 swap(Temp); 450 451 return true; 452 } 453 454 // resize accepting a fixed ArraySize, this solution is type-safe 455 bool resize(const ArraySize<N> & Dimensions, const T & Init=T(), bool PreserveElems=false) 456 { 457 unsigned int Dims[N]; 458 std::copy(Dimensions.Vect().begin(),Dimensions.Vect().end(),Dims); 459 return resize(Dims,Init,PreserveElems); 460 } 461 462 // Delete the complete Array clear()463 void clear() 464 { 465 delete [] m_pArrayElements; 466 m_pArrayElements=NULL; 467 m_nArrayElements=0; 468 469 std::fill(m_NDimensions,m_NDimensions+N,0); 470 std::fill(m_SubArrayLen,m_SubArrayLen+N,0); 471 } 472 473 // Assignment operator 474 Array<T,N> & operator = (const Array<T,N> & A) 475 { 476 if (&A!=this) // For efficiency 477 { 478 Array<T,N> Temp(A); 479 swap(Temp); 480 } 481 return *this; 482 } 483 484 // Return STL-like iterators begin()485 iterator begin() { return m_pArrayElements; } begin()486 const_iterator begin() const { return m_pArrayElements; } end()487 iterator end() { return m_pArrayElements+m_nArrayElements; } end()488 const_iterator end() const { return m_pArrayElements+m_nArrayElements; } 489 490 // Some more STL-like size members size()491 size_type size() const { return m_nArrayElements; } 492 493 // Return the size of each dimension, 1 to N size(unsigned int Dim)494 size_type size(unsigned int Dim) const 495 { 496 assert(Dim>=1 && Dim<=N); 497 return m_NDimensions[Dim-1]; 498 } 499 500 // Say if the array is empty empty()501 bool empty() const { return m_nArrayElements==0; } 502 503 // Return number of dimensions dimensions()504 unsigned int dimensions() const { return N; } 505 506 // Swap this array with another, a'la STL swap(Array<T,N> & A)507 void swap(Array<T,N> & A) 508 { 509 std::swap(m_pArrayElements,A.m_pArrayElements); 510 std::swap(m_nArrayElements,A.m_nArrayElements); 511 512 std::swap_ranges(m_NDimensions,m_NDimensions+N,A.m_NDimensions); 513 std::swap_ranges(m_SubArrayLen,m_SubArrayLen+N,A.m_SubArrayLen); 514 } 515 516 protected: 517 518 // The following are protected mainly because they are not exception-safe 519 // but the way they are used in the rest of the class is exception-safe 520 521 // Copy the elements of another array on this one where possible 522 // Where not possible, initialize them to a specified value Init 523 void copy(const Array<T,N> & A, const T & Init=T()) 524 { 525 size_type below=std::min(size(1),A.size(1)); 526 size_type above=size(1); 527 528 // Copy the elements we can copy 529 for (size_type i=0;i<below;++i) 530 (*this)[i].copy(A[i],Init); 531 532 // Reset the elements we can't copy 533 for (size_type j=below;j<above;++j) 534 (*this)[j].initialize(Init); 535 } 536 537 // Initialize all the array elements 538 void initialize(const T & Init=T()) 539 { 540 std::fill(begin(),end(),Init); 541 } 542 543 // Prefer non-member operator ==, but it needs to be a friend 544 friend bool operator == (const Array<T,N> & A, const Array<T,N> & B); 545 }; 546 547 548 // Test for equality between two arrays 549 template <typename T, unsigned int N> 550 bool operator == (const Array<T,N> & A, const Array<T,N> & B) 551 { 552 return std::equal(A.m_NDimensions,A.m_NDimensions+N,B.m_NDimensions) 553 && std::equal(A.begin(),A.end(),B.begin()); 554 } 555 556 // Test for inequality between two arrays 557 template <typename T, unsigned int N> 558 bool operator != (const Array<T,N> & A, const Array<T,N> & B) 559 { 560 return !(A==B); 561 } 562 563 564 /* The following don't work for Visual C++ 565 566 // Not implemented, meaningless to have 0 dimensions 567 template <typename T> 568 class Array<T,0> 569 { 570 }; 571 572 // Not implemented, use std::vector for one dimensional arrays 573 template <typename T> 574 class Array<T,1> 575 { 576 }; 577 578 */ 579 } 580 #endif 581 582 583