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

Last change on this file since 3685 was 3392, checked in by ansari, 18 years ago

Implementation NTuple::Fill(), BaseDataTable:;AddRow()/GetRow() thread-safe - Reza 22/11/2007

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