ColumnData.h
// Astrophysics Science Division,
// NASA/ Goddard Space Flight Center
// HEASARC
// http://heasarc.gsfc.nasa.gov
// e-mail: ccfits@legacy.gsfc.nasa.gov
//
// Original author: Ben Dorman
#ifndef COLUMNDATA_H
#define COLUMNDATA_H 1
#include "CCfits.h"
// vector
#include <vector>
// Column
#include "Column.h"
#ifdef _MSC_VER
#include "MSconfig.h"
#endif
#include <complex>
#include <memory>
#include <iterator>
#include "FITSUtil.h"
using std::complex;
#include "FITS.h"
namespace CCfits {
template <typename T>
class ColumnData : public Column //## Inherits: <unnamed>%385E51565EE8
{
public:
ColumnData(const ColumnData< T > &right);
ColumnData (Table* p = 0);
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 = "");
~ColumnData();
virtual ColumnData<T>* clone () const;
virtual void readData (long firstRow, long nelements, long firstElem = 1);
void setDataLimits (T* limits);
const T minLegalValue () const;
void minLegalValue (T value);
const T maxLegalValue () const;
void maxLegalValue (T value);
const T minDataValue () const;
void minDataValue (T value);
const T maxDataValue () const;
void maxDataValue (T value);
const std::vector<T>& data () const;
void setData (const std::vector<T>& value);
T data (int i);
void data (int i, T value);
// Additional Public Declarations
friend class Column;
protected:
// Additional Protected Declarations
private:
ColumnData< T > & operator=(const ColumnData< T > &right);
void readColumnData (long firstRow, long nelements, T* nullValue = 0);
virtual bool compare (const Column &right) const;
virtual std::ostream& put (std::ostream& s) const;
void writeData (T* indata, long nRows = 1, long firstRow = 1, T* nullValue = 0);
void writeData (const std::vector<T>& indata, long firstRow = 1, T* nullValue = 0);
// Insert one or more blank rows into a FITS column.
virtual void insertRows (long first, long number = 1);
virtual void deleteRows (long first, long number = 1);
virtual size_t getStoredDataSize() const;
// Additional Private Declarations
private: //## implementation
// Data Members for Class Attributes
T m_minLegalValue;
T m_maxLegalValue;
T m_minDataValue;
T m_maxDataValue;
// Data Members for Associations
std::vector<T> m_data;
// Additional Implementation Declarations
};
// Parameterized Class CCfits::ColumnData
template <typename T>
inline void ColumnData<T>::readData (long firstRow, long nelements, long firstElem)
{
readColumnData(firstRow,nelements,static_cast<T*>(0));
}
template <typename T>
inline const T ColumnData<T>::minLegalValue () const
{
return m_minLegalValue;
}
template <typename T>
inline void ColumnData<T>::minLegalValue (T value)
{
m_minLegalValue = value;
}
template <typename T>
inline const T ColumnData<T>::maxLegalValue () const
{
return m_maxLegalValue;
}
template <typename T>
inline void ColumnData<T>::maxLegalValue (T value)
{
m_maxLegalValue = value;
}
template <typename T>
inline const T ColumnData<T>::minDataValue () const
{
return m_minDataValue;
}
template <typename T>
inline void ColumnData<T>::minDataValue (T value)
{
m_minDataValue = value;
}
template <typename T>
inline const T ColumnData<T>::maxDataValue () const
{
return m_maxDataValue;
}
template <typename T>
inline void ColumnData<T>::maxDataValue (T value)
{
m_maxDataValue = value;
}
template <typename T>
inline const std::vector<T>& ColumnData<T>::data () const
{
return m_data;
}
template <typename T>
inline void ColumnData<T>::setData (const std::vector<T>& value)
{
m_data = value;
}
template <typename T>
inline T ColumnData<T>::data (int i)
{
// return data stored in the ith row, which is in the i-1 th location in the array.
return m_data[i - 1];
}
template <typename T>
inline void ColumnData<T>::data (int i, T value)
{
// assign data to i-1 th location in the array, representing the ith row.
m_data[i - 1] = value;
}
// Parameterized Class CCfits::ColumnData
template <typename T>
ColumnData<T>::ColumnData(const ColumnData<T> &right)
:Column(right),
m_minLegalValue(right.m_minLegalValue),
m_maxLegalValue(right.m_maxLegalValue),
m_minDataValue(right.m_minDataValue),
m_maxDataValue(right.m_maxDataValue),
m_data(right.m_data)
{
}
template <typename T>
ColumnData<T>::ColumnData (Table* p)
: Column(p),
m_minLegalValue(),
m_maxLegalValue(),
m_minDataValue(),
m_maxDataValue(),
m_data()
{
}
template <typename T>
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)
: Column(columnIndex,columnName,type,format,unit,p,rpt,w,comment),
m_minLegalValue(),
m_maxLegalValue(),
m_minDataValue(),
m_maxDataValue(),
m_data()
{
}
template <typename T>
ColumnData<T>::~ColumnData()
{
}
template <typename T>
void ColumnData<T>::readColumnData (long firstRow, long nelements, T* nullValue)
{
if ( rows() < nelements )
{
std::cerr << "CCfits: More data requested than contained in table. ";
std::cerr << "Extracting complete column.\n";
nelements = rows();
}
int status(0);
int anynul(0);
FITSUtil::auto_array_ptr<T> array(new T[nelements]);
makeHDUCurrent();
if ( fits_read_col(fitsPointer(),type(), index(), firstRow, 1,
nelements, nullValue, array.get(), &anynul, &status) ) throw FitsError(status);
if (m_data.size() != static_cast<size_t>( rows() ) ) m_data.resize(rows());
std::copy(&array[0],&array[nelements],m_data.begin()+firstRow-1);
if (nelements == rows()) isRead(true);
}
template <typename T>
bool ColumnData<T>::compare (const Column &right) const
{
if ( !Column::compare(right) ) return false;
const ColumnData<T>& that = static_cast<const ColumnData<T>&>(right);
unsigned int n = m_data.size();
if ( that.m_data.size() != n ) return false;
for (unsigned int i = 0; i < n ; i++)
{
if (m_data[i] != that.m_data[i]) return false;
}
return true;
}
template <typename T>
ColumnData<T>* ColumnData<T>::clone () const
{
return new ColumnData<T>(*this);
}
template <typename T>
std::ostream& ColumnData<T>::put (std::ostream& s) const
{
Column::put(s);
if (FITS::verboseMode() && type() != Tstring)
{
s << " Column Legal limits: ( " << m_minLegalValue << "," << m_maxLegalValue << " )\n"
<< " Column Data limits: ( " << m_minDataValue << "," << m_maxDataValue << " )\n";
}
if (!m_data.empty())
{
std::ostream_iterator<T> output(s,"\n");
// output each row on a separate line.
// user can supply manipulators to stream for formatting.
std::copy(m_data.begin(),m_data.end(),output);
}
return s;
}
template <typename T>
void ColumnData<T>::writeData (T* indata, long nRows, long firstRow, T* nullValue)
{
// set columnData's data member to equal what's written to file.
// indata has size nRows: elements firstRow to firstRow + nRows - 1 will be written.
// if this exceeds the current rowlength of the HDU, update the return value for
// rows() in the parent after the fitsio call.
int status(0);
try
{
if (nullValue)
{
if (fits_write_colnull(fitsPointer(), type(), index(), firstRow, 1, nRows,
indata, nullValue, &status) != 0) throw FitsError(status);
}
else
{
if (fits_write_col(fitsPointer(), type(), index(), firstRow, 1, nRows,
indata, &status) != 0) throw FitsError(status);
}
}
catch (FitsError) // the only thing that can throw here.
{
if (status == NO_NULL) throw NoNullValue(name());
else throw;
}
long elementsToWrite(nRows + firstRow -1);
if (elementsToWrite > static_cast<long>(m_data.size()))
{
m_data.resize(elementsToWrite,T());
}
std::copy(&indata[0],&indata[nRows],m_data.begin()+firstRow-1);
// tell the Table that the number of rows has changed
parent()->updateRows();
}
template <typename T>
void ColumnData<T>::writeData (const std::vector<T>& indata, long firstRow, T* nullValue)
{
FITSUtil::CVarray<T> convert;
FITSUtil::auto_array_ptr<T> pcolData (convert(indata));
T* columnData = pcolData.get();
writeData(columnData,indata.size(),firstRow,nullValue);
}
template <typename T>
void ColumnData<T>::insertRows (long first, long number)
{
// Don't assume the calling routine (ie. Table's insertRows)
// knows Column's current m_data size. m_data may still be
// size 0 if no read operations have been performed on Column.
// Therefore perform range checking before inserting.
// As with CFITSIO, rows are inserted AFTER 1-based 'first'.
if (first >= 0 && first <= static_cast<long>(m_data.size()))
{
typename std::vector<T>::iterator in;
if (first !=0)
{
in = m_data.begin()+first;
}
else
{
in = m_data.begin();
}
// non-throwing operations.
m_data.insert(in,number,T());
}
}
template <typename T>
void ColumnData<T>::deleteRows (long first, long number)
{
// Don't assume the calling routine (ie. Table's deleteRows)
// knows Column's current m_data size. m_data may still be
// size 0 if no read operations have been performed on Column.
// Therefore perform range checking before erasing.
const long curSize = static_cast<long>(m_data.size());
if (curSize>0 && first <= curSize)
{
const long last = std::min(curSize, first-1+number);
m_data.erase(m_data.begin()+first-1,m_data.begin()+last);
}
}
template <typename T>
size_t ColumnData<T>::getStoredDataSize() const
{
return m_data.size();
}
template <typename T>
void ColumnData<T>::setDataLimits (T* limits)
{
m_minLegalValue = limits[0];
m_maxLegalValue = limits[1];
m_minDataValue = std::max(limits[2],limits[0]);
m_maxDataValue = std::min(limits[3],limits[1]);
}
// Additional Declarations
// all functions that operate on strings or complex data that call cfitsio
// need to be specialized.
#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
template <>
inline void ColumnData<complex<float> >::setDataLimits (complex<float>* limits)
{
m_minLegalValue = limits[0];
m_maxLegalValue = limits[1];
m_minDataValue = limits[2];
m_maxDataValue = limits[3];
}
#else
template <>
void ColumnData<complex<float> >::setDataLimits (complex<float>* limits);
#endif
#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
template <>
inline void ColumnData<complex<double> >::setDataLimits (complex<double>* limits)
{
m_minLegalValue = limits[0];
m_maxLegalValue = limits[1];
m_minDataValue = limits[2];
m_maxDataValue = limits[3];
}
#else
template <>
void ColumnData<complex<double> >::setDataLimits (complex<double>* limits);
#endif
#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
template <>
inline void ColumnData<string>::readColumnData (long firstRow,
long nelements,
string* nullValue)
{
// nelements = nrows to read.
if (nelements < 1)
throw Column::InvalidNumberOfRows((int)nelements);
if (firstRow < 1 || (firstRow+nelements-1)>rows())
throw Column::InvalidRowNumber(name());
int status = 0;
int anynul = 0;
char** array = new char*[nelements];
// Initialize pointers to NULL so we can safely delete
// during error handling, even if they haven't been allocated.
for (long i=0; i<nelements; ++i)
array[i]=static_cast<char*>(0);
bool isError = false;
// Strings are unusual. The variable length case is still
// handled by a ColumnData class, not a ColumnVectorData.
char* nulval = 0;
if (nullValue)
{
nulval = const_cast<char*>(nullValue->c_str());
}
else
{
nulval = new char;
*nulval = '\0';
}
makeHDUCurrent();
if (varLength())
{
long* strLengths = new long[nelements];
long* offsets = new long[nelements];
if (fits_read_descripts(fitsPointer(), index(), firstRow,
nelements, strLengths, offsets, &status))
{
isError = true;
}
else
{
// For variable length cols, must read 1 and only 1 row
// at a time into array.
for (long j=0; j<nelements; ++j)
{
array[j] = new char[strLengths[j] + 1];
}
const long lastRow = firstRow+nelements-1;
for (long iRow=firstRow; !isError && iRow<=lastRow; ++iRow)
{
if (fits_read_col_str(fitsPointer(),index(), iRow, 1, 1,
nulval, &array[iRow-firstRow], &anynul,&status) )
isError=true;
}
}
delete [] strLengths;
delete [] offsets;
}
else
{
// Fixed length strings, length is stored in Column's m_width.
for (long j=0; j<nelements; ++j)
{
array[j] = new char[width() + 1];
}
if (fits_read_col_str(fitsPointer(),index(), firstRow,1,nelements,
nulval,array, &anynul,&status))
isError=true;
}
if (isError)
{
// It's OK to do this even if error occurred before
// array rows were allocated. In that case their pointers
// were set to NULL.
for (long j = 0; j < nelements; ++j)
{
delete [] array[j];
}
delete [] array;
delete nulval;
throw FitsError(status);
}
if (m_data.size() != static_cast<size_t>(rows()))
setData(std::vector<String>(rows(),String(nulval)));
for (long j=0; j<nelements; ++j)
{
m_data[j - 1 + firstRow] = String(array[j]);
}
for (long j=0; j<nelements; j++)
{
delete [] array[j];
}
delete [] array;
delete nulval;
if (nelements == rows()) isRead(true);
}
#else
template <>
void ColumnData<string>::readColumnData (long firstRow, long nelements, string* nullValue);
#endif
#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
template <>
inline void ColumnData<complex<float> >::readColumnData (long firstRow,
long nelements,
complex<float>* nullValue)
{
// specialization for ColumnData<string>
int status(0);
int anynul(0);
FITSUtil::auto_array_ptr<float> pArray(new float[nelements*2]);
float* array = pArray.get();
float nulval(0);
makeHDUCurrent();
if (fits_read_col_cmp(fitsPointer(),index(), firstRow,1,nelements,
nulval,array, &anynul,&status) ) throw FitsError(status);
if (m_data.size() != rows()) m_data.resize(rows());
// the 'j -1 ' converts to zero based indexing.
for (int j = 0; j < nelements; ++j)
{
m_data[j - 1 + firstRow] = std::complex<float>(array[2*j],array[2*j+1]);
}
if (nelements == rows()) isRead(true);
}
#else
template <>
void ColumnData<complex<float> >::readColumnData (long firstRow, long nelements,complex<float>* nullValue );
#endif
#if SPEC_TEMPLATE_IMP_DEFECT || SPEC_TEMPLATE_DECL_DEFECT
template <>
inline void ColumnData<complex<double> >::readColumnData (long firstRow,
long nelements,
complex<double>* nullValue)
{
// specialization for ColumnData<complex<double> >
int status(0);
int anynul(0);
FITSUtil::auto_array_ptr<double> pArray(new double[nelements*2]);
double* array = pArray.get();
double nulval(0);
makeHDUCurrent();
if (fits_read_col_dblcmp(fitsPointer(), index(), firstRow,1,nelements,
nulval,array, &anynul,&status) ) throw FitsError(status);
if (m_data.size() != rows()) setData(std::vector<complex<double> >(rows(),nulval));
// the 'j -1 ' converts to zero based indexing.
for (int j = 0; j < nelements; j++)
{
m_data[j - 1 + firstRow] = std::complex<double>(array[2*j],array[2*j+1]);
}
if (nelements == rows()) isRead(true);
}
#else
template <>
void ColumnData<complex<double> >::readColumnData (long firstRow, long nelements,complex<double>* nullValue);
#endif
#if SPEC_TEMPLATE_DECL_DEFECT
template <>
inline void ColumnData<string>::writeData (const std::vector<string>& indata,
long firstRow, string* nullValue)
{
int status=0;
char** columnData=FITSUtil::CharArray(indata);
if ( fits_write_colnull(fitsPointer(), TSTRING, index(), firstRow, 1, indata.size(),
columnData, 0, &status) != 0 )
throw FitsError(status);
unsigned long elementsToWrite (indata.size() + firstRow - 1);
std::vector<string> __tmp(m_data);
if (m_data.size() < elementsToWrite)
{
m_data.resize(elementsToWrite,"");
std::copy(__tmp.begin(),__tmp.end(),m_data.begin());
}
std::copy(indata.begin(),indata.end(),m_data.begin()+firstRow-1);
for (size_t i = 0; i < indata.size(); ++i)
{
delete [] columnData[i];
}
delete [] columnData;
}
#else
template <>
void ColumnData<string>::writeData (const std::vector<string>& inData, long firstRow, string* nullValue);
#endif
#ifdef SPEC_TEMPLATE_DECL_DEFECT
template <>
inline void ColumnData<complex<float> >::writeData (const std::vector<complex<float> >& inData,
long firstRow,
complex<float>* nullValue)
{
int status(0);
int nRows (inData.size());
FITSUtil::auto_array_ptr<float> pData(new float[nRows*2]);
float* Data = pData.get();
std::vector<complex<float> > __tmp(m_data);
for (int j = 0; j < nRows; ++j)
{
Data[ 2*j] = inData[j].real();
Data[ 2*j + 1] = inData[j].imag();
}
try
{
if (fits_write_col_cmp(fitsPointer(), index(), firstRow, 1,
nRows,Data, &status) != 0) throw FitsError(status);
long elementsToWrite(nRows + firstRow -1);
if (elementsToWrite > static_cast<long>(m_data.size()))
{
m_data.resize(elementsToWrite);
}
std::copy(inData.begin(),inData.end(),m_data.begin()+firstRow-1);
// tell the Table that the number of rows has changed
parent()->updateRows();
}
catch (FitsError) // the only thing that can throw here.
{
// reset to original content and rethrow the exception.
m_data.resize(__tmp.size());
m_data = __tmp;
}
}
#else
template <>
void ColumnData<complex<float> >::writeData (const std::vector<complex<float> >& inData, long firstRow,
complex<float>* nullValue);
#endif
#ifdef SPEC_TEMPLATE_DECL_DEFECT
template <>
inline void ColumnData<complex<double> >::writeData (const std::vector<complex<double> >& inData,
long firstRow,
complex<double>* nullValue)
{
int status(0);
int nRows (inData.size());
FITSUtil::auto_array_ptr<double> pData(new double[nRows*2]);
double* Data = pData.get();
std::vector<complex<double> > __tmp(m_data);
for (int j = 0; j < nRows; ++j)
{
pData[ 2*j] = inData[j].real();
pData[ 2*j + 1] = inData[j].imag();
}
try
{
if (fits_write_col_dblcmp(fitsPointer(), index(), firstRow, 1,
nRows,Data, &status) != 0) throw FitsError(status);
long elementsToWrite(nRows + firstRow -1);
if (elementsToWrite > static_cast<long>(m_data.size()))
{
m_data.resize(elementsToWrite);
}
std::copy(inData.begin(),inData.end(),m_data.begin()+firstRow-1);
// tell the Table that the number of rows has changed
parent()->updateRows();
}
catch (FitsError) // the only thing that can throw here.
{
// reset to original content and rethrow the exception.
m_data.resize(__tmp.size());
m_data = __tmp;
}
}
#else
template <>
void ColumnData<complex<double> >::writeData (const std::vector<complex<double> >& inData, long firstRow,
complex<double>* nullValue);
#endif
} // namespace CCfits
#endif
CCfits::Column::put
virtual std::ostream & put(std::ostream &s) const
internal implementation of &lt;&lt; operator.
Definition: Column.cxx:302
CCfits::FITS::verboseMode
static bool verboseMode()
return verbose setting for library
Definition: FITS.h:862
CCfits::ValueType
ValueType
CCfits value types and their CFITSIO equivalents (in caps)
Definition: CCfits.h:81
CCfits::Column::Column
Column(const Column &right)
copy constructor, used in copying Columns to standard library containers.
Definition: Column.cxx:171