Index: /trunk/SophyaExt/FitsIOServer/swfitsdtable.cc
===================================================================
--- /trunk/SophyaExt/FitsIOServer/swfitsdtable.cc	(revision 2865)
+++ /trunk/SophyaExt/FitsIOServer/swfitsdtable.cc	(revision 2865)
@@ -0,0 +1,402 @@
+#include "swfitsdtable.h"
+#include "sopnamsp.h"
+#include "pexceptions.h"
+
+
+/*!
+   \class SOPHYA::SwFitsDataTable
+   \ingroup FitsIOServer
+   This class can be used to organize data in table (row-column) form.
+   Each column holds homogeneous data (same data type), while different
+   columns can be used for different data types 
+   (integer, float, string ...).
+   A Fits file binary table is used as swap space.
+
+   \warning 
+   - When creating a table, the output fits file (FitsInOutFile) must not be closed
+   (destroyed) before the SwFitsDataTable object is destroyed. The destructor writes
+   out any pending buffer to the fits file.
+   - It is not possible to make a complete (deep) copy of a SwFitsDataTable
+   Copy constructor and equal operator shares the data.
+
+   \sa SOPHYA::MuTyV
+   \sa SOPHYA::DataTableRow
+   \sa SOPHYA::DataTable
+   \sa SOPHYA::SwSegDataBlock  SOPHYA::FitsDataSwapper
+
+   \code
+   #include "swppfdtable.h"
+   // ...
+   {
+   // ---- Creation of the table
+   // Create the swap stream 
+   POutPersist so("myswtable.ppf");
+   SwFitsDataTable dt(so, 64);
+   // define table columns
+   dt.AddFloatColumn("X0_f");
+   dt.AddFloatColumn("X1_f");
+   dt.AddDoubleColumn("X0X0pX1X1_d");
+   // Fill the table
+   MuTyV x[5];
+   for(int i=0; i<63; i++) {
+     x[0] = (i%9)-4.;  x[1] = (i/9)-3.;  x[2] = x[0]*x[0]+x[1]*x[1];
+     dt.AddLine(x);
+   }
+   // Printing table info
+   cout << dt ;
+   // Swap out all data and write the table structure to the PPF stream 
+   so << dt ;
+   // ....
+   }
+   {
+   // ---- Accessing information from a previously created table
+   SwFitsDataTable dt;
+   PInPersist si("myswtable.ppf");
+   si >> dt;
+   // Printing table info
+   cout << dt ;   
+   }
+   \endcode
+*/
+//! Default constructor with optional specification of block (or segment) size 
+SwFitsDataTable::SwFitsDataTable(sa_size_t segsz)
+  : BaseDataTable(segsz)
+{
+  mFgCreate = false;
+}
+/*! Constructor with the specification of the output swap stream -
+    and optional specification of block (or segment) size
+*/
+SwFitsDataTable::SwFitsDataTable(FitsInOutFile & os, sa_size_t segsz, bool fgcreate)
+  : BaseDataTable(segsz) ,
+    mSwF(os) , mFgCreate(fgcreate)
+{
+}
+//! copy constructor - shares the data
+SwFitsDataTable::SwFitsDataTable(SwFitsDataTable const & a)
+  : BaseDataTable(a.SegmentSize()),
+    mSwF(a.mSwF) , mFgCreate(a.mFgCreate)
+{
+  Share(a);
+}
+//! Destructor - Deletes / closes the input PPF swap stream  
+SwFitsDataTable::~SwFitsDataTable()
+{
+  if (mFgCreate) SwapOutAll();
+}
+
+void SwFitsDataTable::Share(SwFitsDataTable const & a)
+{
+  // On recopie la taille de segment
+  mSegSz = a.SegmentSize();
+  if (a.NVar() == 0)  return;  // Table sans colonne 
+
+  // On copie la structure de table 
+  CopyStructure(a);
+
+  //
+  // Update nombre d'entree, ...
+  mNEnt = a.mNEnt;
+  mNSeg = a.mNSeg;
+  if (a.mInfo)  mInfo = new DVList(*(a.mInfo));
+
+  // mis a jour des tableax min-max 
+  mMin = a.mMin;
+  mMax = a.mMax;
+  mMinMaxNEnt = a.mMinMaxNEnt;
+
+  // Et on partage les donnees des colonnes 
+  for (size_t kk=0; kk<mNames.size(); kk++) {
+    sa_size_t sk = mNames[kk].ser;
+    sa_size_t ska = a.mNames[kk].ser;
+    switch (mNames[kk].type) {
+    case IntegerField :
+      mICols[sk] = a.mICols[ska];
+    break;
+    case LongField :
+      mLCols[sk] = a.mLCols[ska]; 
+      break;
+    case FloatField :
+      mFCols[sk] = a.mFCols[ska]; 
+      break;
+    case DoubleField :
+    case DateTimeField :
+      mDCols[sk] = a.mDCols[ska]; 
+      break;
+    case ComplexField :
+      mYCols[sk] = a.mYCols[ska]; 
+      break;
+    case DoubleComplexField :
+      mZCols[sk] = a.mZCols[ska]; 
+      break;
+    case StringField :
+      mSCols[sk] = a.mSCols[ska]; 
+      break;
+    default:
+      throw ForbiddenError("SwFitsDataTable::Share() : unknown column type ");
+    break;
+    }
+  }  
+}
+void SwFitsDataTable::SwapOutAll() const
+{
+  // Et on vide les buffers de swap 
+  for (size_t kk=0; kk<mNames.size(); kk++) {
+    sa_size_t sk = mNames[kk].ser;
+    switch (mNames[kk].type) {
+    case IntegerField :
+      mICols[sk].SwapOutBuffer();
+    break;
+    case LongField :
+      mLCols[sk].SwapOutBuffer();
+      break;
+    case FloatField :
+      mFCols[sk].SwapOutBuffer();
+      break;
+    case DoubleField :
+    case DateTimeField :
+      mDCols[sk].SwapOutBuffer();
+      break;
+    case ComplexField :
+      mYCols[sk].SwapOutBuffer();
+      break;
+    case DoubleComplexField :
+      mZCols[sk].SwapOutBuffer();
+      break;
+    case StringField :
+      mSCols[sk].SwapOutBuffer();
+      break;
+    default:
+      throw ForbiddenError("SwFitsDataTable::Share() : unknown column type ");
+    break;
+    }
+  }  
+}
+
+void SwFitsDataTable::Clear()
+{
+  if ( (NVar() == 0) && (NEntry() == 0)) return;
+  mNEnt = 0;
+  mNSeg = 0;
+  if (mVarD) delete[] mVarD;
+  mVarD = NULL;
+  if (mVarMTV) delete[] mVarMTV;
+  mVarMTV = NULL;
+  mNames.clear();
+  if (mInfo) delete mInfo;
+  mInfo = NULL;
+  mMin.clear();
+  mMax.clear();
+  mMinMaxNEnt.clear();
+  mIColsP.clear();
+  mLColsP.clear();
+  mFColsP.clear();
+  mDColsP.clear();
+  mYColsP.clear();
+  mZColsP.clear();
+  mSColsP.clear();
+
+  mIColIdx.clear();
+  mLColIdx.clear();
+  mFColIdx.clear();
+  mDColIdx.clear();
+  mYColIdx.clear();
+  mZColIdx.clear();
+  mSColIdx.clear();
+
+  mICols.clear();
+  mLCols.clear();
+  mFCols.clear();
+  mDCols.clear();
+  mYCols.clear();
+  mZCols.clear();
+  mSCols.clear();
+
+  /*
+  mISwapper.clear();
+  mLSwapper.clear();
+  mFSwapper.clear();
+  mDSwapper.clear();
+  mYSwapper.clear();
+  mZSwapper.clear();
+  mSSwapper.clear();
+  */
+}
+
+
+/*! 
+  Implements the action defined in the BaseDataTable interface.
+  In the current implementation, throws an exception (ParmError) 
+  if the table contains some data already.
+*/
+sa_size_t SwFitsDataTable::AddColumn(FieldType ft, string const & cnom)
+{
+  return AddColRd(ft, cnom, NULL);
+}
+/*! 
+  Adds a column to the table. If swpos != NULL, the swapper is initialized 
+  for reading data from the fits file. This method can be called
+  by FitsHandler<BaseDataTable> with non zero swpos. 
+*/
+sa_size_t SwFitsDataTable::AddColRd(FieldType ft, string const & cnom, 
+				    vector<int_8> const * swpos)
+{
+  if (NEntry() > 0) 
+    throw ParmError("SwFitsDataTable::AddColumn() Table contains already data ");
+  CheckColName(cnom);
+  sa_size_t ser; 
+  sa_size_t idx = NVar(); 
+  switch (ft) {
+  case IntegerField :
+  {
+    ser = mICols.size();
+    FITSDataSwapper<int_4> ISwapper(mSwF, idx+1);
+    if (swpos)
+      mICols.push_back(SwSegDataBlock<int_4>(ISwapper, *swpos, mSegSz));
+    else 
+      mICols.push_back(SwSegDataBlock<int_4>(ISwapper, mSegSz));
+    mIColIdx.push_back(idx);
+    mIColsP.push_back(NULL);
+    for(sa_size_t kk=0; kk<mICols.size(); kk++)
+      mIColsP[kk] = &(mICols[kk]);
+    break;
+  }
+  case LongField :
+  {
+    ser = mLCols.size();
+    FITSDataSwapper<int_8> LSwapper(mSwF, idx+1);
+    if (swpos)    
+      mLCols.push_back(SwSegDataBlock<int_8>(LSwapper, *swpos, mSegSz));
+    else 
+      mLCols.push_back(SwSegDataBlock<int_8>(LSwapper, mSegSz));
+    mLColIdx.push_back(idx);
+    mLColsP.push_back(NULL);
+    for(sa_size_t kk=0; kk<mLCols.size(); kk++)
+      mLColsP[kk] = &(mLCols[kk]);
+    break;
+  }
+  case FloatField :
+  {
+    ser = mFCols.size();
+    FITSDataSwapper<r_4> FSwapper(mSwF, idx+1);
+    if (swpos)    
+      mFCols.push_back(SwSegDataBlock<r_4>(FSwapper, *swpos, mSegSz));
+    else
+      mFCols.push_back(SwSegDataBlock<r_4>(FSwapper, mSegSz));
+    mFColIdx.push_back(idx);
+    mFColsP.push_back(NULL);
+    for(sa_size_t kk=0; kk<mFCols.size(); kk++)
+      mFColsP[kk] = &(mFCols[kk]);
+    break;
+  }
+  case DoubleField :
+  case DateTimeField :
+  {
+    ser = mDCols.size();
+    FITSDataSwapper<r_8> DSwapper(mSwF, idx+1);
+    if (swpos)    
+      mDCols.push_back(SwSegDataBlock<r_8>(DSwapper, *swpos, mSegSz));
+    else 
+      mDCols.push_back(SwSegDataBlock<r_8>(DSwapper, mSegSz));      
+    mDColIdx.push_back(idx);
+    mDColsP.push_back(NULL);
+    for(sa_size_t kk=0; kk<mDCols.size(); kk++)
+      mDColsP[kk] = &(mDCols[kk]);
+    break;
+  }
+  case ComplexField :
+  {
+    ser = mYCols.size();
+    FITSDataSwapper< complex<r_4> > YSwapper(mSwF, idx+1);
+    if (swpos)    
+      mYCols.push_back(SwSegDataBlock< complex<r_4> >(YSwapper, *swpos, mSegSz));
+    else
+      mYCols.push_back(SwSegDataBlock< complex<r_4> >(YSwapper, mSegSz));
+    mYColIdx.push_back(idx);
+    mYColsP.push_back(NULL);
+    for(sa_size_t kk=0; kk<mYCols.size(); kk++)
+      mYColsP[kk] = &(mYCols[kk]);
+    break;
+  }
+  case DoubleComplexField :
+  {
+    ser = mZCols.size();
+    FITSDataSwapper< complex<r_8> > ZSwapper(mSwF, idx+1);
+    if (swpos)    
+      mZCols.push_back(SwSegDataBlock< complex<r_8> >(ZSwapper, *swpos, mSegSz));
+    else
+      mZCols.push_back(SwSegDataBlock< complex<r_8> >(ZSwapper, mSegSz));
+    mZColIdx.push_back(idx);
+    mZColsP.push_back(NULL);
+    for(sa_size_t kk=0; kk<mZCols.size(); kk++)
+      mZColsP[kk] = &(mZCols[kk]);
+    break;
+  }
+  case StringField :
+  {
+    ser = mSCols.size();
+    FITSDataSwapper< string > SSwapper(mSwF, idx+1);
+    if (swpos)    
+      mSCols.push_back(SwSegDataBlock< string >(SSwapper, *swpos, mSegSz));
+    else 
+      mSCols.push_back(SwSegDataBlock< string >(SSwapper, mSegSz));
+    mSColIdx.push_back(idx);
+    mSColsP.push_back(NULL);
+    for(sa_size_t kk=0; kk<mSCols.size(); kk++)
+      mSColsP[kk] = &(mSCols[kk]);
+    break;
+  }
+  default:
+    throw ParmError("SwFitsDataTable::AddColumn() unknown field type ");
+    break;
+  }
+  colst col;
+  col.nom = cnom;
+  col.type = ft;
+  col.ser = ser;
+  mNames.push_back(col);
+  // On est oblige de calculer les min-max lors du remplissage
+  // On ne peut pas en effet 'relire' le swap pendant l'ecriture
+  mMin.push_back(9.E39);
+  mMax.push_back(-9.E39);
+  mMinMaxNEnt.push_back(0);
+
+  return NVar();
+}
+
+//! Adds a line (or row to the table) with r_8* input data.
+/*! 
+  The min/max values for each column is updated, in addition 
+  to the actions performed by the base class AddLine()
+*/
+sa_size_t SwFitsDataTable::AddLine(const r_8* data)
+{
+  // On est oblige de calculer les min-max lors du remplissage
+  // On ne peut pas en effet 'relire' le swap pendant l'ecriture
+  for(sa_size_t k=0; k<NVar(); k++) {
+    double x = data[k];
+    if (x < mMin[k])  mMin[k] = x;
+    if (x > mMax[k])  mMax[k] = x;
+    mMinMaxNEnt[k]++;
+  }
+  return BaseDataTable::AddLine(data);
+}
+
+//! Adds a line (or row to the table) with input data as an array of MuTyV
+/*! 
+  The min/max values for each column is updated, in addition 
+  to the actions performed by the base class AddLine()
+*/
+sa_size_t SwFitsDataTable::AddLine(const MuTyV * data)
+{
+  // On est oblige de calculer les min-max lors du remplissage
+  // On ne peut pas en effet 'relire' le swap pendant l'ecriture
+  for(sa_size_t k=0; k<NVar(); k++) {
+    double x = (double)data[k];
+    if (x < mMin[k])  mMin[k] = x;
+    if (x > mMax[k])  mMax[k] = x;
+    mMinMaxNEnt[k]++;
+  }
+  return BaseDataTable::AddLine(data);
+}
+
Index: /trunk/SophyaExt/FitsIOServer/swfitsdtable.h
===================================================================
--- /trunk/SophyaExt/FitsIOServer/swfitsdtable.h	(revision 2865)
+++ /trunk/SophyaExt/FitsIOServer/swfitsdtable.h	(revision 2865)
@@ -0,0 +1,70 @@
+// This may look like C code, but it is really -*- C++ -*-
+// Class DataTable  (Row-Column data table in memory) 
+//   R. Ansari -  Avril 2005
+//   (C)  LAL-IN2P3/CNRS    CEA-DAPNIA  
+
+#ifndef SWFITSDTABLE_H_SEEN
+#define SWFITSDTABLE_H_SEEN
+
+#include "basedtable.h"
+#include "swsegdb.h"
+#include "fitsswapper.h"
+
+
+namespace SOPHYA {
+
+//! An implementation of BaseDataTable with using FITS files as swap space.
+class SwFitsDataTable : public BaseDataTable {
+public:
+  SwFitsDataTable(sa_size_t segsz=512);
+  SwFitsDataTable(FitsInOutFile & os, sa_size_t segsz=512, bool fgcreate=true); 
+  SwFitsDataTable(SwFitsDataTable const& a); 
+
+  virtual ~SwFitsDataTable();
+
+  virtual sa_size_t AddColumn(FieldType ft, string const & cnom);
+
+  // Filling data structures (adding lines)
+  virtual sa_size_t AddLine(const r_8* data);
+  virtual sa_size_t AddLine(const MuTyV * data);
+
+  //! Equal (copy) operator - Copies the structure and shares the data \b a   
+  inline SwFitsDataTable& operator = (SwFitsDataTable const& a) 
+  { Clear(); Share(a); return *this ; } 
+
+  
+  //! Reset(Clear) the table content and structure
+  virtual void Clear();
+  /*! This method should be called in order to empty the swapout buffer, 
+     before saving object to PPF stream 
+  */
+  void SwapOutAll() const;
+
+  //  Pour la gestion I/O FITS
+  friend class FitsHandler<BaseDataTable> ; 
+
+protected:
+  void Share(SwFitsDataTable const & a);
+  // Methode pour utilisation par FitsHandler<BaseDataTable>
+  sa_size_t AddColRd(FieldType ft, string const & cnom, vector<int_8> const * swpos=NULL);
+
+
+  // Donnees (SegDataBlock) et leurs swapper
+  std::vector< SwSegDataBlock<int_4> > mICols; 
+  std::vector< SwSegDataBlock<int_8> > mLCols; 
+  std::vector< SwSegDataBlock<r_4> > mFCols;
+  std::vector< SwSegDataBlock<r_8> > mDCols; 
+  std::vector< SwSegDataBlock< complex<r_4> > > mYCols;
+  std::vector< SwSegDataBlock< complex<r_8> > > mZCols;
+  std::vector< SwSegDataBlock<string> > mSCols;    
+ 
+  // In/Out swap file doit etre cree avant l'appel au constructeur
+  // et rester valide (non detruit) tant que l'objet SwFitsDataTable existe
+  FitsInOutFile mSwF;   
+  bool mFgCreate; // true -> creation de table, false -> lecture
+}; 
+  
+} // namespace SOPHYA
+
+#endif
+
