www.pudn.com > colortracker.rar > Array.h


/* 
 *  Array.h 
 *   
 * 
 *  Created by John Hershey 2002. 
 *  Copyright (c) 2003 Machine Perception Laboratory 
 *  University of California San Diego. 
 *  Please read the disclaimer and notes about redistribution 
 *  at the end of this file. 
 * 
 *  Authors: John Hershey, Josh Susskind 
 */ 
#ifndef ARRAY_H 
#define ARRAY_H 
 
#include "preprocessor.h" 
 
#include  
#include  
#include "assert.h" 
 
//***************************************************************************** 
// Class Template for a Generic Resizable N Dimensional Array        (for N>=2) 
// By Giovanni Bavestrelli                  Copyright 1999 Giovanni Bavestrelli  
// Any feedback is welcome, you can contact me at gbavestrelli@yahoo.com 
// 
// This is the version for Microsoft Visual C++ 6.0, and perhaps for other  
// compilers which do not support partial specialization.  
// To make my classes work, I had to use a trick. I moved the RefArray classes  
// as nested classes withing class Array, removing template parameter T from  
// them, allowing me to use full specialization for class RefArray.  
// I don't think this is up to standard C++. If your compiler supports partial 
// specialization, be sure to use the other version of these classes. 
// Thanks to Andrei Alexandrescu for suggesting this trick, which makes my  
// classes work well with Visual C++, although the solution is not standard. 
//***************************************************************************** 
 
 
//============================================================================= 
// Classes for passing a typesafe vector of dimensions to the Array constructor 
//============================================================================= 
 
template  
class ArraySize 
{ 
     std::vector & Vector; 
 
     ArraySize(std::vector & v) 
        :Vector(v) 
     {} 
 
  public: 
 
     ArraySize operator () (unsigned int dim)  
     {  
        if (Vector.size()>N) Vector.resize(N); 
        Vector.push_back(dim); 
        return ArraySize(Vector); 
     } 
 
     const std::vector & Vect() const  
     { 
        assert(Vector.size()==N);  
        return Vector; 
     } 
 
     friend class ArraySizes; 
     friend class ArraySize; 
}; 
 
class ArraySizes 
{ 
     std::vector Vector; 
  
  public: 
       
     explicit ArraySizes(unsigned int dim)  
     {  
        Vector.push_back(dim);  
     } 
 
     ArraySize<2> operator () (unsigned int dim)  
     {  
        if (Vector.size()>1) Vector.resize(1); 
        Vector.push_back(dim); 
        return ArraySize<2>(Vector); 
     } 
}; 
 
//============================================================================= 
// Class Template for a Generic Resizable N Dimensional Array 
//============================================================================= 
 
template  
class Array 
{ 
 public: 
 
    //----------------------------------------------------------------------------- 
    // Class Template for N Dimensional SubArrays within an Array 
    //----------------------------------------------------------------------------- 
 
    template  
    class RefArray 
    { 
     public: 
 
       // STL-like types 
       typedef T         value_type; 
       typedef T &       reference; 
       typedef const T & const_reference; 
       typedef T *       pointer; 
       typedef const T * const_pointer; 
       typedef T *       iterator; 
       typedef const T * const_iterator; 
       typedef size_t    size_type; 
       typedef ptrdiff_t difference_type; 
 
       // Give access to number of dimensions 
       enum  { array_dims = N }; 
 
     private: 
 
       const size_type * const m_pNDimensions; // Array dimensions 
       const size_type * const m_pSubArrayLen; // SubArray dimensions 
 
       T   * const m_pElements; // Point to SubArray with elements within Array 
 
       RefArray(T * pElements, const size_type * pNDimensions,  
                                  const size_type * pSubArrayLen) 
         :m_pElements(pElements),m_pNDimensions(pNDimensions), 
                                 m_pSubArrayLen(pSubArrayLen) 
       {  
          assert(m_pElements && m_pNDimensions && m_pSubArrayLen);  
          assert(m_pNDimensions[0]>0 && m_pSubArrayLen[0]>0);  
       }   
 
     public: 
 
       RefArray operator [](size_type Index) 
       { 
          assert(m_pElements); 
          assert(Index(&m_pElements[Index*m_pSubArrayLen[0]], 
                                m_pNDimensions+1,m_pSubArrayLen+1); 
       } 
 
       const RefArray operator [](size_type Index) const 
       { 
          assert(m_pElements); 
          assert(Index(&m_pElements[Index*m_pSubArrayLen[0]], 
                                m_pNDimensions+1,m_pSubArrayLen+1); 
       } 
 
       // Return STL-like iterators 
       iterator       begin()       { return m_pElements; } 
       const_iterator begin() const { return m_pElements; } 
       iterator       end()         { return m_pElements+size(); } 
       const_iterator end()   const { return m_pElements+size(); }  
 
       // Return size of array 
       size_type size() const { return m_pNDimensions[0]*m_pSubArrayLen[0]; } 
 
       // Return size of subdimensions 
       size_type size(unsigned int Dim) const  
       {   
          assert(Dim>=1 && Dim<=N);  
          return m_pNDimensions[Dim-1];   
       } 
 
       // Return number of dimensions  
       unsigned int dimensions()  const { return N; } 
 
     protected: 
 
       // The following are protected mainly because they are not exception-safe 
       // but the way they are used in the rest of the class is exception-safe 
 
       // Copy the elements of another subarray on this one where possible 
       // Where not possible, initialize them to a specified value Init 
       void copy(const RefArray & SA, const T & Init=T()) 
       { 
           size_type below=std::_MIN(size(1),SA.size(1)); 
           size_type above=size(1); 
 
           // Copy the elements we can copy 
           for (size_type i=0;i; 
       friend class Array;  
       friend class RefArray;  
    }; 
 
 
    //----------------------------------------------------------------------------- 
    // Partial Specialization for Monodimensional SubArray within an Array 
    //----------------------------------------------------------------------------- 
 
    template <> 
    class RefArray<1> 
    { 
     public: 
 
       // STL-like types 
       typedef T         value_type; 
       typedef T &       reference; 
       typedef const T & const_reference; 
       typedef T *       pointer; 
       typedef const T * const_pointer; 
       typedef T *       iterator; 
       typedef const T * const_iterator; 
       typedef size_t    size_type; 
       typedef ptrdiff_t difference_type; 
 
       // Give access to number of dimensions 
       enum  { array_dims = 1 }; 
 
     private: 
 
       const size_type * const m_pNDimensions; // Array dimension 
 
       T   * const     m_pElements; // Point to elements within Array 
 
       RefArray<1>(T * pElements, const size_type * pNDimensions,  
                                  const size_type * pSubArrayLen) 
         :m_pElements(pElements),m_pNDimensions(pNDimensions) 
       {  
          assert(m_pElements && m_pNDimensions && pSubArrayLen);  
          assert(m_pNDimensions[0]>0 && pSubArrayLen[0]==1); // We found the elements 
       }  
 
     public: 
 
       reference operator [](size_type Index) 
       { 
          assert(m_pElements); 
          assert(Index & SA, const T & Init=T()) 
       { 
           size_type below=std::_MIN(size(1),SA.size(1)); 
           size_type above=size(1); 
 
           // Copy the elements we can copy 
           for (size_type i=0;i; 
       friend class Array; 
       friend class RefArray<2>;  
    }; 
 
 
//----------------------------------------------------------------------------- 
// Class Template for a Generic Resizable N Dimensional Array 
//----------------------------------------------------------------------------- 
 
 public: 
 
   // STL-like types 
   typedef T         value_type; 
   typedef T &       reference; 
   typedef const T & const_reference; 
   typedef T *       pointer; 
   typedef const T * const_pointer; 
   typedef T *       iterator; 
   typedef const T * const_iterator; 
   typedef size_t    size_type; 
   typedef ptrdiff_t difference_type; 
 
   // Give access to number of dimensions 
   enum  { array_dims = N }; 
 
 private: 
 
   T *        m_pArrayElements; // Pointer to actual array elements 
   size_type  m_nArrayElements; // Total number of array elements 
 
   size_type  m_NDimensions[N];  // Size of the N array dimensions 
   size_type  m_SubArrayLen[N];  // Size of each subarray 
 
 public: 
 
   // Default constructor 
   Array() 
      :m_pArrayElements(NULL),m_nArrayElements(0) 
   { 
      std::fill(m_NDimensions,m_NDimensions+N,0); 
      std::fill(m_SubArrayLen,m_SubArrayLen+N,0); 
   } 
    
   // This takes an array of N values representing the size of the N dimensions  
   explicit Array(const unsigned int * Dimensions, const T & Init=T()) 
      :m_pArrayElements(NULL),m_nArrayElements(0) 
   {  
      std::fill(m_NDimensions,m_NDimensions+N,0); 
      std::fill(m_SubArrayLen,m_SubArrayLen+N,0); 
 
      resize(Dimensions,Init);  
   } 
 
   // This takes an ArraySize object with the N dimensions 
   explicit Array(const ArraySize & Dimensions, const T & Init=T()) 
      :m_pArrayElements(NULL),m_nArrayElements(0) 
   {  
      std::fill(m_NDimensions,m_NDimensions+N,0); 
      std::fill(m_SubArrayLen,m_SubArrayLen+N,0); 
 
      resize(Dimensions,Init);  
   } 
 
   // Copy constructor 
   Array(const Array & A) 
      :m_pArrayElements(NULL),m_nArrayElements(0) 
   { 
      std::fill(m_NDimensions,m_NDimensions+N,0); 
      std::fill(m_SubArrayLen,m_SubArrayLen+N,0); 
 
      Array Temp; 
      if (!A.empty() && Temp.resize(A.m_NDimensions)) 
         std::copy(A.begin(),A.end(),Temp.begin()); 
      swap(Temp); 
   } 
 
   // Destructor 
  ~Array()  
   {  
      delete [] m_pArrayElements;  
   } 
 
   // Indexing Array 
   RefArray operator [](size_type Index)  
   {   
      assert(m_pArrayElements); 
      assert(Index(&m_pArrayElements[Index*m_SubArrayLen[0]], 
                            m_NDimensions+1,m_SubArrayLen+1); 
   } 
 
   // Indexing Constant Array 
   const RefArray operator [](size_type Index) const  
   {   
      assert(m_pArrayElements); 
      assert(Index(&m_pArrayElements[Index*m_SubArrayLen[0]], 
                            m_NDimensions+1,m_SubArrayLen+1); 
   } 
 
   // Return RefArray referencing entire Array  
   RefArray GetRefArray()  
   {   
      assert(m_pArrayElements); 
      return RefArray(m_pArrayElements,m_NDimensions,m_SubArrayLen); 
   } 
 
   // Return constant RefArray referencing entire Array  
   const RefArray GetRefArray() const  
   {   
      assert(m_pArrayElements); 
      return RefArray(m_pArrayElements,m_NDimensions,m_SubArrayLen); 
   } 
 
   // Set the size of each array dimension 
   // Visual C++ does not accept parameter defined so: const unsigned int (&)[N] 
   // so I accepted a solution which is not type-safe: use it judiciously 
   bool resize(const unsigned int * Dimensions, const T & Init=T(), bool PreserveElems=false) 
   { 
      assert(Dimensions); 
       
      Array Temp;  
 
      // Calculate all the information you need to use the array 
      Temp.m_nArrayElements=1; 
      for (int i=0;ii;k--) 
            Temp.m_SubArrayLen[i]*=Dimensions[k]; 
      }   
 
      // Allocate new elements, let exception propagate  
      Temp.m_pArrayElements=new T[Temp.m_nArrayElements]; 
  
      // Some compilers might not throw exception if allocation fails 
      if (!Temp.m_pArrayElements)  
          return false; 
 
      // Copy the elements from the previous array if requested 
      if (PreserveElems && !empty()) 
          Temp.copy(*this,Init); 
      // Otherwise initialize them to the specified value 
      else  
          Temp.initialize(Init); 
 
      // Now swap this object with the temporary 
      swap(Temp); 
 
      return true;  
   } 
 
   // resize accepting a fixed ArraySize, this solution is type-safe 
   bool resize(const ArraySize & Dimensions, const T & Init=T(), bool PreserveElems=false) 
   { 
      unsigned int Dims[N]; 
      std::copy(Dimensions.Vect().begin(),Dimensions.Vect().end(),Dims); 
      return resize(Dims,Init,PreserveElems); 
   } 
 
   // Delete the complete Array 
   void clear() 
   {  
      delete [] m_pArrayElements;  
      m_pArrayElements=NULL;  
      m_nArrayElements=0; 
 
      std::fill(m_NDimensions,m_NDimensions+N,0); 
      std::fill(m_SubArrayLen,m_SubArrayLen+N,0); 
   } 
 
   // Assignment operator 
   Array & operator = (const Array & A) 
   { 
      if (&A!=this) // For efficiency  
      { 
        Array Temp(A); 
        swap(Temp); 
      } 
      return *this; 
   } 
 
   // Return STL-like iterators 
   iterator       begin()       { return m_pArrayElements; } 
   const_iterator begin() const { return m_pArrayElements; } 
   iterator       end()         { return m_pArrayElements+m_nArrayElements; } 
   const_iterator end()   const { return m_pArrayElements+m_nArrayElements; } 
 
   // Some more STL-like size members 
   size_type size()       const { return m_nArrayElements; } 
 
   // Return the size of each dimension, 1 to N  
   size_type size(unsigned int Dim) const  
   {   
      assert(Dim>=1 && Dim<=N);  
      return m_NDimensions[Dim-1];   
   } 
 
   // Say if the array is empty 
   bool empty()           const { return m_nArrayElements==0; } 
 
   // Return number of dimensions 
   unsigned int dimensions()  const { return N; }  
 
   // Swap this array with another, a'la STL  
   void swap(Array & A) 
   { 
      std::swap(m_pArrayElements,A.m_pArrayElements);  
      std::swap(m_nArrayElements,A.m_nArrayElements);  
 
      std::swap_ranges(m_NDimensions,m_NDimensions+N,A.m_NDimensions); 
      std::swap_ranges(m_SubArrayLen,m_SubArrayLen+N,A.m_SubArrayLen); 
   } 
 
 protected: 
 
   // The following are protected mainly because they are not exception-safe 
   // but the way they are used in the rest of the class is exception-safe 
 
   // Copy the elements of another array on this one where possible 
   // Where not possible, initialize them to a specified value Init 
   void copy(const Array & A, const T & Init=T()) 
   { 
        size_type below=std::_MIN(size(1),A.size(1)); 
        size_type above=size(1); 
 
        // Copy the elements we can copy 
        for (size_type i=0;i & A, const Array & B); 
}; 
 
 
// Test for equality between two arrays 
template  
bool operator == (const Array & A, const Array & B) 
{ 
   return std::equal(A.m_NDimensions,A.m_NDimensions+N,B.m_NDimensions) 
       && std::equal(A.begin(),A.end(),B.begin()); 
} 
 
// Test for inequality between two arrays 
template  
bool operator != (const Array & A, const Array & B)  
{ 
   return !(A==B);  
} 
 
 
/* The following don't work for Visual C++ 
 
// Not implemented, meaningless to have 0 dimensions 
template  
class Array 
{ 
}; 
 
// Not implemented, use std::vector for one dimensional arrays 
template  
class Array 
{ 
}; 
 
*/ 
 
#endif 
 
/* 
 *  
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 
 *  
 *    1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
 *    3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 
 *  
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 *  
 */