1 //==============================================================================
2 //
3 // This file is part of GPSTk, the GPS Toolkit.
4 //
5 // The GPSTk is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published
7 // by the Free Software Foundation; either version 3.0 of the License, or
8 // any later version.
9 //
10 // The GPSTk is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with GPSTk; if not, write to the Free Software Foundation,
17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 // This software was developed by Applied Research Laboratories at the
20 // University of Texas at Austin.
21 // Copyright 2004-2020, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24
25 //==============================================================================
26 //
27 // This software was developed by Applied Research Laboratories at the
28 // University of Texas at Austin, under contract to an agency or agencies
29 // within the U.S. Department of Defense. The U.S. Government retains all
30 // rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 // Pursuant to DoD Directive 523024
33 //
34 // DISTRIBUTION STATEMENT A: This software has been approved for public
35 // release, distribution is unlimited.
36 //
37 //==============================================================================
38
39 /**
40 * @file Namelist.cpp
41 * Implementation of class Namelist.
42 * class gpstk::Namelist encapsulates a list of labels for use with classes Matrix,
43 * Vector and SRI.
44 */
45
46 //------------------------------------------------------------------------------------
47 // system includes
48 #include <string>
49 #include <vector>
50 #include <algorithm>
51 #include <ostream>
52 #include <fstream> // for copyfmt
53 // GPSTk
54 #include "Exception.hpp"
55 #include "StringUtils.hpp"
56 #include "Namelist.hpp"
57
58 using namespace std;
59
60 namespace gpstk
61 {
62
63 using namespace StringUtils;
64
65 //------------------------------------------------------------------------------------
66 // constructor given dimension - creates default labels
Namelist(const unsigned int & n)67 Namelist::Namelist(const unsigned int& n)
68 {
69 try {
70 if(n == 0) return;
71 string name;
72 for(unsigned int i=0; i<n; i++) {
73 ostringstream oss;
74 oss << "NAME" << setw(3) << setfill('0') << i;
75 name = oss.str();
76 labels.push_back(name);
77 }
78 }
79 catch(Exception& e) { GPSTK_RETHROW(e); }
80 }
81
82 // explicit constructor - only a unique subset of names will be included.
Namelist(const vector<string> & names)83 Namelist::Namelist(const vector<string>& names)
84 {
85 try {
86 for(unsigned int i=0; i<names.size(); i++) {
87 bool unique=true;
88 for(unsigned int j=i+1; j<names.size(); j++) {
89 if(names[i] == names[j]) { unique=false; break; }
90 }
91 if(unique) labels.push_back(names[i]);
92 }
93 }
94 catch(Exception& e) { GPSTK_RETHROW(e); }
95 }
96
97 // add a name to the Namelist; throw if the name is not unique.
operator +=(const string & name)98 Namelist& Namelist::operator+=(const string& name)
99 {
100 try {
101 if(contains(name))
102 GPSTK_THROW(Exception("Name is not unique: " + name));
103 labels.push_back(name);
104 return *this;
105 }
106 catch(Exception& e) { GPSTK_RETHROW(e); }
107 }
108
109 // remove a name from the Namelist; does nothing if the name is not found.
operator -=(const string & name)110 Namelist& Namelist::operator-=(const string& name)
111 {
112 try {
113 vector<string>::iterator it;
114 it = find(labels.begin(),labels.end(),name);
115 if(it != labels.end())
116 labels.erase(it);
117 return *this;
118 }
119 catch(Exception& e) { GPSTK_RETHROW(e); }
120 }
121
122 // swap two elements, as given by their indexes; no effect if either index
123 // is out of range.
swap(const unsigned int & i,const unsigned int & j)124 void Namelist::swap(const unsigned int& i, const unsigned int& j)
125 {
126 try {
127 if(i == j) return;
128 if(i >= labels.size() || j >= labels.size()) return;
129 string str = labels[i];
130 labels[i] = labels[j];
131 labels[j] = str;
132 }
133 catch(Exception& e) { GPSTK_RETHROW(e); }
134 }
135
136 // reorder the list by sorting
sort(void)137 void Namelist::sort(void)
138 {
139 try {
140 // compiler tries Namelist::sort() first...
141 std::sort(labels.begin(),labels.end());
142 }
143 catch(Exception& e) { GPSTK_RETHROW(e); }
144 }
145
146 // resize the list by either truncation or adding default names.
resize(unsigned int n)147 void Namelist::resize(unsigned int n)
148 {
149 try {
150 if(n == labels.size()) return;
151 int N=labels.size();
152 while(labels.size() < n) {
153 string s;
154 do {
155 ostringstream oss;
156 oss << "NAME" << setw(3) << setfill('0') << N;
157 s = oss.str();
158 N++;
159 } while(contains(s));
160 labels.push_back(s);
161 }
162 while(labels.size() > n) {
163 labels.pop_back();
164 }
165 }
166 catch(Exception& e) { GPSTK_RETHROW(e); }
167 }
168
169 // randomize the list
randomize(long seed)170 void Namelist::randomize(long seed)
171 {
172 try {
173 if(labels.size() <= 1) return;
174 //random_shuffle(labels.begin(), labels.end());
175 if(seed) std::srand(seed);
176 for(int i=labels.size()-1; i>0; --i) {
177 using std::swap;
178 swap(labels[i], labels[std::rand() % (i+1)]);
179 }
180 }
181 catch(Exception& e) { GPSTK_RETHROW(e); }
182 }
183
184 // is the Namelist valid? checks for repeated names
valid(void) const185 bool Namelist::valid(void) const
186 {
187 try {
188 for(unsigned int i=0; i<labels.size(); i++)
189 for(unsigned int j=i+1; j<labels.size(); j++)
190 if(labels[i] == labels[j]) return false;
191 return true;
192 }
193 catch(Exception& e) { GPSTK_RETHROW(e); }
194 }
195
196 // does the Namelist contain the input name?
contains(const string & name) const197 bool Namelist::contains(const string& name) const
198 {
199 try {
200 for(unsigned int i=0; i<labels.size(); i++) {
201 if(labels[i] == name) return true;
202 }
203 return false;
204 }
205 catch(Exception& e) { GPSTK_RETHROW(e); }
206 }
207
208 // are two Namelists identical, ignoring a permutation?
operator ==(const Namelist & N1,const Namelist & N2)209 bool operator==(const Namelist& N1, const Namelist& N2)
210 {
211 try {
212 if(N1.size() != N2.size()) return false;
213 if(N1.size() == 0) return true;
214 for(unsigned int i=0; i<N1.size(); i++) {
215 unsigned int match=0;
216 for(unsigned int j=0; j<N2.size(); j++)
217 if(N1.labels[i] == N2.labels[j]) match++;
218 if(match != 1) return false; // if > 1, N2 is invalid
219 }
220 return true;
221 }
222 catch(Exception& e) { GPSTK_RETHROW(e); }
223 }
224
225 // are two Namelists different, ignoring a permutation?
operator !=(const Namelist & N1,const Namelist & N2)226 bool operator!=(const Namelist& N1, const Namelist& N2)
227 {
228 try {
229 return !(N1==N2);
230 }
231 catch(Exception& e) { GPSTK_RETHROW(e); }
232 }
233
234 // are two Namelists exactly identical, even considering permutations?
identical(const Namelist & N1,const Namelist & N2)235 bool identical(const Namelist& N1, const Namelist& N2)
236 {
237 try {
238 if(N1.size() != N2.size()) return false;
239 if(N1.size() == 0) return true;
240 for(unsigned int i=0; i<N1.size(); i++) {
241 if(N1.labels[i] != N2.labels[i]) return false;
242 }
243 return true;
244 }
245 catch(Exception& e) { GPSTK_RETHROW(e); }
246 }
247
248 // construct the subset Namelist which is common to the two input (AND)
operator &(const Namelist & N1,const Namelist & N2)249 Namelist operator&(const Namelist& N1, const Namelist& N2)
250 {
251 try {
252 Namelist N(N1);
253 N &= N2;
254 return N;
255 }
256 catch(Exception& e) { GPSTK_RETHROW(e); }
257 }
258
259 // merge two Namelists, i.e. construct a non-redundant combination (OR)
operator |(const Namelist & N1,const Namelist & N2)260 Namelist operator|(const Namelist& N1, const Namelist& N2)
261 {
262 try {
263 Namelist N(N1);
264 N |= N2;
265 return N;
266 }
267 catch(Exception& e) { GPSTK_RETHROW(e); }
268 }
269
270 // construct the subset Namelist which is NOT common to two others (XOR)
operator ^(const Namelist & N1,const Namelist & N2)271 Namelist operator^(const Namelist& N1, const Namelist& N2)
272 {
273 try {
274 Namelist N(N1);
275 N ^= N2;
276 return N;
277 }
278 catch(Exception& e) { GPSTK_RETHROW(e); }
279 }
280
281 // replace this with (this & input) (AND - common to both)
operator &=(const Namelist & N)282 Namelist& Namelist::operator&=(const Namelist& N)
283 {
284 try {
285 Namelist NAND;
286 for(unsigned int i=0; i<N.labels.size(); i++)
287 if(contains(N.labels[i])) NAND += N.labels[i];
288 *this = NAND;
289 return *this;
290 }
291 catch(Exception& e) { GPSTK_RETHROW(e); }
292 }
293
294 // replace this with (this | input) (OR - merge - superset)
295 // NB new elements must be added at the end (for class SRI).
operator |=(const Namelist & N)296 Namelist& Namelist::operator|=(const Namelist& N)
297 {
298 try {
299 Namelist NOR(*this);
300 for(unsigned int i=0; i<N.labels.size(); i++)
301 if(!(contains(N.labels[i]))) NOR += N.labels[i];
302 *this = NOR;
303 return *this;
304 }
305 catch(Exception& e) { GPSTK_RETHROW(e); }
306 }
307
308 // replace this with (this ^ input) (XOR - not common)
operator ^=(const Namelist & N)309 Namelist& Namelist::operator^=(const Namelist& N)
310 {
311 try {
312 unsigned int i;
313 Namelist NXOR;
314 for(i=0; i<labels.size(); i++)
315 if(!(N.contains(labels[i]))) NXOR += labels[i];
316 for(i=0; i<N.labels.size(); i++)
317 if(!(contains(N.labels[i]))) NXOR += N.labels[i];
318 *this = NXOR;
319 return *this;
320 }
321 catch(Exception& e) { GPSTK_RETHROW(e); }
322 }
323
324
325 // access to a specific name, given its index; may be used as lvalue.
326 //string& Namelist::operator[](const unsigned int in)
327 //{
328 // if(in >= labels.size()) throw ...
329 // return labels[in];
330 //}
331
332 // access to a specific name, given its index.
333 // returns 'out-of-range' if the index is out of range.
getName(const unsigned int in) const334 string Namelist::getName(const unsigned int in) const
335 {
336 try {
337 if(in >= labels.size()) return string("out-of-range");
338 return labels[in];
339 }
340 catch(Exception& e) { GPSTK_RETHROW(e); }
341 }
342
343 // assign a specific name, given its index;
344 // no effect if the index is out of range or the name is not unique.
345 // return true if successful
setName(const unsigned int in,const string & name)346 bool Namelist::setName(const unsigned int in, const string& name)
347 {
348 try {
349 if(in >= labels.size()) return false;
350 if(labels[in] == name) return true; // NB b/c contains(name) would be true..
351 if(contains(name)) return false;
352 labels[in] = name;
353 return true;
354 }
355 catch(Exception& e) { GPSTK_RETHROW(e); }
356 }
357
358 // return the index of the name in the list that matches the input, -1 if not found.
index(const string & name) const359 int Namelist::index(const string& name) const
360 {
361 try {
362 for(unsigned int i=0; i<labels.size(); i++)
363 if(labels[i] == name) return i;
364 return -1;
365 }
366 catch(Exception& e) { GPSTK_RETHROW(e); }
367 }
368
369 // output operator
operator <<(ostream & os,const Namelist & N)370 ostream& operator<<(ostream& os, const Namelist& N)
371 {
372 try {
373 if(N.labels.size() > 0) {
374 for(unsigned int i=0; i<N.labels.size(); i++)
375 os << " / " << N.labels[i];
376 os << " / ";
377 }
378 return os;
379 }
380 catch(Exception& e) { GPSTK_RETHROW(e); }
381 }
382
operator <<(ostream & os,const LabeledVector & LV)383 ostream& operator<<(ostream& os, const LabeledVector& LV)
384 {
385 try {
386 size_t i;
387 string s;
388 //ofstream savefmt;
389 //savefmt.copyfmt(os);
390 //int wid=os.width(),prec=os.precision();
391
392 // print message or blanks
393 os << LV.tag << " ";
394 if(LV.msg.size() > 0)
395 s = LV.msg;
396 else
397 s = rightJustify(string(""),LV.msg.size()); //LV.wid);
398 os << s << " ";
399
400 // print each label
401 for(i=0; i<LV.NL.size(); i++) {
402 if(int(LV.NL.getName(i).size()) > LV.wid)
403 s = leftJustify(LV.NL.getName(i),LV.wid);
404 else
405 s = rightJustify(LV.NL.getName(i),LV.wid);
406 os << s;
407 if(i-LV.NL.size()+1) os << " ";
408 }
409 os << endl; // next line
410
411 // print same space as with labels
412 s = rightJustify(string(""),LV.msg.size()+2); //LV.wid);
413 os << LV.tag << " " << s << " ";
414 if(LV.form == 1) os << fixed;
415 if(LV.form == 2) os << scientific;
416 for(i=0; i<LV.V.size(); i++) {
417 //os.copyfmt(savefmt);
418 //os << LV.V(i);
419 os << setw(LV.wid) << setprecision(LV.prec) << LV.V(i);
420 if(i-LV.V.size()+1) os << " ";
421 }
422
423 return os;
424 }
425 catch(Exception& e) { GPSTK_RETHROW(e); }
426 }
427
operator <<(ostream & os,const LabeledMatrix & LM)428 ostream& operator<<(ostream& os, const LabeledMatrix& LM)
429 {
430 try {
431 int nspace;
432 size_t i, j, jlast, n;
433 string s;
434 const Namelist *pNLcol = &LM.NLcols;
435 const Namelist *pNLrow = &LM.NLrows;
436
437 // first make sure we have both namelists
438 if(LM.NLrows.size() == 0 && LM.NLcols.size() == 0) {
439 os << " Error -- Namelists in LabeledMatrix are empty! ";
440 return os;
441 }
442 if(LM.NLrows.size() == 0) pNLrow = pNLcol;
443 if(LM.NLcols.size() == 0) pNLcol = pNLrow;
444
445 // on column labels line
446 os << setw(0);
447 if(LM.rc == 0) { // only if printing both column and row labels
448 os << LM.tag << " "; // tag
449 if(LM.msg.size() > 0) // msg
450 s = LM.msg + " ";
451 else
452 s = rightJustify(string(" "),LM.wid);
453 os << s << " ";
454 if(int(LM.msg.size()) > 0 && int(LM.msg.size()) < LM.wid)
455 os << rightJustify(string(" "),LM.wid-LM.msg.size()); // space
456 }
457 // print column labels
458 if(LM.rc != 1) { // but not if 'rows only'
459 n = (LM.M.cols() < pNLcol->size() ? LM.M.cols() : pNLcol->size());
460 if(LM.rc == 2) os << " ";
461 for(i=0; i<n; i++) {
462 if(int(pNLcol->getName(i).size()) > LM.wid)
463 s = leftJustify(pNLcol->getName(i),LM.wid);
464 else
465 s = rightJustify(pNLcol->getName(i),LM.wid);
466 os << s; // label
467 if(i<n-1) os << " ";
468 }
469 os << endl;
470 }
471
472 if(LM.form == 1) os << fixed;
473 if(LM.form == 2) os << scientific;
474 if(int(LM.msg.size()) > LM.wid) nspace = LM.msg.size()-LM.wid+2;
475 else if(int(LM.msg.size())) nspace = 2;
476 else nspace = 0;
477
478 // print one row per line
479 for(i=0; i<LM.M.rows(); i++) {
480 os << LM.tag << " "; // tag
481 if(nspace) os << rightJustify(string(" "),nspace); // space
482 // print row labels
483 if(LM.rc != 2) { // but not if 'columns only'
484 if(int(pNLrow->getName(i).size()) > LM.wid)
485 s = leftJustify(pNLrow->getName(i),LM.wid);
486 else
487 s = rightJustify(pNLrow->getName(i),LM.wid);
488 os << s << " "; // label
489 }
490 // finally, print the data
491 jlast = (LM.sym ? i+1 : LM.M.cols());
492 for(j=0; j<jlast; j++) {
493 if(LM.cln && ::fabs(LM.M(i,j)) < ::pow(10.0,-LM.prec)) // clean print
494 os << rightJustify("0",LM.wid);
495 else
496 os << setw(LM.wid) << setprecision(LM.prec) << LM.M(i,j);
497 if(j<jlast-1) os << " "; // data
498 }
499 if(i<LM.M.rows()-1) os << endl;
500 }
501
502 return os;
503 }
504 catch(Exception& e) { GPSTK_RETHROW(e); }
505 }
506
507 } // end namespace gpstk
508
509 //------------------------------------------------------------------------------------
510 //------------------------------------------------------------------------------------
511