| 1 | #include "swppfdtable.h" | 
|---|
| 2 | #include "pexceptions.h" | 
|---|
| 3 | #include "thsafeop.h" | 
|---|
| 4 |  | 
|---|
| 5 | namespace SOPHYA { | 
|---|
| 6 |  | 
|---|
| 7 | /*! | 
|---|
| 8 | \class SwPPFDataTable | 
|---|
| 9 | \ingroup HiStats | 
|---|
| 10 | This class can be used to organize data in table (row-column) form. | 
|---|
| 11 | Each column holds homogeneous data (same data type), while different | 
|---|
| 12 | columns can be used for different data types | 
|---|
| 13 | (integer, float, string ...). | 
|---|
| 14 | A PPF stream is used as swap space. Due to limitations in the current | 
|---|
| 15 | implementation of PPF streams, read operations (acces to table data) cannot | 
|---|
| 16 | be performed when a table is being filled. | 
|---|
| 17 |  | 
|---|
| 18 | \warning | 
|---|
| 19 | - When creating a table, the output PPF stream (POutPersist) must not be closed | 
|---|
| 20 | (destroyed) before the SwPPFDataTable object is written to the stream. | 
|---|
| 21 | - It is not possible to make a complete (deep) copy of a SwPPFDataTable | 
|---|
| 22 | Copy constructor and equal operator shares the data. | 
|---|
| 23 | - The destructor  DOES NOT save the table object itself to the swap | 
|---|
| 24 | stream. The << operator should be used on the output PPF stream being | 
|---|
| 25 | used as swap in order to save the table. | 
|---|
| 26 |  | 
|---|
| 27 | \sa SOPHYA::MuTyV | 
|---|
| 28 | \sa SOPHYA::DataTableRow | 
|---|
| 29 | \sa SOPHYA::DataTable | 
|---|
| 30 | \sa SOPHYA::SwSegDataBlock  SOPHYA::PPFDataSwapper | 
|---|
| 31 |  | 
|---|
| 32 | \code | 
|---|
| 33 | #include "swppfdtable.h" | 
|---|
| 34 | // ... | 
|---|
| 35 | { | 
|---|
| 36 | // ---- Creation of the table | 
|---|
| 37 | // Create the swap stream | 
|---|
| 38 | POutPersist so("myswtable.ppf"); | 
|---|
| 39 | SwPPFDataTable dt(so, 64); | 
|---|
| 40 | // define table columns | 
|---|
| 41 | dt.AddFloatColumn("X0_f"); | 
|---|
| 42 | dt.AddFloatColumn("X1_f"); | 
|---|
| 43 | dt.AddDoubleColumn("X0X0pX1X1_d"); | 
|---|
| 44 | // Fill the table | 
|---|
| 45 | r_8 x[5]; | 
|---|
| 46 | for(int i=0; i<63; i++) { | 
|---|
| 47 | x[0] = (i%9)-4.;  x[1] = (i/9)-3.;  x[2] = x[0]*x[0]+x[1]*x[1]; | 
|---|
| 48 | dt.AddRow(x); | 
|---|
| 49 | } | 
|---|
| 50 | // Printing table info | 
|---|
| 51 | cout << dt ; | 
|---|
| 52 | // Swap out all data and write the table structure to the PPF stream | 
|---|
| 53 | so << dt ; | 
|---|
| 54 | // .... | 
|---|
| 55 | } | 
|---|
| 56 | { | 
|---|
| 57 | // ---- Accessing information from a previously created table | 
|---|
| 58 | SwPPFDataTable dt; | 
|---|
| 59 | PInPersist si("myswtable.ppf"); | 
|---|
| 60 | si >> dt; | 
|---|
| 61 | // Printing table info | 
|---|
| 62 | cout << dt ; | 
|---|
| 63 | } | 
|---|
| 64 | \endcode | 
|---|
| 65 | */ | 
|---|
| 66 | //! Default constructor with optional specification of block (or segment) size | 
|---|
| 67 | SwPPFDataTable::SwPPFDataTable(sa_size_t segsz) | 
|---|
| 68 | : BaseDataTable(segsz), | 
|---|
| 69 | mSwOut(NULL), mSwIn(NULL) | 
|---|
| 70 | { | 
|---|
| 71 | } | 
|---|
| 72 | /*! Constructor with the specification of the output swap stream - | 
|---|
| 73 | and optional specification of block (or segment) size | 
|---|
| 74 | */ | 
|---|
| 75 | SwPPFDataTable::SwPPFDataTable(POutPersist & os, sa_size_t segsz) | 
|---|
| 76 | : BaseDataTable(segsz) , | 
|---|
| 77 | mSwOut(&os), mSwIn(NULL), | 
|---|
| 78 | mISwapper(os), mLSwapper(os), mFSwapper(os), mDSwapper(os), | 
|---|
| 79 | mYSwapper(os), mZSwapper(os), mSSwapper(os) | 
|---|
| 80 | { | 
|---|
| 81 | } | 
|---|
| 82 | //! Protected constructor for creation from a swap stream | 
|---|
| 83 | SwPPFDataTable::SwPPFDataTable(PInPersist & is, sa_size_t segsz) | 
|---|
| 84 | : BaseDataTable(segsz) , | 
|---|
| 85 | mSwOut(NULL), mSwIn(NULL) | 
|---|
| 86 | { | 
|---|
| 87 | PInPersist* pis = new PInPersist(is.FileName(), false); | 
|---|
| 88 | mSwIn = new St_InSwap; | 
|---|
| 89 | mSwIn->pis = pis;  mSwIn->refcnt = 1; | 
|---|
| 90 | mISwapper.SetInStream(*pis); | 
|---|
| 91 | mLSwapper.SetInStream(*pis); | 
|---|
| 92 | mFSwapper.SetInStream(*pis); | 
|---|
| 93 | mDSwapper.SetInStream(*pis); | 
|---|
| 94 | mYSwapper.SetInStream(*pis); | 
|---|
| 95 | mZSwapper.SetInStream(*pis); | 
|---|
| 96 | mSSwapper.SetInStream(*pis); | 
|---|
| 97 | } | 
|---|
| 98 |  | 
|---|
| 99 | //! copy constructor - shares the data (and copies the thread safety state) | 
|---|
| 100 |  | 
|---|
| 101 | SwPPFDataTable::SwPPFDataTable(SwPPFDataTable const & a) | 
|---|
| 102 | : BaseDataTable(a.SegmentSize()), | 
|---|
| 103 | mSwOut(NULL), mSwIn(NULL) | 
|---|
| 104 | { | 
|---|
| 105 | Share(a); | 
|---|
| 106 | } | 
|---|
| 107 | //! Destructor - Deletes / closes the input PPF swap stream | 
|---|
| 108 | SwPPFDataTable::~SwPPFDataTable() | 
|---|
| 109 | { | 
|---|
| 110 | if (mSwIn) { | 
|---|
| 111 | mSwIn->refcnt--; | 
|---|
| 112 | if (mSwIn->refcnt == 0) { | 
|---|
| 113 | delete mSwIn->pis; | 
|---|
| 114 | delete mSwIn; | 
|---|
| 115 | mSwIn = NULL; | 
|---|
| 116 | } | 
|---|
| 117 | } | 
|---|
| 118 | } | 
|---|
| 119 |  | 
|---|
| 120 | void SwPPFDataTable::Share(SwPPFDataTable const & a) | 
|---|
| 121 | { | 
|---|
| 122 | // Recopie (attention !) brutale des swappers  et les streams associes | 
|---|
| 123 | mISwapper = a.mISwapper; | 
|---|
| 124 | mLSwapper = a.mLSwapper; | 
|---|
| 125 | mFSwapper = a.mFSwapper; | 
|---|
| 126 | mDSwapper = a.mDSwapper; | 
|---|
| 127 | mYSwapper = a.mYSwapper; | 
|---|
| 128 | mZSwapper = a.mZSwapper; | 
|---|
| 129 | mSSwapper = a.mSSwapper; | 
|---|
| 130 |  | 
|---|
| 131 | mSwOut = a.mSwOut; | 
|---|
| 132 | mSwIn = a.mSwIn; | 
|---|
| 133 | if (mSwIn)  mSwIn->refcnt++;  // comptage de reference pour le stream input | 
|---|
| 134 |  | 
|---|
| 135 | // On recopie la taille de segment | 
|---|
| 136 | mSegSz = a.SegmentSize(); | 
|---|
| 137 | if (a.NVar() == 0)  return;  // Table sans colonne | 
|---|
| 138 |  | 
|---|
| 139 | // On copie la structure de table | 
|---|
| 140 | CopyStructure(a); | 
|---|
| 141 | if (a.IsThreadSafe())  SetThreadSafe(true); | 
|---|
| 142 | else SetThreadSafe(false); | 
|---|
| 143 |  | 
|---|
| 144 | // | 
|---|
| 145 | // Update nombre d'entree, ... | 
|---|
| 146 | mNEnt = a.mNEnt; | 
|---|
| 147 | mNSeg = a.mNSeg; | 
|---|
| 148 | if (a.mInfo)  mInfo = new DVList(*(a.mInfo)); | 
|---|
| 149 |  | 
|---|
| 150 | // mis a jour des tableax min-max | 
|---|
| 151 | mMin = a.mMin; | 
|---|
| 152 | mMax = a.mMax; | 
|---|
| 153 | mMinMaxNEnt = a.mMinMaxNEnt; | 
|---|
| 154 |  | 
|---|
| 155 | // Et on partage les donnees des colonnes | 
|---|
| 156 | for (size_t kk=0; kk<mNames.size(); kk++) { | 
|---|
| 157 | sa_size_t sk = mNames[kk].ser; | 
|---|
| 158 | sa_size_t ska = a.mNames[kk].ser; | 
|---|
| 159 | switch (mNames[kk].type) { | 
|---|
| 160 | case IntegerField : | 
|---|
| 161 | mICols[sk] = a.mICols[ska]; | 
|---|
| 162 | break; | 
|---|
| 163 | case LongField : | 
|---|
| 164 | mLCols[sk] = a.mLCols[ska]; | 
|---|
| 165 | break; | 
|---|
| 166 | case FloatField : | 
|---|
| 167 | mFCols[sk] = a.mFCols[ska]; | 
|---|
| 168 | break; | 
|---|
| 169 | case DoubleField : | 
|---|
| 170 | case DateTimeField : | 
|---|
| 171 | mDCols[sk] = a.mDCols[ska]; | 
|---|
| 172 | break; | 
|---|
| 173 | case ComplexField : | 
|---|
| 174 | mYCols[sk] = a.mYCols[ska]; | 
|---|
| 175 | break; | 
|---|
| 176 | case DoubleComplexField : | 
|---|
| 177 | mZCols[sk] = a.mZCols[ska]; | 
|---|
| 178 | break; | 
|---|
| 179 | case StringField : | 
|---|
| 180 | mSCols[sk] = a.mSCols[ska]; | 
|---|
| 181 | break; | 
|---|
| 182 | default: | 
|---|
| 183 | throw ForbiddenError("SwPPFDataTable::Share() : unknown column type "); | 
|---|
| 184 | break; | 
|---|
| 185 | } | 
|---|
| 186 | } | 
|---|
| 187 | } | 
|---|
| 188 | void SwPPFDataTable::SwapOutAll() const | 
|---|
| 189 | { | 
|---|
| 190 | // Et on vide les buffers de swap | 
|---|
| 191 | for (size_t kk=0; kk<mNames.size(); kk++) { | 
|---|
| 192 | sa_size_t sk = mNames[kk].ser; | 
|---|
| 193 | switch (mNames[kk].type) { | 
|---|
| 194 | case IntegerField : | 
|---|
| 195 | mICols[sk].SwapOutBuffer(); | 
|---|
| 196 | break; | 
|---|
| 197 | case LongField : | 
|---|
| 198 | mLCols[sk].SwapOutBuffer(); | 
|---|
| 199 | break; | 
|---|
| 200 | case FloatField : | 
|---|
| 201 | mFCols[sk].SwapOutBuffer(); | 
|---|
| 202 | break; | 
|---|
| 203 | case DoubleField : | 
|---|
| 204 | case DateTimeField : | 
|---|
| 205 | mDCols[sk].SwapOutBuffer(); | 
|---|
| 206 | break; | 
|---|
| 207 | case ComplexField : | 
|---|
| 208 | mYCols[sk].SwapOutBuffer(); | 
|---|
| 209 | break; | 
|---|
| 210 | case DoubleComplexField : | 
|---|
| 211 | mZCols[sk].SwapOutBuffer(); | 
|---|
| 212 | break; | 
|---|
| 213 | case StringField : | 
|---|
| 214 | mSCols[sk].SwapOutBuffer(); | 
|---|
| 215 | break; | 
|---|
| 216 | default: | 
|---|
| 217 | throw ForbiddenError("SwPPFDataTable::Share() : unknown column type "); | 
|---|
| 218 | break; | 
|---|
| 219 | } | 
|---|
| 220 | } | 
|---|
| 221 | } | 
|---|
| 222 |  | 
|---|
| 223 | void SwPPFDataTable::Clear() | 
|---|
| 224 | { | 
|---|
| 225 | if ( (NVar() == 0) && (NEntry() == 0)) return; | 
|---|
| 226 | mNEnt = 0; | 
|---|
| 227 | mNSeg = 0; | 
|---|
| 228 | if (mVarD) delete[] mVarD; | 
|---|
| 229 | mVarD = NULL; | 
|---|
| 230 | if (mVarMTV) delete[] mVarMTV; | 
|---|
| 231 | mVarMTV = NULL; | 
|---|
| 232 | mNames.clear(); | 
|---|
| 233 | if (mInfo) delete mInfo; | 
|---|
| 234 | mInfo = NULL; | 
|---|
| 235 | if (mThS) delete mThS; | 
|---|
| 236 | mThS = NULL; | 
|---|
| 237 | mMin.clear(); | 
|---|
| 238 | mMax.clear(); | 
|---|
| 239 | mMinMaxNEnt.clear(); | 
|---|
| 240 | mIColsP.clear(); | 
|---|
| 241 | mLColsP.clear(); | 
|---|
| 242 | mFColsP.clear(); | 
|---|
| 243 | mDColsP.clear(); | 
|---|
| 244 | mYColsP.clear(); | 
|---|
| 245 | mZColsP.clear(); | 
|---|
| 246 | mSColsP.clear(); | 
|---|
| 247 |  | 
|---|
| 248 | mIColIdx.clear(); | 
|---|
| 249 | mLColIdx.clear(); | 
|---|
| 250 | mFColIdx.clear(); | 
|---|
| 251 | mDColIdx.clear(); | 
|---|
| 252 | mYColIdx.clear(); | 
|---|
| 253 | mZColIdx.clear(); | 
|---|
| 254 | mSColIdx.clear(); | 
|---|
| 255 |  | 
|---|
| 256 | mICols.clear(); | 
|---|
| 257 | mLCols.clear(); | 
|---|
| 258 | mFCols.clear(); | 
|---|
| 259 | mDCols.clear(); | 
|---|
| 260 | mYCols.clear(); | 
|---|
| 261 | mZCols.clear(); | 
|---|
| 262 | mSCols.clear(); | 
|---|
| 263 | } | 
|---|
| 264 |  | 
|---|
| 265 |  | 
|---|
| 266 | /*! | 
|---|
| 267 | Implements the action defined in the BaseDataTable interface. | 
|---|
| 268 | In the current implementation, throws an exception (ParmError) | 
|---|
| 269 | if the table contains some data already. | 
|---|
| 270 | */ | 
|---|
| 271 | sa_size_t SwPPFDataTable::AddColumn(FieldType ft, string const & cnom) | 
|---|
| 272 | { | 
|---|
| 273 | if (NEntry() > 0) | 
|---|
| 274 | throw ParmError("SwPPFDataTable::AddColumn() Table contains already data "); | 
|---|
| 275 | CheckColName(cnom); | 
|---|
| 276 | sa_size_t ser; | 
|---|
| 277 | sa_size_t idx = NVar(); | 
|---|
| 278 | switch (ft) { | 
|---|
| 279 | case IntegerField : | 
|---|
| 280 | ser = mICols.size(); | 
|---|
| 281 | mICols.push_back(SwSegDataBlock<int_4>(mISwapper, mSegSz)); | 
|---|
| 282 | mIColIdx.push_back(idx); | 
|---|
| 283 | mIColsP.push_back(NULL); | 
|---|
| 284 | for(sa_size_t kk=0; kk<mICols.size(); kk++) | 
|---|
| 285 | mIColsP[kk] = &(mICols[kk]); | 
|---|
| 286 | break; | 
|---|
| 287 | case LongField : | 
|---|
| 288 | ser = mLCols.size(); | 
|---|
| 289 | mLCols.push_back(SwSegDataBlock<int_8>(mLSwapper, mSegSz)); | 
|---|
| 290 | mLColIdx.push_back(idx); | 
|---|
| 291 | mLColsP.push_back(NULL); | 
|---|
| 292 | for(sa_size_t kk=0; kk<mLCols.size(); kk++) | 
|---|
| 293 | mLColsP[kk] = &(mLCols[kk]); | 
|---|
| 294 | break; | 
|---|
| 295 | case FloatField : | 
|---|
| 296 | ser = mFCols.size(); | 
|---|
| 297 | mFCols.push_back(SwSegDataBlock<r_4>(mFSwapper, mSegSz)); | 
|---|
| 298 | mFColIdx.push_back(idx); | 
|---|
| 299 | mFColsP.push_back(NULL); | 
|---|
| 300 | for(sa_size_t kk=0; kk<mFCols.size(); kk++) | 
|---|
| 301 | mFColsP[kk] = &(mFCols[kk]); | 
|---|
| 302 | break; | 
|---|
| 303 | case DoubleField : | 
|---|
| 304 | case DateTimeField : | 
|---|
| 305 | ser = mDCols.size(); | 
|---|
| 306 | mDCols.push_back(SwSegDataBlock<r_8>( mDSwapper,mSegSz)); | 
|---|
| 307 | mDColIdx.push_back(idx); | 
|---|
| 308 | mDColsP.push_back(NULL); | 
|---|
| 309 | for(sa_size_t kk=0; kk<mDCols.size(); kk++) | 
|---|
| 310 | mDColsP[kk] = &(mDCols[kk]); | 
|---|
| 311 | break; | 
|---|
| 312 | case ComplexField : | 
|---|
| 313 | ser = mYCols.size(); | 
|---|
| 314 | mYCols.push_back(SwSegDataBlock< complex<r_4> >(mYSwapper, mSegSz)); | 
|---|
| 315 | mYColIdx.push_back(idx); | 
|---|
| 316 | mYColsP.push_back(NULL); | 
|---|
| 317 | for(sa_size_t kk=0; kk<mYCols.size(); kk++) | 
|---|
| 318 | mYColsP[kk] = &(mYCols[kk]); | 
|---|
| 319 | break; | 
|---|
| 320 | case DoubleComplexField : | 
|---|
| 321 | ser = mZCols.size(); | 
|---|
| 322 | mZCols.push_back(SwSegDataBlock< complex<r_8> >(mZSwapper, mSegSz)); | 
|---|
| 323 | mZColIdx.push_back(idx); | 
|---|
| 324 | mZColsP.push_back(NULL); | 
|---|
| 325 | for(sa_size_t kk=0; kk<mZCols.size(); kk++) | 
|---|
| 326 | mZColsP[kk] = &(mZCols[kk]); | 
|---|
| 327 | break; | 
|---|
| 328 | case StringField : | 
|---|
| 329 | ser = mSCols.size(); | 
|---|
| 330 | mSCols.push_back(SwSegDataBlock<string>(mSSwapper, mSegSz)); | 
|---|
| 331 | mSColIdx.push_back(idx); | 
|---|
| 332 | mSColsP.push_back(NULL); | 
|---|
| 333 | for(sa_size_t kk=0; kk<mSCols.size(); kk++) | 
|---|
| 334 | mSColsP[kk] = &(mSCols[kk]); | 
|---|
| 335 | break; | 
|---|
| 336 | default: | 
|---|
| 337 | throw ParmError("SwPPFDataTable::AddColumn() unknown field type "); | 
|---|
| 338 | break; | 
|---|
| 339 | } | 
|---|
| 340 | colst col; | 
|---|
| 341 | col.nom = cnom; | 
|---|
| 342 | col.type = ft; | 
|---|
| 343 | col.ser = ser; | 
|---|
| 344 | mNames.push_back(col); | 
|---|
| 345 | // On est oblige de calculer les min-max lors du remplissage | 
|---|
| 346 | // On ne peut pas en effet 'relire' le swap pendant l'ecriture | 
|---|
| 347 | mMin.push_back(9.E39); | 
|---|
| 348 | mMax.push_back(-9.E39); | 
|---|
| 349 | mMinMaxNEnt.push_back(0); | 
|---|
| 350 |  | 
|---|
| 351 | return NVar(); | 
|---|
| 352 | } | 
|---|
| 353 |  | 
|---|
| 354 | //! Adds a row (or line to the table) with r_8* input data. | 
|---|
| 355 | /*! | 
|---|
| 356 | The min/max values for each column is updated, in addition | 
|---|
| 357 | to the actions performed by the base class AddRow() | 
|---|
| 358 | */ | 
|---|
| 359 | sa_size_t SwPPFDataTable::AddRow(const r_8* data) | 
|---|
| 360 | { | 
|---|
| 361 | // On est oblige de calculer les min-max lors du remplissage | 
|---|
| 362 | // On ne peut pas en effet 'relire' le swap pendant l'ecriture | 
|---|
| 363 | if (mThS) mThS->lock();   // tread-safety | 
|---|
| 364 | for(sa_size_t k=0; k<NVar(); k++) { | 
|---|
| 365 | double x = data[k]; | 
|---|
| 366 | if (x < mMin[k])  mMin[k] = x; | 
|---|
| 367 | if (x > mMax[k])  mMax[k] = x; | 
|---|
| 368 | mMinMaxNEnt[k]++; | 
|---|
| 369 | } | 
|---|
| 370 | if (mThS) mThS->unlock(); // tread-safety | 
|---|
| 371 | return BaseDataTable::AddRow(data); | 
|---|
| 372 | } | 
|---|
| 373 |  | 
|---|
| 374 | //! Adds a row (or line to the table) with input data as an array of MuTyV | 
|---|
| 375 | /*! | 
|---|
| 376 | The min/max values for each column is updated, in addition | 
|---|
| 377 | to the actions performed by the base class AddRow() | 
|---|
| 378 | */ | 
|---|
| 379 | sa_size_t SwPPFDataTable::AddRow(const MuTyV * data) | 
|---|
| 380 | { | 
|---|
| 381 | // On est oblige de calculer les min-max lors du remplissage | 
|---|
| 382 | // On ne peut pas en effet 'relire' le swap pendant l'ecriture | 
|---|
| 383 | if (mThS) mThS->lock();   // tread-safety | 
|---|
| 384 | for(sa_size_t k=0; k<NVar(); k++) { | 
|---|
| 385 | double x = (double)data[k]; | 
|---|
| 386 | if (x < mMin[k])  mMin[k] = x; | 
|---|
| 387 | if (x > mMax[k])  mMax[k] = x; | 
|---|
| 388 | mMinMaxNEnt[k]++; | 
|---|
| 389 | } | 
|---|
| 390 | if (mThS) mThS->unlock(); // tread-safety | 
|---|
| 391 | return BaseDataTable::AddRow(data); | 
|---|
| 392 | } | 
|---|
| 393 |  | 
|---|
| 394 |  | 
|---|
| 395 | //! Adds a row (or line) to the table with input data as DataTableRow object | 
|---|
| 396 | /*! | 
|---|
| 397 | The min/max values for each column is updated, in addition | 
|---|
| 398 | to the actions performed by the base class AddRow() | 
|---|
| 399 | */ | 
|---|
| 400 | sa_size_t SwPPFDataTable::AddRow(DataTableRow const& data) | 
|---|
| 401 | { | 
|---|
| 402 | if ( data.Size() != NCols() ) | 
|---|
| 403 | throw SzMismatchError(" SwPPFDataTable::AddRow() - data.Size() != NCols() "); | 
|---|
| 404 | return AddRow(data.MTVPtr()); | 
|---|
| 405 | } | 
|---|
| 406 |  | 
|---|
| 407 | } // FIN namespace SOPHYA | 
|---|