source: Sophya/trunk/SophyaLib/HiStats/basedtable.cc@ 3831

Last change on this file since 3831 was 3712, checked in by ansari, 16 years ago

Correction bug trouve par cmv, ajout destructeur avec delete[] pour DataTableRow - Reza 10/12/2009

File size: 30.1 KB
RevLine 
[2688]1#include "basedtable.h"
2#include <ctype.h>
3#include "pexceptions.h"
[3392]4#include "thsafeop.h"
[2688]5
[3392]6namespace SOPHYA {
7
[2688]8/*!
[3392]9 \class DataTableRow
[2849]10 \ingroup HiStats
11 This class is intented to be used with datatable classes
12 (inheriting from BaseDataTable) for representing a row (line)
13 of the table.
14*/
[2850]15DataTableRow::DataTableRow( vector<string> const& colnames )
[2849]16{
17 if (colnames.size() < 1)
18 throw ParmError("DataTableRow::DataTableRow(vector<string>& cn) cn.size()==0 ");
19 size_ = colnames.size();
20 mtv_ = new MuTyV[ size_ ];
21 for(sa_size_t k=0; k<size_; k++)
22 nm2idx_[colnames[k]] = k;
23}
24
25DataTableRow::DataTableRow(DataTableRow const & a )
26{
27 size_ = a.size_;
28 mtv_ = new MuTyV[ size_ ];
29 nm2idx_ = a.nm2idx_;
30}
31
[3712]32DataTableRow::~DataTableRow()
33{
34 delete[] mtv_;
35}
36
[2849]37MuTyV DataTableRow::get(string const& colname) const
38{
39 map<string, sa_size_t>::const_iterator it = nm2idx_.find(colname);
40 if (it == nm2idx_.end()) {
41 string msg = "DataTableRow::get( " ;
42 msg += colname; msg += " ) Not found column name";
43 throw NotFoundExc(msg);
44 }
45 return mtv_[(*it).second];
46}
47
48MuTyV& DataTableRow::get(string const& colname)
49{
50 map<string, sa_size_t>::const_iterator it = nm2idx_.find(colname);
51 if (it == nm2idx_.end()) {
52 string msg = "DataTableRow::get( " ;
53 msg += colname; msg += " ) const - Not found column name";
54 throw NotFoundExc(msg);
55 }
56 return mtv_[(*it).second];
57}
58
59ostream& DataTableRow::Print(ostream& os) const
60{
61 for(sa_size_t k=0; k<size_; k++)
62 os << (string)mtv_[k] << " ";
63 return os;
64}
65
66/*!
[3392]67 \class BaseDataTable
[2688]68 \ingroup HiStats
69 Base class for data tables. Each line represent a record
70 and the column contains a given data type.
[3392]71 \warning
72 Thread safe fill operation can be activated using the method SetThreadSafe()
73 Default mode is NON thread-safe fill.
[2688]74*/
75
[2831]76/*!
77 if fgl == true , return LongForm string
78 \verbatim
79 ----------------------------------------------
80 FieldType ShortForm LongForm
81 ----------------------------------------------
82 IntegerField I Integer
83 LongField L Long Integer
84 FloatField F Float
85 DoubleField D Double
86 ComplexField Zx4 Complex
87 DoubleComplexField Zx8 DoubleComplex
88 StringField S String
89 DateTimeField T DateTime
90 ----------------------------------------------
91 \endverbatim
92*/
[2688]93string BaseDataTable::ColTypeToString(FieldType ft, bool fgl)
94{
95 string rs;
96 switch (ft) {
97 case IntegerField :
98 if (fgl) rs = "Integer";
99 else rs = "I";
100 break;
101 case LongField :
102 if (fgl) rs = "Long Integer";
103 else rs = "L";
104 break;
105 case FloatField :
106 if (fgl) rs = "Float";
107 else rs = "F";
108 break;
109 case DoubleField :
110 if (fgl) rs = "Double";
111 else rs = "D";
112 break;
113 case ComplexField :
114 if (fgl) rs = "Complex";
115 else rs = "Zx4";
116 break;
117 case DoubleComplexField :
118 if (fgl) rs = "DoubleComplex";
119 else rs = "Zx8";
120 break;
121 case StringField :
122 if (fgl) rs = "String";
123 else rs = "S";
124 break;
[2831]125 case DateTimeField :
[2827]126 if (fgl) rs = "DateTime";
127 else rs = "T";
[2688]128 break;
129 default:
130 rs = "??";
131 break;
132 }
133 return rs;
134}
135
[2831]136BaseDataTable::FieldType BaseDataTable::StringToColType(string const & sctyp)
137{
138 if ( (sctyp == "Integer") || (sctyp == "I") ) return IntegerField;
139 else if ( (sctyp == "Long Integer") || (sctyp == "L") ) return LongField;
140 else if ( (sctyp == "Float") || (sctyp == "F") ) return FloatField;
141 else if ( (sctyp == "Double") || (sctyp == "D") ) return DoubleField;
142 else if ( (sctyp == "Complex") || (sctyp == "Zx4") ) return ComplexField;
143 else if ( (sctyp == "DoubleComplex") || (sctyp == "Zx8") || (sctyp == "Z") )
144 return DoubleComplexField;
145 else if ( (sctyp == "String") || (sctyp == "S") ) return StringField;
146 else if ( (sctyp == "DateTime") || (sctyp == "T") ) return DateTimeField;
147 else return DoubleField;
148}
149
[2688]150/* Constructeur */
151BaseDataTable::BaseDataTable(sa_size_t segsz)
152{
153 mNEnt = 0;
154 mSegSz = (segsz > 0) ? segsz : 16;
155 mNSeg = 0;
156 mVarD = NULL;
157 mVarMTV = NULL;
158 mInfo = NULL;
[3392]159 mThS = NULL;
[2688]160}
161
162BaseDataTable::~BaseDataTable()
163{
164 if (mVarD) delete[] mVarD;
165 if (mVarMTV) delete[] mVarMTV;
166 if (mInfo) delete mInfo;
[3392]167 if (mThS) delete mThS;
[2688]168}
169
[3392]170/*!
171 \brief Activate or deactivate thread-safe \b AddRow() operations
172
173 If fg==true, create an ThSafeOp object in order to insure atomic AddRow()
174 and GetRow()/GetColumn() operations. if fg==false, the ThSafeOp object (mThS)
175 of the target DataTable is destroyed.
176
177 When activated, the following operations are thread-safe :
178
179 - AddRow(const r_8* data)
180 - AddRow(const MuTyV* data)
181 - AddRow(DataTableRow const& data)
182 - GetRow(sa_size_t n, DataTableRow& row)
183 - GetRow(sa_size_t n, MuTyV* mtvp)
184 - GetColumnD(sa_size_t k)
185
186 \warning The default AddRow() operation mode for DataTables is NOT thread-safe.
187 Please note also that the thread-safety state is NOt saved to PPF (or FITS) streams.
188*/
189void BaseDataTable::SetThreadSafe(bool fg)
190{
191 if (fg) {
192 if (mThS) return;
193 else mThS = new ThSafeOp();
194 }
195 else {
196 if (mThS) delete mThS;
197 mThS = NULL;
198 }
199}
200
201
202/*! \cond
203 \class DT_TSOP_SYNC
204 \ingroup HiStats
205 Classe utilitaire pour faciliter la gestion de lock pour
206 operations thread-safe BaseDataTable
207*/
208class DT_TSOP_SYNC {
209 public:
210 explicit DT_TSOP_SYNC(ThSafeOp* ths)
211 {
212 ths_ = ths;
213 if (ths_) ths_->lock();
214 }
215 ~DT_TSOP_SYNC()
216 {
217 if (ths_) ths_->unlock();
218 }
219 inline ThSafeOp* NOp() { return ths_; }
220 protected:
221 ThSafeOp* ths_;
222};
223/*! \endcond */
224
[2688]225sa_size_t BaseDataTable::CopyStructure(BaseDataTable const & a)
226{
227 if (NVar() > 0)
228 throw ParmError("BaseDataTable::CopyStructure() Table already has columns");
229 if (a.NVar() == 0) {
230 cout << "BaseDataTable::CopyStructure(a)/Warning Table a is not initialized" << endl;
231 return 0;
232 }
233 for (size_t kk=0; kk<a.mNames.size(); kk++)
234 AddColumn(a.mNames[kk].type, a.mNames[kk].nom);
235 return NVar();
236}
237
238//! return true is same structure
239bool BaseDataTable::CompareStructure(BaseDataTable const & a)
240{
241 if (NVar() != a.NVar()) return false;
242 for (size_t kk=0; kk<mNames.size(); kk++)
243 if ( (mNames[kk].type != a.mNames[kk].type) ||
244 (mNames[kk].nom != a.mNames[kk].nom) ) return false;
245 return true;
246}
247
[2962]248//! Check the validity of column name \b cnom - throw exception.
[2688]249bool BaseDataTable::CheckColName(string const & cnom)
250{
251 size_t l,k;
252 l = cnom.length();
253 if (l < 1)
254 throw ParmError("BaseDataTable::CheckColName() zero length column name");
255 if (!isalpha(cnom[0]))
256 throw ParmError("BaseDataTable::CheckColName() first character not alphabetical");
257 for(k=1; k<l; k++)
258 if ((!isalnum(cnom[k])) && (cnom[k] != '_'))
259 throw ParmError("BaseDataTable::CheckColName() Non alphanumeric char in name");
260 for(k=0; k<mNames.size(); k++)
261 if (cnom == mNames[k].nom)
262 throw ParmError("BaseDataTable::CheckColName() already existing name");
263 return true;
264}
265
[2962]266/*!
267 \brief Check the validity of column name \b cnom and correct it if necessary
268 return true if \b cnom has been changed
269*/
270bool BaseDataTable::CheckCorrectColName(string& cnom)
271{
272 size_t l,k;
273 l = cnom.length();
274 string ssn;
275 MuTyV mvv = (NCols()+1);
276 mvv.Convert(ssn);
277 bool fgrc = false;
278 if (l < 1) { cnom = "C"+ssn; fgrc = true; }
279 if (!isalpha(cnom[0])) { cnom = "C"+cnom; fgrc = true; }
280 for(k=1; k<l; k++)
281 if ((!isalnum(cnom[k])) && (cnom[k] != '_')) {
282 cnom[k] = '_'; fgrc = true;
283 }
284 bool fgdouble = true;
285 while (fgdouble) {
286 fgdouble = false;
287 for(k=0; k<mNames.size(); k++)
288 if (cnom == mNames[k].nom) {
289 fgdouble = true; break;
290 }
291 if (fgdouble) { cnom = cnom+ssn; fgrc = true; }
292 }
293 return fgrc;
294}
295
[2849]296// Retourne une structure
297/*!
298 The returned BaseDataTable object can be used for subsequent call to
299 AddRow() or GetRow() methods.
300 Generate an exception if called for a table with no columns
301*/
302DataTableRow BaseDataTable::EmptyRow()
303{
[2850]304 if (NCols() == 0)
[2849]305 throw ParmError("BaseDataTable::EmptyRow() Table has no column !");
306 vector<string> nms;
307 for(sa_size_t k=0; k<NVar(); k++) nms.push_back(mNames[k].nom);
[2850]308 DataTableRow row(nms);
309 return row;
[2849]310}
311
[2688]312//
313// A quel index correspond mon nom ?
314//
315sa_size_t BaseDataTable::IndexNom(char const* nom) const
316{
[2699]317 for(sa_size_t k=0; k<NVar(); k++)
318 if ( mNames[k].nom == nom ) return k;
319 return -1;
320 // Reza:Avril 2005 : PINtuple se base sur le renvoi de -1 et pas d'une exception
321 // throw NotFoundExc("BaseDataTable::IndexNom() : column name not found ");
[2688]322}
323
324string BaseDataTable::NomIndex(sa_size_t k) const
325{
326 if ((k < 0) || (k >= NVar()))
327 throw RangeCheckError("BaseDataTable::NomIndex() out of range column index k");
328 return mNames[k].nom ;
329}
330
[2849]331//! Adds a row (or line) to the table with r_8* inout data
[2808]332/*!
333 The data to be added is provided as an array (vector) of double (r_8).
334 The necessary data conversion is performed, depending on each
335 column's data typeconverted to the data type.
336 Return the new number of table rows (lines / entries)
337 \param data : Data for each cell of the row to be appended
338 (data[k] k=0..NbColumns())
339*/
[2849]340sa_size_t BaseDataTable::AddRow(const r_8* data)
[2688]341{
[3392]342 DT_TSOP_SYNC dttss(mThS); dttss.NOp(); // Thread-safe operation
343
[2688]344 if (NVar() == 0)
[2849]345 throw ParmError("BaseDataTable::AddRow(const r_8*) Table has no column !");
[2688]346 if (NEntry() == SegmentSize()*NbSegments()) Extend();
347 sa_size_t n = NEntry();
348 sa_size_t bid = n/mSegSz;
349 sa_size_t off = n%mSegSz;
350 for(sa_size_t k=0; k<mIColsP.size(); k++)
351 mIColsP[k]->GetSegment(bid)[off] = (int_4)data[mIColIdx[k]];
352 for(sa_size_t k=0; k<mLColsP.size(); k++)
353 mLColsP[k]->GetSegment(bid)[off] = (int_8)data[mLColIdx[k]];
354 for(sa_size_t k=0; k<mFColsP.size(); k++)
355 mFColsP[k]->GetSegment(bid)[off] = (r_4)data[mFColIdx[k]];
356 for(sa_size_t k=0; k<mDColsP.size(); k++)
357 mDColsP[k]->GetSegment(bid)[off] = data[mDColIdx[k]];
[2827]358 for(sa_size_t k=0; k<mYColsP.size(); k++)
359 mYColsP[k]->GetSegment(bid)[off] = complex<r_4>(data[mYColIdx[k]],0.);
360 for(sa_size_t k=0; k<mZColsP.size(); k++)
361 mZColsP[k]->GetSegment(bid)[off] = complex<r_8>(data[mZColIdx[k]],0.);
[2688]362 for(sa_size_t k=0; k<mSColsP.size(); k++)
363 mSColsP[k]->GetSegment(bid)[off] = (string)MuTyV(data[mSColIdx[k]]);
364
365 mNEnt++;
366 return mNEnt;
367}
368
[2849]369//! Adds a row (or line) to the table with input data as an array of MuTyV
[2808]370/*!
371 The data to be added is provided as an array (vector) of MuTyV.
372 The MuTyV class conversion operators are used to match against each
373 cell data type.
374 Return the new number of table rows (lines / entries)
375 \param data : Data (MuTyV*) for each cell of the row to be appended
376 (data[k] k=0..NbColumns())
377*/
[2849]378sa_size_t BaseDataTable::AddRow(const MuTyV* data)
[2688]379{
[3392]380 DT_TSOP_SYNC dttss(mThS); dttss.NOp(); // Thread-safe operation
381
[2688]382 if (NVar() == 0)
[2849]383 throw ParmError("BaseDataTable::AddRow(const MuTyV*) Table has no column !");
[2688]384 if (NEntry() == SegmentSize()*NbSegments()) Extend();
385 sa_size_t n = NEntry();
386 sa_size_t bid = n/mSegSz;
387 sa_size_t off = n%mSegSz;
388 for(sa_size_t k=0; k<mIColsP.size(); k++)
389 mIColsP[k]->GetSegment(bid)[off] = (int_4)data[mIColIdx[k]];
390 for(sa_size_t k=0; k<mLColsP.size(); k++)
391 mLColsP[k]->GetSegment(bid)[off] = (int_8)data[mLColIdx[k]];
392 for(sa_size_t k=0; k<mSColsP.size(); k++)
393 mSColsP[k]->GetSegment(bid)[off] = (string)data[mSColIdx[k]];
394 for(sa_size_t k=0; k<mFColsP.size(); k++)
395 mFColsP[k]->GetSegment(bid)[off] = (r_4)data[mFColIdx[k]];
396 for(sa_size_t k=0; k<mDColsP.size(); k++)
397 mDColsP[k]->GetSegment(bid)[off] = (r_8)data[mDColIdx[k]];
[2827]398 for(sa_size_t k=0; k<mYColsP.size(); k++)
399 mYColsP[k]->GetSegment(bid)[off] =
400 complex<r_4>(data[mYColIdx[k]].GetRealPart(), data[mYColIdx[k]].GetImagPart());
401 for(sa_size_t k=0; k<mZColsP.size(); k++)
402 mZColsP[k]->GetSegment(bid)[off] =
403 complex<r_8>(data[mZColIdx[k]].GetRealPart(), data[mZColIdx[k]].GetImagPart());
[2688]404
405 mNEnt++;
406 return mNEnt;
407}
[2849]408//! Adds a row (or line) to the table with input data as DataTableRow object
409/*!
[2891]410 The internal MuTyV array of the object contains the data and the
[2849]411 MuTyV class conversion operators are used to match against each
412 cell data type.
413 Only the size of the input data object is checked.
414 Return the new number of table rows (lines / entries)
415 \param data : Data for each cell of the row to be appended
416 (data[k] k=0..NbColumns())
417*/
418sa_size_t BaseDataTable::AddRow(DataTableRow const& data)
419{
420 if ( data.Size() != NCols() )
421 throw SzMismatchError(" BaseDataTable::AddRow() - data.Size() != NCols() ");
422 return AddRow(data.MTVPtr());
423}
[2688]424
[2849]425/*!
426 Extends the table (in the row direction). This method is called automatically when needed.
427*/
[2688]428sa_size_t BaseDataTable::Extend()
429{
430 for(sa_size_t k=0; k<mIColsP.size(); k++)
431 mIColsP[k]->Extend();
432 for(sa_size_t k=0; k<mLColsP.size(); k++)
433 mLColsP[k]->Extend();
434 for(sa_size_t k=0; k<mFColsP.size(); k++)
435 mFColsP[k]->Extend();
436 for(sa_size_t k=0; k<mDColsP.size(); k++)
437 mDColsP[k]->Extend();
[2827]438 for(sa_size_t k=0; k<mYColsP.size(); k++)
439 mYColsP[k]->Extend();
440 for(sa_size_t k=0; k<mZColsP.size(); k++)
441 mZColsP[k]->Extend();
[2688]442 for(sa_size_t k=0; k<mSColsP.size(); k++)
443 mSColsP[k]->Extend();
444 mNSeg++;
445 return mNSeg;
446}
447
[2849]448/*!
449 Fills the input \b row object with the content of row \b n.
450 Return a reference to the input \b row object.
451 Generate an exception if the input \b row object has the wrong size.
452*/
453DataTableRow& BaseDataTable::GetRow(sa_size_t n, DataTableRow& row) const
454{
455 if ( row.Size() != NCols() )
456 throw SzMismatchError(" BaseDataTable::GetRow(n, row) - row.Size() != NCols() ");
[3392]457 GetRow(n, row.MTVPtr());
[2849]458 return row;
459}
[2688]460
[3392]461/*!
462 For thread-safe operation, specify a valid \b mtvp pointer (!= NULL)
463*/
464MuTyV* BaseDataTable::GetRow(sa_size_t n, MuTyV* mtvp) const
[2688]465{
[3392]466 DT_TSOP_SYNC dttss(mThS); dttss.NOp(); // Thread-safe operation
467
[2688]468 if ((n < 0) || (n >= NEntry()))
[2849]469 throw RangeCheckError("BaseDataTable::GetRow() out of range line index n");
[3392]470 if (mtvp == NULL) {
471 if (mVarMTV == NULL) mVarMTV = new MuTyV[NVar()];
472 mtvp = mVarMTV;
473 }
[2688]474 sa_size_t bid = n/mSegSz;
475 sa_size_t off = n%mSegSz;
476 for(sa_size_t k=0; k<mIColsP.size(); k++)
[3392]477 mtvp[mIColIdx[k]] = mIColsP[k]->GetCstSegment(bid)[off];
[2688]478 for(sa_size_t k=0; k<mLColsP.size(); k++)
[3392]479 mtvp[mLColIdx[k]] = mLColsP[k]->GetCstSegment(bid)[off];
[2688]480 for(sa_size_t k=0; k<mFColsP.size(); k++)
[3392]481 mtvp[mFColIdx[k]] = mFColsP[k]->GetCstSegment(bid)[off];
[2853]482 for(sa_size_t k=0; k<mDColsP.size(); k++) {
483 if (GetColumType(mDColIdx[k]) == DateTimeField)
[3392]484 mtvp[mDColIdx[k]] = TimeStamp(mDColsP[k]->GetCstSegment(bid)[off]);
485 else mtvp[mDColIdx[k]] = mDColsP[k]->GetCstSegment(bid)[off];
[2853]486 }
[2827]487 for(sa_size_t k=0; k<mYColsP.size(); k++)
[3392]488 mtvp[mYColIdx[k]] = mYColsP[k]->GetCstSegment(bid)[off];
[2827]489 for(sa_size_t k=0; k<mZColsP.size(); k++)
[3392]490 mtvp[mZColIdx[k]] = mZColsP[k]->GetCstSegment(bid)[off];
[2688]491 for(sa_size_t k=0; k<mSColsP.size(); k++)
[3392]492 mtvp[mSColIdx[k]] = mSColsP[k]->GetCstSegment(bid)[off];
[2688]493
[3392]494 return mtvp;
[2688]495}
496
[2831]497#define BADVAL -1.e39
498
499TVector<r_8> BaseDataTable::GetColumnD(sa_size_t k) const
500{
[3392]501 DT_TSOP_SYNC dttss(mThS); dttss.NOp(); // Thread-safe operation
502
[2831]503 if ((k < 0) || (k >= NVar()))
504 throw RangeCheckError("BaseDataTable::GetColumnD() out of range column index k");
505 sa_size_t sk = mNames[k].ser;
506 sa_size_t i = 0;
507 TVector<r_8> rv(NEntry());
508
509 for (sa_size_t is=0; is<NbSegments(); is++) {
510 switch (mNames[k].type) {
511 case IntegerField :
[3181]512 for(sa_size_t j=0; (j<SegmentSize())&&(i<NEntry()); j++,i++)
[2831]513 rv(i) = mIColsP[sk]->GetCstSegment(is)[j];
514 break;
515 case LongField :
[3181]516 for(sa_size_t j=0; (j<SegmentSize())&&(i<NEntry()); j++,i++)
[2831]517 rv(i) = mLColsP[sk]->GetCstSegment(is)[j];
518 break;
519 case FloatField :
[3181]520 for(sa_size_t j=0; (j<SegmentSize())&&(i<NEntry()); j++,i++)
[2831]521 rv(i) = mFColsP[sk]->GetCstSegment(is)[j];
522 break;
523 case DoubleField :
524 case DateTimeField :
[3181]525 for(sa_size_t j=0; (j<SegmentSize())&&(i<NEntry()); j++,i++)
[2831]526 rv(i) = mDColsP[sk]->GetCstSegment(is)[j];
527 break;
528 case ComplexField :
[3181]529 for(sa_size_t j=0; (j<SegmentSize())&&(i<NEntry()); j++,i++)
[2831]530 rv(i) = mYColsP[sk]->GetCstSegment(is)[j].real();
531 break;
532 case DoubleComplexField :
[3181]533 for(sa_size_t j=0; (j<SegmentSize())&&(i<NEntry()); j++,i++)
[2831]534 rv(i) = mZColsP[sk]->GetCstSegment(is)[j].real();
535 break;
536 case StringField :
[3181]537 for(sa_size_t j=0; (j<SegmentSize())&&(i<NEntry()); j++,i++)
[2831]538 rv = atof(mSColsP[sk]->GetCstSegment(is)[j].c_str());
539 break;
540 default:
[3181]541 for(sa_size_t j=0; (j<SegmentSize())&&(i<NEntry()); j++,i++)
542 rv(i) = BADVAL;
[2831]543 break;
544 }
545 }
546 return rv ;
547}
548
[2688]549void BaseDataTable::CopyMerge(BaseDataTable const& a, bool cp)
550{
551 if (cp && (NEntry() > 0) )
552 throw ParmError("BaseDataTable::CopyMerge(a) Table has entries already");
553 if (a.NVar() == 0) throw ParmError("BaseDataTable::CopyMerge(a) Table a has no column");
554 if (NVar() == 0) CopyStructure(a);
555 else if (!CompareStructure(a))
556 throw SzMismatchError("BaseDataTable::CopyMerge(a) (this,a) have different table structure");
557 if (a.NEntry() == 0) {
558 cout << " BaseDataTable::CopyMerge(a)/Warning : table a has zero (0) entry ! " << endl;
559 return;
560 }
561 for(sa_size_t kk=0; kk<a.NEntry(); kk++)
[2849]562 AddRow(a.GetLine(kk));
[2688]563}
564
565
566//! Returns the associated DVList object
567DVList& BaseDataTable::Info() const
568{
569 if (mInfo == NULL) mInfo = new DVList;
570 return(*mInfo);
571}
572
[2831]573/*!
574 Formatted (text) output of the table, for lines lstart <= l_index < lend , with step lstep
575 \param os : output stream (formatted output)
576 \param lstart : start row (line) index
577 \param lend : end row (line) index
578 \param lstep : row index increment
579*/
580ostream& BaseDataTable::Print(ostream& os, sa_size_t lstart, sa_size_t lend, sa_size_t lstep) const
[2688]581{
[2831]582 os << "##### BaseDataTable::Print() - Table(NRow=" << NEntry() << " , NCol="
583 << NVar() << ") ##### " << endl;
584 os << "#! " ;
585 for (size_t i=0; i<NVar(); i++) {
586 string nom = mNames[i].nom;
587 nom += ':'; nom += ColTypeToString(mNames[i].type);
588 os << setw(12) << nom << " ";
589 }
590 os << endl;
591 os << "##########################################################################" << endl;
592 for (sa_size_t l=lstart; l<lend; l+=lstep)
593 os << TableRowToString(l, true) << endl;
594 return os;
[2688]595}
596
[2808]597/*! In addition to printing the number of entries and column names,
598 this method prints also minimum/maximum value for each column.
599 This information might be computed when the Show() method is called.
600 This may take some time for tables with large number of entries (>~ 10^6)
601*/
[2688]602void BaseDataTable::Show(ostream& os) const
603{
604 os << "BaseDataTable: NVar= " << NVar() << " NEnt= " << NEntry()
605 << " ( SegSize= " << SegmentSize() << " NbSegments= "
606 << NbSegments() << " )" << endl;
607 os << "--------------------------------------------------------------------" << endl;
608 os << setw(3) << "i" << ":" << setw(20) << " Name" << " ("
609 << setw(4) << "Type" << ") | "
610 << setw(15) << " Min " << " | " << setw(15) << " Max " << endl;
611 os << "--------------------------------------------------------------------" << endl;
612 r_8 min, max ;
613 for(sa_size_t i = 0 ; i < NVar() ; i++) {
614 GetMinMax(i, min, max) ;
615 string nom;
616 if (mNames[i].nom.length() > 20)
617 nom = mNames[i].nom.substr(20);
618 else nom = mNames[i].nom;
619 os << setw(3) << i << ":" << setw(20) << nom << " ("
620 << setw(4) << ColTypeToString(mNames[i].type) << ") | "
621 << setw(15) << min << " | " << setw(15) << max << endl;
622 }
623 os << "--------------------------------------------------------------------" << endl;
624 return;
625}
626
[2831]627//! Fills table from an ascii (text) file
628/*
629 Return number of non empt lines (added to table)
630 \param is : input ascii (text) stream
631 \param clm : Lines starting with clm are ignored (comments)
632 \param sep : separator between different fields (columns)
633*/
634sa_size_t BaseDataTable::FillFromASCIIFile(istream& is, char clm, const char* sep)
[2688]635{
[2831]636 string str;
637 if (mVarMTV == NULL) mVarMTV = new MuTyV[NVar()];
638 sa_size_t iv, nl;
639 nl = 0;
640 while (!is.eof()) {
641 str = "";
642 getline(is, str);
643 if (is.good() || is.eof()) {
644 size_t l = str.length();
645 if ((l == 0) || (str[0]==clm)) continue;
646 for(iv=0; iv<NVar(); iv++) mVarMTV[iv] = 0.;
647 iv = 0;
648 size_t q = 0;
649 size_t p = 0;
650 while ( (q < l) && (iv < NVar()) ) {
651 p = str.find_first_not_of(sep,q);
652 if (p >= l) break;
653 if (str[p] == '\'') { // Decodage d'un string
654 q = str.find('\'',p+1);
655 if (q < l) {
656 mVarMTV[iv] = str.substr(p+1,q-p-1);
657 q++;
658 }
659 else mVarMTV[iv] = str.substr(p+1,l-p-1);
660 iv++;
661 }
662 else {
663 q = str.find_first_of(sep,p);
664 if (q > l) q = l;
665 mVarMTV[iv] = str.substr(p,q-p);
666 iv++;
667 }
668 if (mNames[iv-1].type == DateTimeField) {
669 string tts = (string)mVarMTV[iv-1];
670 mVarMTV[iv-1] = TimeStamp(tts);
671 }
672 }
[2849]673 AddRow(mVarMTV);
[2831]674 nl++;
675 }
676 } // Fin boucle lignes fichier
677 cout << "BaseDataTable::FillFromASCIIFile()/Info: " << nl << " lines decoded from stream " << endl;
678 return(nl);
[2688]679}
680
681
682
683//
684// ------------------------------------
685// ------- Interface NTuple -----------
686// ------------------------------------
687//
688sa_size_t BaseDataTable::NbLines() const
689{
690 return(NEntry());
691}
692
693sa_size_t BaseDataTable::NbColumns() const
694{
695 return(NVar());
696}
697
698r_8* BaseDataTable::GetLineD(sa_size_t n) const
699{
700 if ((n < 0) || (n >= NEntry()))
701 throw RangeCheckError("BaseDataTable::GetLineD() out of range line index n");
702 if (mVarD == NULL) mVarD = new r_8[NVar()];
703
704 sa_size_t bid = n/mSegSz;
705 sa_size_t off = n%mSegSz;
706 for(sa_size_t k=0; k<mIColsP.size(); k++)
[2699]707 mVarD[mIColIdx[k]] = mIColsP[k]->GetCstSegment(bid)[off];
[2688]708 for(sa_size_t k=0; k<mLColsP.size(); k++)
[2699]709 mVarD[mLColIdx[k]] = mLColsP[k]->GetCstSegment(bid)[off];
[2688]710 for(sa_size_t k=0; k<mFColsP.size(); k++)
[2699]711 mVarD[mFColIdx[k]] = mFColsP[k]->GetCstSegment(bid)[off];
[2688]712 for(sa_size_t k=0; k<mDColsP.size(); k++)
[2699]713 mVarD[mDColIdx[k]] = mDColsP[k]->GetCstSegment(bid)[off];
[2827]714 for(sa_size_t k=0; k<mYColsP.size(); k++)
715 mVarD[mYColIdx[k]] = mYColsP[k]->GetCstSegment(bid)[off].real();
716 for(sa_size_t k=0; k<mZColsP.size(); k++)
717 mVarD[mZColIdx[k]] = mZColsP[k]->GetCstSegment(bid)[off].real();
[2688]718 for(sa_size_t k=0; k<mSColsP.size(); k++)
[2699]719 mVarD[mSColIdx[k]] = atof(mSColsP[k]->GetCstSegment(bid)[off].c_str());
[2688]720
721 return mVarD;
722}
723
724
725r_8 BaseDataTable::GetCell(sa_size_t n, sa_size_t k) const
726{
727 if ((n < 0) || (n >= NEntry()))
728 throw RangeCheckError("BaseDataTable::GetCell() out of range line index n");
[2699]729 if ((k < 0) || (k >= NVar()))
[2688]730 throw RangeCheckError("BaseDataTable::GetCell() out of range column index k");
731 double rv = BADVAL;
732 sa_size_t sk = mNames[k].ser;
733 sa_size_t bid = n/mSegSz;
734 sa_size_t off = n%mSegSz;
[2699]735
[2688]736 switch (mNames[k].type) {
737 case IntegerField :
[2699]738 rv = mIColsP[sk]->GetCstSegment(bid)[off];
[2688]739 break;
740 case LongField :
[2699]741 rv = mLColsP[sk]->GetCstSegment(bid)[off];
[2688]742 break;
743 case FloatField :
[2699]744 rv = mFColsP[sk]->GetCstSegment(bid)[off];
[2688]745 break;
746 case DoubleField :
[2831]747 case DateTimeField :
748 rv = mDColsP[sk]->GetCstSegment(bid)[off];
[2688]749 break;
[2827]750 case ComplexField :
751 rv = mYColsP[sk]->GetCstSegment(bid)[off].real();
752 break;
753 case DoubleComplexField :
754 rv = mZColsP[sk]->GetCstSegment(bid)[off].real();
755 break;
[2688]756 case StringField :
[2699]757 rv = atof(mSColsP[sk]->GetCstSegment(bid)[off].c_str());
[2688]758 break;
759 default:
760 rv = BADVAL;
761 break;
762 }
763 return rv ;
764}
765
766
767r_8 BaseDataTable::GetCell(sa_size_t n, string const& nom) const
768{
769 return GetCell(n, IndexNom(nom));
770}
771
772string BaseDataTable::GetCelltoString(sa_size_t n, sa_size_t k) const
773{
774 if ((n < 0) || (n >= NEntry()))
775 throw RangeCheckError("BaseDataTable::GetCell() out of range line index n");
[2699]776 if ((k < 0) || (k >= NVar()))
[2688]777 throw RangeCheckError("BaseDataTable::GetCell() out of range column index k");
778 MuTyV rv;;
779 sa_size_t sk = mNames[k].ser;
780 sa_size_t bid = n/mSegSz;
781 sa_size_t off = n%mSegSz;
782 switch (mNames[k].type) {
783 case IntegerField :
[2699]784 rv = mIColsP[sk]->GetCstSegment(bid)[off];
[2688]785 break;
786 case LongField :
[2699]787 rv = mLColsP[sk]->GetCstSegment(bid)[off];
[2688]788 break;
789 case FloatField :
[2699]790 rv = mFColsP[sk]->GetCstSegment(bid)[off];
[2688]791 break;
792 case DoubleField :
[2699]793 rv = mDColsP[sk]->GetCstSegment(bid)[off];
[2688]794 break;
[2827]795 case ComplexField :
796 rv = mYColsP[sk]->GetCstSegment(bid)[off];
797 break;
798 case DoubleComplexField :
799 rv = mZColsP[sk]->GetCstSegment(bid)[off];
800 break;
[2688]801 case StringField :
[2699]802 rv = mSColsP[sk]->GetCstSegment(bid)[off];
[2688]803 break;
[2831]804 case DateTimeField :
805 rv = TimeStamp(mDColsP[sk]->GetCstSegment(bid)[off]);
806 break;
[2688]807 default:
808 rv = " ";
809 break;
810 }
811 return (string)rv ;
812}
813
814void BaseDataTable::GetMinMax(sa_size_t k, double& min, double& max) const
815{
816 min = 9E39 ; max = -9E39 ;
817 if ((k < 0) || (k >= NVar()))
818 throw RangeCheckError("BaseDataTable::GetCell() out of range column index k");
819 if (mMinMaxNEnt.size() < NVar()) {
820 mMin.clear();
821 mMax.clear();
822 mMinMaxNEnt.clear();
823 for(size_t kk=0; kk<NVar(); kk++) {
824 mMin.push_back(0.);
825 mMax.push_back(0.);
826 mMinMaxNEnt.push_back(0);
827 }
828 }
829 if (mMinMaxNEnt[k] == mNEnt) {
830 min = mMin[k];
831 max = mMax[k];
832 return;
833 }
834 sa_size_t sk = mNames[k].ser;
835
836 sa_size_t cnt = 0;
837 switch (mNames[k].type) {
838 case IntegerField :
839 for(size_t is=0; is<mIColsP[sk]->NbSegments(); is++) {
[2699]840 const int_4* sp = mIColsP[sk]->GetCstSegment(is);
[2688]841 for(size_t n=0; n<mIColsP[sk]->SegmentSize(); n++) {
842 if (cnt >= NEntry()) break;
843 if (sp[n] > max) max = sp[n];
844 if (sp[n] < min) min = sp[n];
845 cnt++;
846 }
847 }
848
849 break;
850 case LongField :
851 for(size_t is=0; is<mLColsP[sk]->NbSegments(); is++) {
[2699]852 const int_8* sp = mLColsP[sk]->GetCstSegment(is);
[2688]853 for(size_t n=0; n<mLColsP[sk]->SegmentSize(); n++) {
854 if (cnt >= NEntry()) break;
855 if (sp[n] > max) max = sp[n];
856 if (sp[n] < min) min = sp[n];
857 cnt++;
858 }
859 }
860 break;
861 case FloatField :
862 for(size_t is=0; is<mFColsP[sk]->NbSegments(); is++) {
[2699]863 const r_4* sp = mFColsP[sk]->GetCstSegment(is);
[2688]864 for(size_t n=0; n<mFColsP[sk]->SegmentSize(); n++) {
865 if (cnt >= NEntry()) break;
866 if (sp[n] > max) max = sp[n];
867 if (sp[n] < min) min = sp[n];
868 cnt++;
869 }
870 }
871 break;
872 case DoubleField :
[2831]873 case DateTimeField :
[2688]874 for(size_t is=0; is<mDColsP[sk]->NbSegments(); is++) {
[2699]875 const r_8* sp = mDColsP[sk]->GetCstSegment(is);
[2688]876 for(size_t n=0; n<mDColsP[sk]->SegmentSize(); n++) {
877 if (cnt >= NEntry()) break;
878 if (sp[n] > max) max = sp[n];
879 if (sp[n] < min) min = sp[n];
880 cnt++;
881 }
882 }
883 break;
[2827]884 case ComplexField :
885 for(size_t is=0; is<mYColsP[sk]->NbSegments(); is++) {
886 const complex<r_4> * sp = mYColsP[sk]->GetCstSegment(is);
887 for(size_t n=0; n<mYColsP[sk]->SegmentSize(); n++) {
888 if (cnt >= NEntry()) break;
889 if (sp[n].real() > max) max = sp[n].real();
890 if (sp[n].real() < min) min = sp[n].real();
891 cnt++;
892 }
893 }
894 break;
895 case DoubleComplexField :
896 for(size_t is=0; is<mZColsP[sk]->NbSegments(); is++) {
897 const complex<r_8> * sp = mZColsP[sk]->GetCstSegment(is);
898 for(size_t n=0; n<mZColsP[sk]->SegmentSize(); n++) {
899 if (cnt >= NEntry()) break;
900 if (sp[n].real() > max) max = sp[n].real();
901 if (sp[n].real() < min) min = sp[n].real();
902 cnt++;
903 }
904 }
905 break;
[2688]906 case StringField :
907 return;
908 break;
909 default:
910 return;
911 break;
912 }
913
914 mMinMaxNEnt[k] = cnt;
915 mMin[k] = min;
916 mMax[k] = max;
917 return ;
918}
919
920
921void BaseDataTable::GetMinMax(string const & nom, double& min, double& max) const
922{
923 GetMinMax(IndexNom(nom), min, max) ;
924}
925
926
927sa_size_t BaseDataTable::ColumnIndex(string const& nom) const
928{
929 return IndexNom(nom) ;
930}
931
932
933string BaseDataTable::ColumnName(sa_size_t k) const
934{
935 return NomIndex(k) ;
936}
937
938
939string BaseDataTable::VarList_C(const char* nomx) const
940{
941 string rets="";
942 sa_size_t i;
943 for(i=0; i<NVar(); i++) {
944 if ( (i%5 == 0) && (i > 0) ) rets += ";";
945 if (i%5 == 0) rets += "\ndouble ";
946 else rets += ",";
947 rets += mNames[i].nom;
948 }
949 rets += "; \n";
950 if (nomx) {
951 char buff[256];
952 for(i=0; i<NVar(); i++) {
953 rets += mNames[i].nom;
954 rets += '=';
955
[2693]956 sprintf(buff,"%s[%ld]; ", nomx, (long)i);
[2688]957 rets += buff;
958 if ( (i%3 == 0) && (i > 0) ) rets += "\n";
959 }
960 }
961 return(rets);
962}
963
964
965string BaseDataTable::LineHeaderToString() const
966{
[2699]967 string rets,s;
968
[2688]969 for(int i=0; i<NVar(); i++) {
[2699]970 s = mNames[i].nom;
971 size_t l = s.length();
[2831]972 for(size_t ii=l; ii<12; ii++) s += ' ';
973 if (i > 0) rets += ' ';
[2699]974 rets += s;
[2688]975 }
976 return(rets);
977}
978
[2831]979/*!
980 Return a table row (line) as a string
981 \sa TableRowToString()
982*/
983string BaseDataTable::LineToString(sa_size_t n) const
984{
985 return TableRowToString(n, false);
986}
[2688]987
[2831]988/*!
989 \param n : table row index ( 0 ... NEntry()-1)
990 \param qstr : if true , enclose strings in quotes ''
991 \param sep : separates fields using \b sep
992 \param fw : minimum field width
993 */
994string BaseDataTable::TableRowToString(sa_size_t n, bool qstr,
995 const char* sep, int fw) const
[2688]996{
997 if ((n < 0) || (n >= NEntry()))
998 throw RangeCheckError("BaseDataTable::GetCell() out of range line index n");
999 string rs;
1000 MuTyV rv;;
1001 sa_size_t bid = n/mSegSz;
1002 sa_size_t off = n%mSegSz;
1003 for(sa_size_t k=0; k<NVar(); k++) {
1004 sa_size_t sk = mNames[k].ser;
1005 switch (mNames[k].type) {
1006 case IntegerField :
[2699]1007 rv = mIColsP[sk]->GetCstSegment(bid)[off];
[2688]1008 break;
1009 case LongField :
[2699]1010 rv = mLColsP[sk]->GetCstSegment(bid)[off];
[2688]1011 break;
1012 case FloatField :
[2699]1013 rv = mFColsP[sk]->GetCstSegment(bid)[off];
[2688]1014 break;
1015 case DoubleField :
[2699]1016 rv = mDColsP[sk]->GetCstSegment(bid)[off];
[2688]1017 break;
[2827]1018 case ComplexField :
1019 rv = mYColsP[sk]->GetCstSegment(bid)[off];
1020 break;
1021 case DoubleComplexField :
1022 rv = mZColsP[sk]->GetCstSegment(bid)[off];
1023 break;
[2688]1024 case StringField :
[2699]1025 rv = mSColsP[sk]->GetCstSegment(bid)[off];
[2831]1026 break;
1027 case DateTimeField :
1028 rv = TimeStamp(mDColsP[sk]->GetCstSegment(bid)[off]);
1029 break;
[2688]1030 default:
1031 rv = " ";
1032 break;
1033 }
[2831]1034 string s;
1035 if ( (mNames[k].type == StringField) && (qstr) ) {
1036 s = '\''; s += (string)rv; s += '\'';
1037 }
1038 else s= (string)rv;
[2699]1039 size_t l = s.length();
[2831]1040 for(size_t ii=l; ii<fw; ii++) s += ' ';
1041 if (k > 0) rs += sep;
[2699]1042 rs += s;
[2688]1043 }
1044 return rs;
1045}
1046
[3392]1047} // FIN namespace SOPHYA
1048
Note: See TracBrowser for help on using the repository browser.