Index: trunk/SophyaLib/HiStats/basedtable.cc
===================================================================
--- trunk/SophyaLib/HiStats/basedtable.cc	(revision 3181)
+++ trunk/SophyaLib/HiStats/basedtable.cc	(revision 3392)
@@ -1,9 +1,11 @@
 #include "basedtable.h"
 #include <ctype.h>
-#include "sopnamsp.h"
 #include "pexceptions.h"
+#include "thsafeop.h"
+
+namespace SOPHYA {
 
 /*!
-   \class SOPHYA::DataTableRow
+   \class DataTableRow
    \ingroup HiStats
    This class is intented to be used with datatable classes
@@ -58,8 +60,11 @@
 
 /*!
-   \class SOPHYA::BaseDataTable
+   \class BaseDataTable
    \ingroup HiStats
    Base class for data tables. Each line represent a record
    and the column contains a given data type.
+   \warning 
+   Thread safe fill operation can be activated using the method SetThreadSafe()
+   Default mode is NON thread-safe fill.   
 */
 
@@ -147,4 +152,5 @@
   mVarMTV = NULL;
   mInfo = NULL;
+  mThS = NULL;
 }
 
@@ -154,5 +160,61 @@
   if (mVarMTV) delete[] mVarMTV;
   if (mInfo) delete mInfo;
-}
+  if (mThS) delete mThS;
+}
+
+/*!
+  \brief Activate or deactivate thread-safe \b AddRow() operations
+
+  If fg==true, create an ThSafeOp object in order to insure atomic AddRow()
+  and GetRow()/GetColumn() operations. if fg==false, the ThSafeOp object (mThS) 
+  of the target DataTable is destroyed.
+
+  When activated, the following operations are thread-safe : 
+
+  - AddRow(const r_8* data)
+  - AddRow(const MuTyV* data)
+  - AddRow(DataTableRow const& data)
+  - GetRow(sa_size_t n, DataTableRow& row)
+  - GetRow(sa_size_t n, MuTyV* mtvp)
+  - GetColumnD(sa_size_t k)
+
+  \warning The default AddRow() operation mode for DataTables is NOT thread-safe. 
+  Please note also that the thread-safety state is NOt saved to PPF (or FITS) streams.
+*/
+void BaseDataTable::SetThreadSafe(bool fg) 
+{
+  if (fg) {
+    if (mThS) return;
+    else mThS = new ThSafeOp();
+  }
+  else {
+    if (mThS) delete mThS;
+    mThS = NULL;
+  }
+}
+
+
+/*! \cond
+  \class DT_TSOP_SYNC 
+  \ingroup HiStats 
+  Classe utilitaire pour faciliter la gestion de lock pour 
+  operations thread-safe BaseDataTable
+*/
+class DT_TSOP_SYNC {
+ public:
+  explicit DT_TSOP_SYNC(ThSafeOp* ths) 
+  { 
+    ths_ = ths; 
+    if (ths_) ths_->lock(); 
+  }
+  ~DT_TSOP_SYNC() 
+  {
+    if (ths_) ths_->unlock(); 
+  }
+  inline ThSafeOp* NOp() { return ths_; }
+ protected:
+  ThSafeOp* ths_;
+};
+/*! \endcond */
 
 sa_size_t BaseDataTable::CopyStructure(BaseDataTable const & a)
@@ -273,4 +335,6 @@
 sa_size_t BaseDataTable::AddRow(const r_8* data)
 {
+  DT_TSOP_SYNC dttss(mThS); dttss.NOp();  // Thread-safe operation 
+
   if (NVar() == 0) 
     throw ParmError("BaseDataTable::AddRow(const r_8*) Table has no column !");
@@ -309,4 +373,6 @@
 sa_size_t BaseDataTable::AddRow(const MuTyV* data)
 {
+  DT_TSOP_SYNC dttss(mThS); dttss.NOp();  // Thread-safe operation 
+
   if (NVar() == 0) 
     throw ParmError("BaseDataTable::AddRow(const MuTyV*) Table has no column !");
@@ -379,5 +445,4 @@
   Return a reference to the input \b row object. 
   Generate an exception if the input \b row object has the wrong size.
-  This method is slower(less efficient) than the GetRow(n) method.
 */
 DataTableRow& BaseDataTable::GetRow(sa_size_t n, DataTableRow& row) const
@@ -385,37 +450,42 @@
   if ( row.Size() != NCols() )
     throw SzMismatchError(" BaseDataTable::GetRow(n, row) - row.Size() != NCols() ");
-  MuTyV* rmtv = GetRow(n);
-  for(sa_size_t k=0; k<NCols(); k++)
-    row[k] = rmtv[k];
+  GetRow(n, row.MTVPtr());
   return row;
 }
 
-MuTyV* BaseDataTable::GetRow(sa_size_t n) const 
-{
+/*!
+  For thread-safe operation, specify a valid \b mtvp  pointer (!= NULL)  
+*/
+MuTyV* BaseDataTable::GetRow(sa_size_t n, MuTyV* mtvp) const 
+{
+  DT_TSOP_SYNC dttss(mThS); dttss.NOp();  // Thread-safe operation 
+
   if ((n < 0) || (n >= NEntry())) 
     throw RangeCheckError("BaseDataTable::GetRow() out of range line index n");
-  if (mVarMTV == NULL) mVarMTV = new MuTyV[NVar()];
-
+  if (mtvp == NULL) {
+    if (mVarMTV == NULL) mVarMTV = new MuTyV[NVar()];
+    mtvp = mVarMTV;
+  }
   sa_size_t bid = n/mSegSz;
   sa_size_t off = n%mSegSz;
   for(sa_size_t k=0; k<mIColsP.size(); k++) 
-    mVarMTV[mIColIdx[k]] = mIColsP[k]->GetCstSegment(bid)[off];
+    mtvp[mIColIdx[k]] = mIColsP[k]->GetCstSegment(bid)[off];
   for(sa_size_t k=0; k<mLColsP.size(); k++) 
-    mVarMTV[mLColIdx[k]] = mLColsP[k]->GetCstSegment(bid)[off];
+    mtvp[mLColIdx[k]] = mLColsP[k]->GetCstSegment(bid)[off];
   for(sa_size_t k=0; k<mFColsP.size(); k++) 
-    mVarMTV[mFColIdx[k]] = mFColsP[k]->GetCstSegment(bid)[off];
+    mtvp[mFColIdx[k]] = mFColsP[k]->GetCstSegment(bid)[off];
   for(sa_size_t k=0; k<mDColsP.size(); k++) {
     if (GetColumType(mDColIdx[k]) == DateTimeField) 
-      mVarMTV[mDColIdx[k]] = TimeStamp(mDColsP[k]->GetCstSegment(bid)[off]);
-    else mVarMTV[mDColIdx[k]] = mDColsP[k]->GetCstSegment(bid)[off];
+      mtvp[mDColIdx[k]] = TimeStamp(mDColsP[k]->GetCstSegment(bid)[off]);
+    else mtvp[mDColIdx[k]] = mDColsP[k]->GetCstSegment(bid)[off];
   }
   for(sa_size_t k=0; k<mYColsP.size(); k++) 
-    mVarMTV[mYColIdx[k]] = mYColsP[k]->GetCstSegment(bid)[off];
+    mtvp[mYColIdx[k]] = mYColsP[k]->GetCstSegment(bid)[off];
   for(sa_size_t k=0; k<mZColsP.size(); k++) 
-    mVarMTV[mZColIdx[k]] = mZColsP[k]->GetCstSegment(bid)[off];
+    mtvp[mZColIdx[k]] = mZColsP[k]->GetCstSegment(bid)[off];
   for(sa_size_t k=0; k<mSColsP.size(); k++) 
-    mVarMTV[mSColIdx[k]] = mSColsP[k]->GetCstSegment(bid)[off];
-
-  return mVarMTV;
+    mtvp[mSColIdx[k]] = mSColsP[k]->GetCstSegment(bid)[off];
+
+  return mtvp;
 }
 
@@ -424,4 +494,6 @@
 TVector<r_8> BaseDataTable::GetColumnD(sa_size_t k) const
 {
+  DT_TSOP_SYNC dttss(mThS); dttss.NOp();  // Thread-safe operation 
+
   if ((k < 0) || (k >= NVar())) 
     throw RangeCheckError("BaseDataTable::GetColumnD() out of range column index k");
@@ -968,2 +1040,4 @@
 }
 
+} // FIN namespace SOPHYA 
+
