CCfits  2.7
ColumnData.h
00001 //  Astrophysics Science Division,
00002 //  NASA/ Goddard Space Flight Center
00003 //  HEASARC
00004 //  http://heasarc.gsfc.nasa.gov
00005 //  e-mail: ccfits@legacy.gsfc.nasa.gov
00006 //
00007 //  Original author: Ben Dorman
00008 
00009 #ifndef COLUMNDATA_H
00010 #define COLUMNDATA_H 1
00011 #include "CCfits.h"
00012 
00013 // vector
00014 #include <vector>
00015 // Column
00016 #include "Column.h"
00017 #ifdef _MSC_VER
00018 #include "MSconfig.h"
00019 #endif
00020 
00021 #include <complex>
00022 #include <memory>
00023 #include <iterator>
00024 #include "FITSUtil.h"
00025 using std::complex;
00026 #include "FITS.h"
00027 
00028 
00029 namespace CCfits {
00030 
00031 
00032 
00033   template <typename T>
00034   class ColumnData : public Column  //## Inherits: <unnamed>%385E51565EE8
00035   {
00036 
00037     public:
00038         ColumnData(const ColumnData< T > &right);
00039         ColumnData (Table* p = 0);
00040         ColumnData (int columnIndex, const string &columnName, ValueType type, const String &format, const String &unit, Table* p, int rpt = 1, long w = 1, const String &comment = "");
00041         ~ColumnData();
00042 
00043         virtual ColumnData<T>* clone () const;
00044         virtual void readData (long firstRow, long nelements, long firstElem = 1);
00045         void setDataLimits (T* limits);
00046         const T minLegalValue () const;
00047         void minLegalValue (T value);
00048         const T maxLegalValue () const;
00049         void maxLegalValue (T value);
00050         const T minDataValue () const;
00051         void minDataValue (T value);
00052         const T maxDataValue () const;
00053         void maxDataValue (T value);
00054         const std::vector<T>& data () const;
00055         void setData (const std::vector<T>& value);
00056         T data (int i);
00057         void data (int i, T value);
00058 
00059       // Additional Public Declarations
00060         friend class Column;
00061     protected:
00062       // Additional Protected Declarations
00063 
00064     private:
00065         ColumnData< T > & operator=(const ColumnData< T > &right);
00066 
00067         void readColumnData (long firstRow, long nelements, T* nullValue = 0);
00068         virtual bool compare (const Column &right) const;
00069         virtual std::ostream& put (std::ostream& s) const;
00070         void writeData (T* indata, long nRows = 1, long firstRow = 1, T* nullValue = 0);
00071         void writeData (const std::vector<T>& indata, long firstRow = 1, T* nullValue = 0);
00072         //  Insert one or more blank rows into a FITS column.
00073         virtual void insertRows (long first, long number = 1);
00074         virtual void deleteRows (long first, long number = 1);
00075         
00076         virtual size_t getStoredDataSize() const;
00077 
00078       // Additional Private Declarations
00079 
00080     private: //## implementation
00081       // Data Members for Class Attributes
00082         T m_minLegalValue;
00083         T m_maxLegalValue;
00084         T m_minDataValue;
00085         T m_maxDataValue;
00086 
00087       // Data Members for Associations
00088         std::vector<T> m_data;
00089 
00090       // Additional Implementation Declarations
00091 
00092   };
00093 
00094   // Parameterized Class CCfits::ColumnData 
00095 
00096   template <typename T>
00097   inline void ColumnData<T>::readData (long firstRow, long nelements, long firstElem)
00098   {
00099    readColumnData(firstRow,nelements,static_cast<T*>(0));
00100   }
00101 
00102   template <typename T>
00103   inline const T ColumnData<T>::minLegalValue () const
00104   {
00105     return m_minLegalValue;
00106   }
00107 
00108   template <typename T>
00109   inline void ColumnData<T>::minLegalValue (T value)
00110   {
00111     m_minLegalValue = value;
00112   }
00113 
00114   template <typename T>
00115   inline const T ColumnData<T>::maxLegalValue () const
00116   {
00117     return m_maxLegalValue;
00118   }
00119 
00120   template <typename T>
00121   inline void ColumnData<T>::maxLegalValue (T value)
00122   {
00123     m_maxLegalValue = value;
00124   }
00125 
00126   template <typename T>
00127   inline const T ColumnData<T>::minDataValue () const
00128   {
00129     return m_minDataValue;
00130   }
00131 
00132   template <typename T>
00133   inline void ColumnData<T>::minDataValue (T value)
00134   {
00135     m_minDataValue = value;
00136   }
00137 
00138   template <typename T>
00139   inline const T ColumnData<T>::maxDataValue () const
00140   {
00141     return m_maxDataValue;
00142   }
00143 
00144   template <typename T>
00145   inline void ColumnData<T>::maxDataValue (T value)
00146   {
00147     m_maxDataValue = value;
00148   }
00149 
00150   template <typename T>
00151   inline const std::vector<T>& ColumnData<T>::data () const
00152   {
00153     return m_data;
00154   }
00155 
00156   template <typename T>
00157   inline void ColumnData<T>::setData (const std::vector<T>& value)
00158   {
00159     m_data = value;
00160   }
00161 
00162   template <typename T>
00163   inline T ColumnData<T>::data (int i)
00164   {
00165     // return data stored in the ith row, which is in the i-1 th location in the array.
00166     return m_data[i - 1];
00167   }
00168 
00169   template <typename T>
00170   inline void ColumnData<T>::data (int i, T value)
00171   {
00172     // assign data to i-1 th location in the array, representing the ith row.
00173     m_data[i - 1] = value;
00174   }
00175 
00176   // Parameterized Class CCfits::ColumnData 
00177 
00178   template <typename T>
00179   ColumnData<T>::ColumnData(const ColumnData<T> &right)
00180       :Column(right),
00181        m_minLegalValue(right.m_minLegalValue),
00182        m_maxLegalValue(right.m_maxLegalValue),
00183        m_minDataValue(right.m_minDataValue),
00184        m_maxDataValue(right.m_maxDataValue),
00185        m_data(right.m_data)
00186   {
00187   }
00188 
00189   template <typename T>
00190   ColumnData<T>::ColumnData (Table* p)
00191   : Column(p),
00192        m_minLegalValue(),
00193        m_maxLegalValue(),
00194        m_minDataValue(),
00195        m_maxDataValue(), 
00196        m_data()
00197   {
00198   }
00199 
00200   template <typename T>
00201   ColumnData<T>::ColumnData (int columnIndex, const string &columnName, ValueType type, const String &format, const String &unit, Table* p, int rpt, long w, const String &comment)
00202         : Column(columnIndex,columnName,type,format,unit,p,rpt,w,comment), 
00203         m_minLegalValue(),
00204         m_maxLegalValue(),
00205         m_minDataValue(),
00206         m_maxDataValue(),
00207         m_data()
00208   {
00209   }
00210 
00211 
00212   template <typename T>
00213   ColumnData<T>::~ColumnData()
00214   {
00215   }
00216 
00217 
00218   template <typename T>
00219   void ColumnData<T>::readColumnData (long firstRow, long nelements, T* nullValue)
00220   {
00221   if ( rows() < nelements ) 
00222   {
00223         std::cerr << "CCfits: More data requested than contained in table. ";
00224         std::cerr << "Extracting complete column.\n";
00225         nelements = rows();
00226    }   
00227 
00228    int   status(0);
00229    int   anynul(0);
00230 
00231    FITSUtil::auto_array_ptr<T> array(new T[nelements]); 
00232 
00233    makeHDUCurrent();
00234 
00235    if ( fits_read_col(fitsPointer(),type(),  index(), firstRow, 1, 
00236     nelements, nullValue, array.get(), &anynul, &status) ) throw FitsError(status);
00237 
00238 
00239    if (m_data.size() != static_cast<size_t>( rows() ) ) m_data.resize(rows());
00240 
00241    std::copy(&array[0],&array[nelements],m_data.begin()+firstRow-1);
00242    if (nelements == rows()) isRead(true); 
00243   }
00244 
00245   template <typename T>
00246   bool ColumnData<T>::compare (const Column &right) const
00247   {
00248   if ( !Column::compare(right) ) return false;
00249   const ColumnData<T>& that = static_cast<const ColumnData<T>&>(right);
00250   unsigned int n = m_data.size();
00251   if ( that.m_data.size() != n ) return false;
00252   for (unsigned int i = 0; i < n ; i++)
00253   {
00254         if (m_data[i] != that.m_data[i]) return false;   
00255   }
00256   return true;
00257   }
00258 
00259   template <typename T>
00260   ColumnData<T>* ColumnData<T>::clone () const
00261   {
00262         return new ColumnData<T>(*this);
00263   }
00264 
00265   template <typename T>
00266   std::ostream& ColumnData<T>::put (std::ostream& s) const
00267   {
00268   Column::put(s);
00269   if (FITS::verboseMode() && type() != Tstring)
00270   {
00271         s << " Column Legal limits: ( " << m_minLegalValue << "," << m_maxLegalValue << " )\n" 
00272         << " Column Data  limits: ( " << m_minDataValue << "," << m_maxDataValue << " )\n";
00273   }
00274   if (!m_data.empty())
00275   {
00276         std::ostream_iterator<T> output(s,"\n");
00277         // output each row on a separate line.
00278         // user can supply manipulators to stream for formatting.
00279         std::copy(m_data.begin(),m_data.end(),output);
00280   }
00281 
00282     return s;
00283   }
00284 
00285   template <typename T>
00286   void ColumnData<T>::writeData (T* indata, long nRows, long firstRow, T* nullValue)
00287   {
00288 
00289      // set columnData's data member to equal what's written to file.
00290      // indata has size nRows: elements firstRow to firstRow + nRows - 1 will be written.
00291      // if this exceeds the current rowlength of the HDU, update the return value for
00292      // rows() in the parent after the fitsio call.
00293      int status(0);
00294 
00295      try
00296      {
00297         if (nullValue)
00298         {
00299            if (fits_write_colnull(fitsPointer(), type(), index(), firstRow, 1, nRows,
00300                  indata, nullValue, &status) != 0) throw FitsError(status);
00301         }
00302         else
00303         {
00304            if (fits_write_col(fitsPointer(), type(), index(), firstRow, 1, nRows,
00305                  indata, &status) != 0) throw FitsError(status);
00306         }
00307 
00308      }
00309      catch (FitsError) // the only thing that can throw here.
00310      {
00311           if (status == NO_NULL) throw NoNullValue(name());
00312           else throw;
00313      }      
00314      long elementsToWrite(nRows + firstRow -1);
00315 
00316      if (elementsToWrite > static_cast<long>(m_data.size())) 
00317      {
00318         m_data.resize(elementsToWrite,T());
00319      }
00320 
00321      std::copy(&indata[0],&indata[nRows],m_data.begin()+firstRow-1);
00322      // tell the Table that the number of rows has changed
00323      parent()->updateRows();
00324 
00325   }
00326 
00327   template <typename T>
00328   void ColumnData<T>::writeData (const std::vector<T>& indata, long firstRow, T* nullValue)
00329   {
00330         FITSUtil::CVarray<T> convert;
00331         FITSUtil::auto_array_ptr<T> pcolData (convert(indata));
00332         T* columnData  = pcolData.get();
00333         writeData(columnData,indata.size(),firstRow,nullValue);
00334   }
00335 
00336   template <typename T>
00337   void ColumnData<T>::insertRows (long first, long number)
00338   {
00339     // Don't assume the calling routine (ie. Table's insertRows)
00340     // knows Column's current m_data size.  m_data may still be
00341     // size 0 if no read operations have been performed on Column. 
00342     // Therefore perform range checking before inserting.
00343     
00344     // As with CFITSIO, rows are inserted AFTER 1-based 'first'.
00345     if (first >= 0 && first <= static_cast<long>(m_data.size()))
00346     {
00347        typename std::vector<T>::iterator in;
00348        if (first !=0) 
00349        {
00350                in = m_data.begin()+first;
00351        }
00352        else
00353        {
00354                in = m_data.begin();
00355        }           
00356 
00357        // non-throwing operations.
00358        m_data.insert(in,number,T());
00359     }
00360   }
00361 
00362   template <typename T>
00363   void ColumnData<T>::deleteRows (long first, long number)
00364   {
00365     // Don't assume the calling routine (ie. Table's deleteRows)
00366     // knows Column's current m_data size.  m_data may still be
00367     // size 0 if no read operations have been performed on Column. 
00368     // Therefore perform range checking before erasing.
00369     const long curSize = static_cast<long>(m_data.size());
00370     if (curSize>0 && first <= curSize)
00371     {
00372        const long last = std::min(curSize, first-1+number);
00373        m_data.erase(m_data.begin()+first-1,m_data.begin()+last);
00374     }
00375   }
00376   
00377   template <typename T>
00378   size_t ColumnData<T>::getStoredDataSize() const
00379   {
00380      return m_data.size();
00381   }
00382 
00383   template <typename T>
00384   void ColumnData<T>::setDataLimits (T* limits)
00385   {
00386     m_minLegalValue = limits[0];
00387     m_maxLegalValue = limits[1];
00388     m_minDataValue = std::max(limits[2],limits[0]);
00389     m_maxDataValue = std::min(limits[3],limits[1]);
00390   }
00391 
00392   // Additional Declarations
00393 
00394   // all functions that operate on strings or complex data that call cfitsio 
00395   // need to be specialized.
00396 
00397 #if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
00398 template <>
00399 inline void ColumnData<complex<float> >::setDataLimits (complex<float>* limits)
00400        {
00401                 m_minLegalValue = limits[0];
00402                 m_maxLegalValue = limits[1];
00403                 m_minDataValue =  limits[2];
00404                 m_maxDataValue =  limits[3];
00405         }
00406 #else
00407 template <>
00408   void ColumnData<complex<float> >::setDataLimits (complex<float>* limits);
00409 #endif
00410 
00411 #if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
00412 template <>
00413 inline void ColumnData<complex<double> >::setDataLimits (complex<double>* limits)
00414         {
00415                 m_minLegalValue = limits[0];
00416                 m_maxLegalValue = limits[1];
00417                 m_minDataValue =  limits[2];
00418                 m_maxDataValue =  limits[3];
00419         }
00420 #else
00421  template <>
00422   void ColumnData<complex<double> >::setDataLimits (complex<double>* limits);
00423 #endif
00424 
00425 
00426 #if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
00427         template <>
00428         inline void ColumnData<string>::readColumnData (long firstRow, 
00429                                         long nelements, 
00430                                         string* nullValue)
00431         {
00432            // nelements = nrows to read.
00433            if (nelements < 1)
00434               throw Column::InvalidNumberOfRows((int)nelements);
00435            if (firstRow < 1 || (firstRow+nelements-1)>rows())
00436               throw Column::InvalidRowNumber(name());
00437            
00438            int status = 0;
00439            int   anynul = 0;
00440            
00441            char** array = new char*[nelements];
00442            // Initialize pointers to NULL so we can safely delete
00443            //  during error handling, even if they haven't been allocated.           
00444            for (long i=0; i<nelements; ++i)
00445               array[i]=static_cast<char*>(0);
00446            bool isError = false;
00447 
00448            // Strings are unusual.  The variable length case is still
00449            //  handled by a ColumnData class, not a ColumnVectorData.
00450            char* nulval = 0;
00451            if (nullValue) 
00452            {
00453               nulval = const_cast<char*>(nullValue->c_str());
00454            }
00455            else
00456            {
00457               nulval = new char;
00458               *nulval = '\0';       
00459            }
00460            makeHDUCurrent();
00461            if (varLength())
00462            {
00463               long* strLengths = new long[nelements];
00464               long* offsets = new long[nelements];
00465               if (fits_read_descripts(fitsPointer(), index(), firstRow,
00466                    nelements, strLengths, offsets, &status))
00467               {
00468                  isError = true;
00469               }
00470               else
00471               {
00472                  // For variable length cols, must read 1 and only 1 row
00473                  //  at a time into array.
00474                  for (long j=0; j<nelements; ++j)
00475                  {
00476                     array[j] = new char[strLengths[j] + 1];
00477                  }
00478                  
00479                  const long lastRow = firstRow+nelements-1;
00480                  for (long iRow=firstRow; !isError && iRow<=lastRow; ++iRow)
00481                  {
00482                     if (fits_read_col_str(fitsPointer(),index(), iRow, 1, 1,
00483                       nulval, &array[iRow-firstRow], &anynul,&status) )
00484                        isError=true;
00485                  }
00486               }
00487               delete [] strLengths;
00488               delete [] offsets;              
00489            }
00490            else
00491            {
00492               // Fixed length strings, length is stored in Column's m_width.
00493               for (long j=0; j<nelements; ++j)
00494               {
00495                   array[j] = new char[width() + 1];
00496               }
00497               if (fits_read_col_str(fitsPointer(),index(), firstRow,1,nelements,
00498                 nulval,array, &anynul,&status))
00499                 isError=true;
00500            }
00501            
00502            if (isError)
00503            {
00504               // It's OK to do this even if error occurred before
00505               //  array rows were allocated.  In that case their pointers
00506               //  were set to NULL.
00507               for (long j = 0; j < nelements; ++j)
00508               {
00509                  delete [] array[j];
00510               }     
00511               delete [] array; 
00512               delete nulval;
00513               throw FitsError(status); 
00514            }
00515 
00516           if (m_data.size() != static_cast<size_t>(rows()))
00517               setData(std::vector<String>(rows(),String(nulval)));
00518 
00519           for (long j=0; j<nelements; ++j)
00520           {
00521              m_data[j - 1 + firstRow] = String(array[j]);
00522           }
00523 
00524           for (long j=0; j<nelements; j++)
00525           {
00526              delete [] array[j];
00527           }     
00528           delete [] array; 
00529           delete nulval; 
00530           if (nelements == rows()) isRead(true); 
00531 
00532         }
00533 #else 
00534  template <>
00535 void ColumnData<string>::readColumnData (long firstRow, long nelements, string* nullValue);
00536 #endif
00537 
00538 
00539 #if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
00540         template <>
00541         inline void ColumnData<complex<float> >::readColumnData (long firstRow,
00542                                                 long nelements,
00543                                                 complex<float>* nullValue)
00544         {
00545           // specialization for ColumnData<string> 
00546           int status(0);
00547           int   anynul(0);
00548           FITSUtil::auto_array_ptr<float> pArray(new float[nelements*2]); 
00549           float* array = pArray.get();
00550           float nulval(0);
00551           makeHDUCurrent();
00552 
00553 
00554           if (fits_read_col_cmp(fitsPointer(),index(), firstRow,1,nelements,
00555                   nulval,array, &anynul,&status) ) throw FitsError(status);
00556 
00557 
00558           if (m_data.size() != rows()) m_data.resize(rows());
00559 
00560           // the 'j -1 ' converts to zero based indexing.
00561 
00562           for (int j = 0; j < nelements; ++j)
00563           {
00564 
00565                 m_data[j - 1 + firstRow] = std::complex<float>(array[2*j],array[2*j+1]);
00566           }
00567           if (nelements == rows()) isRead(true); 
00568 
00569         }
00570 #else
00571 template <> 
00572 void ColumnData<complex<float> >::readColumnData (long firstRow, long nelements,complex<float>* nullValue );
00573 #endif
00574 
00575 #if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
00576         template <>
00577         inline void ColumnData<complex<double> >::readColumnData (long firstRow, 
00578                                                         long nelements,
00579                                                         complex<double>* nullValue)
00580         {
00581           // specialization for ColumnData<complex<double> > 
00582            int status(0);
00583            int   anynul(0);
00584            FITSUtil::auto_array_ptr<double> pArray(new double[nelements*2]); 
00585            double* array = pArray.get();
00586            double nulval(0);
00587            makeHDUCurrent();
00588 
00589 
00590           if (fits_read_col_dblcmp(fitsPointer(), index(), firstRow,1,nelements,
00591                   nulval,array, &anynul,&status) ) throw FitsError(status);
00592 
00593 
00594 
00595 
00596           if (m_data.size() != rows()) setData(std::vector<complex<double> >(rows(),nulval));
00597 
00598           // the 'j -1 ' converts to zero based indexing.
00599 
00600           for (int j = 0; j < nelements; j++)
00601           {
00602 
00603                 m_data[j - 1 + firstRow] = std::complex<double>(array[2*j],array[2*j+1]);
00604           }
00605           if (nelements == rows()) isRead(true); 
00606 
00607         }
00608 #else
00609 template <>
00610 void ColumnData<complex<double> >::readColumnData (long firstRow, long nelements,complex<double>* nullValue);
00611 #endif
00612 
00613 #if SPEC_TEMPLATE_DECL_DEFECT
00614   template <>
00615   inline void ColumnData<string>::writeData (const std::vector<string>& indata, 
00616                       long firstRow, string* nullValue)
00617   {
00618     int    status=0;
00619     char** columnData=FITSUtil::CharArray(indata);
00620 
00621     if ( fits_write_colnull(fitsPointer(), TSTRING, index(), firstRow, 1, indata.size(),
00622                 columnData, 0, &status) != 0 )
00623       throw FitsError(status);
00624     unsigned long elementsToWrite (indata.size() + firstRow - 1);
00625     std::vector<string> __tmp(m_data);
00626     if (m_data.size() < elementsToWrite) 
00627       {
00628     m_data.resize(elementsToWrite,"");
00629     std::copy(__tmp.begin(),__tmp.end(),m_data.begin());
00630       }
00631     std::copy(indata.begin(),indata.end(),m_data.begin()+firstRow-1);
00632 
00633 
00634     for (size_t i = 0; i < indata.size(); ++i)
00635       {
00636     delete [] columnData[i];
00637       }
00638     delete [] columnData;
00639   }  
00640 #else
00641 template <>
00642 void ColumnData<string>::writeData (const std::vector<string>& inData, long firstRow, string* nullValue);
00643 #endif
00644 
00645 #ifdef SPEC_TEMPLATE_DECL_DEFECT
00646   template <>
00647   inline void ColumnData<complex<float> >::writeData (const std::vector<complex<float> >& inData, 
00648                            long firstRow, 
00649                            complex<float>* nullValue)
00650   {
00651     int status(0);
00652     int nRows (inData.size());
00653     FITSUtil::auto_array_ptr<float> pData(new float[nRows*2]);
00654     float* Data = pData.get();
00655     std::vector<complex<float> > __tmp(m_data);
00656     for (int j = 0; j < nRows; ++j)
00657       {
00658     Data[ 2*j] = inData[j].real();
00659     Data[ 2*j + 1] = inData[j].imag();
00660       }     
00661 
00662     try
00663       {
00664 
00665     if (fits_write_col_cmp(fitsPointer(), index(), firstRow, 1, 
00666                    nRows,Data, &status) != 0) throw FitsError(status);
00667     long elementsToWrite(nRows + firstRow -1);
00668     if (elementsToWrite > static_cast<long>(m_data.size())) 
00669       {
00670 
00671         m_data.resize(elementsToWrite);
00672       }
00673 
00674     std::copy(inData.begin(),inData.end(),m_data.begin()+firstRow-1);
00675 
00676     // tell the Table that the number of rows has changed
00677     parent()->updateRows();
00678       }
00679     catch (FitsError) // the only thing that can throw here.
00680       {
00681     // reset to original content and rethrow the exception.
00682     m_data.resize(__tmp.size());
00683     m_data = __tmp;
00684       }      
00685 
00686   }
00687 
00688 #else
00689 template <>
00690 void ColumnData<complex<float> >::writeData (const std::vector<complex<float> >& inData, long firstRow, 
00691                                 complex<float>* nullValue);
00692 #endif
00693 
00694 #ifdef SPEC_TEMPLATE_DECL_DEFECT
00695   template <>
00696   inline void ColumnData<complex<double> >::writeData (const std::vector<complex<double> >& inData, 
00697                         long firstRow, 
00698                         complex<double>* nullValue)
00699   {
00700     int status(0);
00701     int nRows (inData.size());
00702     FITSUtil::auto_array_ptr<double> pData(new double[nRows*2]);
00703     double* Data = pData.get();
00704     std::vector<complex<double> > __tmp(m_data);
00705     for (int j = 0; j < nRows; ++j)
00706       {
00707     pData[ 2*j] = inData[j].real();
00708     pData[ 2*j + 1] = inData[j].imag();
00709       }     
00710 
00711     try
00712       {
00713 
00714     if (fits_write_col_dblcmp(fitsPointer(), index(), firstRow, 1, 
00715                                   nRows,Data, &status) != 0) throw FitsError(status);
00716     long elementsToWrite(nRows + firstRow -1);
00717     if (elementsToWrite > static_cast<long>(m_data.size())) 
00718       {
00719 
00720         m_data.resize(elementsToWrite);
00721       }
00722 
00723     std::copy(inData.begin(),inData.end(),m_data.begin()+firstRow-1);
00724 
00725     // tell the Table that the number of rows has changed
00726     parent()->updateRows();
00727       }
00728     catch (FitsError) // the only thing that can throw here.
00729       {
00730     // reset to original content and rethrow the exception.
00731     m_data.resize(__tmp.size());
00732     m_data = __tmp;
00733       }      
00734 
00735   }
00736 
00737 #else
00738 template <>
00739 void ColumnData<complex<double> >::writeData (const std::vector<complex<double> >& inData, long firstRow, 
00740                                 complex<double>* nullValue);
00741 
00742 #endif
00743 } // namespace CCfits
00744 
00745 
00746 #endif