Xmipp  v3.23.11-Nereus
metadata_object.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: J.M. De la Rosa Trevin (jmdelarosa@cnb.csic.es)
4  * Jan Horacek (xhorace4@fi.muni.cz)
5  *
6  * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21  * 02111-1307 USA
22  *
23  * All comments concerning this program package may be sent to the
24  * e-mail address 'xmipp@cnb.csic.es'
25  ***************************************************************************/
26 
27 #include <iostream>
28 #include <iomanip>
29 #include <sstream>
30 #include "metadata_object.h"
31 #include "metadata_static.h"
32 #include "xmipp_error.h"
33 #include "xmipp_macros.h"
34 #include <limits>
35 
36 #define DOUBLE2STREAM(d) \
37  if (withFormat) {\
38  (os) << std::setw(12); \
39  (os) << (((d) != 0. && ABS(d) < 0.001) ? std::scientific : std::fixed);\
40  } os << d;
41 
42 #define INT2STREAM(i) \
43  if (withFormat) os << std::setw(20); \
44  os << i;
45  //this must have 20 since SIZE_MAX = 18446744073709551615 size
46 
47 
49 {
50  if ((type == LABEL_STRING) && (data.stringValue != nullptr))
51  {
52  delete data.stringValue;
53  data.stringValue = nullptr;
54  }
55  else if ((type == LABEL_VECTOR_DOUBLE) && (data.vectorValue != nullptr))
56  {
57  delete data.vectorValue;
58  data.vectorValue = nullptr;
59  }
60  else if ((type == LABEL_VECTOR_SIZET) && (data.vectorValueLong != nullptr))
61  {
62  delete data.vectorValueLong;
63  data.vectorValueLong = nullptr;
64  }
65 
66  label = obj.label;
67  failed = obj.failed;
68  type = obj.type;
69  chr = obj.chr;
70 
71  if (type == LABEL_STRING)
72  data.stringValue = new String(*(obj.data.stringValue));
73  else if (type == LABEL_VECTOR_DOUBLE)
74  data.vectorValue = new std::vector<double>(*(obj.data.vectorValue));
75  else if (type == LABEL_VECTOR_SIZET)
76  data.vectorValueLong = new std::vector<size_t>(*(obj.data.vectorValueLong));
77  else
78  data = obj.data;
79 }
80 
82 {
83  copy(obj);
84 }
85 
87 {
88  copy(obj);
89  return *this;
90 }
91 
92 inline void MDObject::labelTypeCheck(MDLabelType checkingType) const
93 {
94  if (this->type != checkingType)
95  {
96  std::stringstream ss;
97  ss << "Mismatch Label (" << MDL::label2Str(label)
98  << ") and value type(" << MDL::labelType2Str(checkingType) << ")";
99  REPORT_ERROR(ERR_MD_BADLABEL, ss.str());
100  }
101 }
102 
103 //Just a simple constructor with the label
104 //don't do any type checking as have not value yet
106 {
107  this->label = label;
108  failed = false;
109  chr = _SPACE;
110  if (label != MDL_UNDEFINED)
111  {
112  type = MDL::labelType(label);
113  if (type == LABEL_STRING)
114  data.stringValue = new String;
115  else if (type == LABEL_VECTOR_DOUBLE)
116  data.vectorValue = new std::vector<double>;
117  else if (type == LABEL_VECTOR_SIZET)
118  data.vectorValueLong = new std::vector<size_t>;
119  }
120  else
121  type = LABEL_NOTYPE;
122 }
123 
125 #define MDOBJECT_INIT() this->label = label; this->type = MDL::labelType(label); this->failed = false; this->chr = _SPACE;
126 
130 {
131  MDOBJECT_INIT();
132  this->setValue(v);
133 }
135 {
136  MDOBJECT_INIT();
137  this->setValue(v);
138 }
140 {
141  MDOBJECT_INIT();
142  this->setValue(v);
143 }
145 {
146  MDOBJECT_INIT();
147  this->data.stringValue = new String();
148  this->setValue(v);
149 }
150 MDObject::MDObject(MDLabel label, const std::vector<double> &v)
151 {
152  MDOBJECT_INIT();
153  this->data.vectorValue = new std::vector<double>();
154  this->setValue(v);
155 }
156 MDObject::MDObject(MDLabel label, const std::vector<size_t> &v)
157 {
158  MDOBJECT_INIT();
159  this->data.vectorValueLong = new std::vector<size_t>();
160  this->setValue(v);
161 }
163 {
164  MDOBJECT_INIT();
165  this->setValue(v);
166 }
167 
169 {
170  if (type == LABEL_STRING)
171  delete data.stringValue;
172  else if (type == LABEL_VECTOR_DOUBLE)
173  delete data.vectorValue;
174  else if (type == LABEL_VECTOR_SIZET)
175  delete data.vectorValueLong;
176 }
177 
178 //These getValue2 also do a compilation type checking
179 //when expanding templates functions and only
180 //will allow the supported types
181 //TODO: think if the type check if needed here
182 
185  return this->data.intValue;
186 }
187 
188 const int& MDObject::getValue2(int ) const {
190  return this->data.intValue;
191 }
192 
193 double& MDObject::getValue2(double) {
195  return this->data.doubleValue;
196 }
197 
198 const double& MDObject::getValue2(double) const {
200  return this->data.doubleValue;
201 }
202 
203 bool& MDObject::getValue2(bool) {
205  return this->data.boolValue;
206 }
207 
208 const bool& MDObject::getValue2(bool) const {
210  return this->data.boolValue;
211 }
212 
215  return *(this->data.stringValue);
216 }
217 
220  return *(this->data.stringValue);
221 }
222 
223 std::vector<double>& MDObject::getValue2(std::vector<double>) {
225  return *(this->data.vectorValue);
226 }
227 
228 const std::vector<double>& MDObject::getValue2(std::vector<double>) const {
230  return *(this->data.vectorValue);
231 }
232 
233 std::vector<float>& MDObject::getValue2(std::vector<float>) {
235  return *(this->data.vectorValueFloat);
236 }
237 
238 const std::vector<float>& MDObject::getValue2(std::vector<float>) const {
240  return *(this->data.vectorValueFloat);
241 }
242 
243 std::vector<size_t>& MDObject::getValue2(std::vector<size_t>) {
245  return *(this->data.vectorValueLong);
246 }
247 
248 const std::vector<size_t>& MDObject::getValue2(std::vector<size_t>) const {
250  return *(this->data.vectorValueLong);
251 }
252 
253 size_t& MDObject::getValue2(size_t) {
255  return this->data.longintValue;
256 }
257 
258 const size_t& MDObject::getValue2(size_t) const {
260  return this->data.longintValue;
261 }
262 
263 float MDObject::getValue2(float) {
264  return getValue2(0.); // double
265 }
266 
267 float MDObject::getValue2(float) const {
268  return getValue2(0.); // double
269 }
270 
271 void MDObject::setValue(const int &iv)
272 {
274  this->data.intValue = iv;
275 }
276 
277 void MDObject::setValue(const double &dv)
278 {
280  this->data.doubleValue = safeDouble(dv);
281 }
282 
283 void MDObject::setValue(const bool &bv)
284 {
286  this->data.boolValue = bv;
287 }
288 
289 void MDObject::setValue(const String &sv)
290 {
292  *(this->data.stringValue) = sv;
293 }
294 
295 void MDObject::setValue(const std::vector<double> &vv)
296 {
298  const auto size = vv.size();
299  this->data.vectorValue->resize(size);
300  for (size_t i = 0; i < size; ++i) {
301  this->data.vectorValue->operator[](i) = safeDouble(vv[i]);
302  }
303 }
304 
305 void MDObject::setValue(const std::vector<float> &vv)
306 {
308  const auto size = vv.size();
309  this->data.vectorValueFloat->resize(size);
310  for (size_t i = 0; i < size; ++i) {
311  this->data.vectorValueFloat->operator[](i) = safeFloat(vv[i]);
312  }
313 }
314 
315 void MDObject::setValue(const std::vector<size_t> &vv)
316 {
318  *(this->data.vectorValueLong) = vv;
319 }
320 
321 void MDObject::setValue(const size_t &lv)
322 {
324  this->data.longintValue = lv;
325 }
326 
327 void MDObject::setValue(const float &floatvalue)
328 {
329  setValue((double) floatvalue);
330 }
331 
332 void MDObject::setValue(const char* &charvalue)
333 {
334  setValue(String(charvalue));
335 }
336 
337 void MDObject::toStream(std::ostream &os, bool withFormat, bool isSql, bool escape) const
338 {
339  if (label == MDL_UNDEFINED) //if undefine label, store as a literal string
340  os << data.stringValue;
341  else
342  switch (MDL::labelType(label))
343  {
344  case LABEL_BOOL: //bools are int in sqlite3
345  os << data.boolValue;
346  break;
347  case LABEL_INT:
349  break;
350  case LABEL_SIZET:
352  break;
353  case LABEL_DOUBLE:
355  break;
356  case LABEL_STRING:
357  {
358  char c = _SPACE;
359  if (escape)
360  {
361  if (isSql || data.stringValue->find_first_of(_DQUOT) != String::npos)
362  c = _QUOT;
363  else if (data.stringValue->find_first_of(_QUOT) != String::npos)
364  c = _DQUOT;
365  else if (data.stringValue->find_first_of(_SPACE) != String::npos)
366  c = _QUOT;
367  else if (data.stringValue->empty())
368  c = _QUOT;
369  }
370  if (c == _SPACE)
371  os << *(data.stringValue);
372  else
373  os << c << *(data.stringValue) << c;
374  }
375  break;
376  case LABEL_VECTOR_DOUBLE:
377  {
378  std::vector<double> &vectorDouble = *(data.vectorValue);
379  if (escape)
380  os << _QUOT << " ";
381  size_t size = vectorDouble.size();
382  for (size_t i = 0; i < size; i++)
383  {
384  double v = vectorDouble[i];
385  DOUBLE2STREAM(v);
386  os << " ";
387  }
388  if (escape)
389  os << _QUOT;
390  }
391  break;
392  case LABEL_VECTOR_SIZET:
393  {
394  std::vector<size_t> &vector = *(data.vectorValueLong);
395  if (escape)
396  os << _QUOT << " ";
397  size_t size = vector.size();
398  for (size_t i = 0; i < size; i++)
399  os << vector[i] << " ";
400  if (escape)
401  os << _QUOT;
402  }
403  break;
404  case LABEL_NOTYPE:
405  if (escape) os << _QUOT;
406  os << "No type";
407  if (escape) os << _QUOT;
408  break;
409  }//close switch
410 }//close function toStream
411 
412 String MDObject::toString(bool withFormat, bool isSql) const
413 {
414  if (type == LABEL_STRING)
415  {
416  return isSql ? formatString("'%s'", data.stringValue->c_str()) : *data.stringValue;
417  }
418  std::stringstream ss;
419  toStream(ss, withFormat, isSql, isSql);
420 
421  return ss.str();
422 }
423 
424 //bool MDValue::fromStream(std::istream &is)
425 std::ostream& operator<< (std::ostream& os, const MDObject &value)
426 {
427  value.toStream(os);
428  return os;
429 }
430 
431 //bool MDValue::fromStream(std::istream &is)
433 {
434  value.fromStream(is);
435  return is;
436 }
437 
439 {
440  if (label == MDL_UNDEFINED) //if undefine label, store as a literal string
441  {
442  String s;
443  is >> s;
444  }
445  else
446  {
447  //NOTE: int, bool and long(size_t) are read as double for compatibility with old doc files
448  double d;
449  size_t value;
450  switch (type)
451  {
452  case LABEL_BOOL: //bools are int in sqlite3
453  is >> d;
454  data.boolValue = (bool) ((int)d);
455  break;
456  case LABEL_INT:
457  is >> d;
458  data.intValue = (int) d;
459  break;
460  case LABEL_SIZET:
461  is >> d;
462  data.longintValue = (size_t) d;
463  break;
464  case LABEL_DOUBLE:
465  is >> data.doubleValue;
466  break;
467  case LABEL_STRING:
468  {
469  data.stringValue->clear();
470  String s;
471  is >> s;
472  char chr = s[0];
473  if (chr == _QUOT || chr == _DQUOT)
474  {
475  s = s.substr(1, s.size() - 1); //remove first char '
476  while (s.find_last_of(chr) == String::npos)
477  {
478  data.stringValue->append(s + " ");
479  is >> s;
480  }
481  s = s.substr(0, s.size() - 1); //remove last char '
482  }
483  data.stringValue->append(s);
484  }
485  break;
486  case LABEL_VECTOR_DOUBLE:
487  if (!fromString)
488  is.ignore(256, _QUOT);
489  //if (data.vectorValue == NULL)
490  // data.vectorValue = new std::vector<double>;
491  data.vectorValue->clear();
492  while (is >> d) //This will stop at ending "]"
493  data.vectorValue->emplace_back(d);
494  if (!fromString)
495  {
496  is.clear(); //this is for clear the fail state after found ']'
497  is.ignore(256, _QUOT); //ignore the ending ']'
498  }
499  break;
500  case LABEL_VECTOR_SIZET:
501  if (!fromString)
502  is.ignore(256, _QUOT);
503  //if (data.vectorValue == NULL)
504  // data.vectorValue = new std::vector<double>;
505  data.vectorValueLong->clear();
506  while (is >> value) //This will stop at ending "]"
507  data.vectorValueLong->emplace_back(value);
508  if (!fromString)
509  {
510  is.clear(); //this is for clear the fail state after found ']'
511  is.ignore(256, _QUOT); //ignore the ending ']'
512  }
513  break;
514  case LABEL_NOTYPE:
515  break;
516  }
517  }
518  return is.good();
519 }
520 
521 bool MDObject::fromString(const String& str)
522 {
523  if (type == LABEL_STRING)
524  *data.stringValue = str;
525  std::stringstream ss(str);
526  return fromStream(ss, true);
527 }
528 
529 bool MDObject::fromChar(const char * szChar)
530 {
531  std::stringstream ss(szChar);
532  return fromStream(ss);
533 }
534 
535 bool MDObject::operator==(const MDObject &obj) const {
536  return this->eq(obj, 0);
537 }
538 
539 bool MDObject::eq(const MDObject &obj, double epsilon) const {
540  // FIXME: allow to compare e.g. int & double & longint
541  if (this->label != obj.label)
542  return false;
543 
544  if (this->type != obj.type)
545  throw std::logic_error("MDObject: cannot compare == objects of different type");
546 
547  switch (this->type) {
548  case LABEL_INT:
549  return this->data.intValue == obj.data.intValue;
550 
551  case LABEL_BOOL:
552  return this->data.boolValue == obj.data.boolValue;
553 
554  case LABEL_SIZET:
555  return this->data.longintValue == obj.data.longintValue;
556 
557  case LABEL_DOUBLE:
558  return std::abs(this->data.doubleValue - obj.data.doubleValue) <= epsilon;
559 
560  case LABEL_STRING:
561  return *(this->data.stringValue) == *(obj.data.stringValue);
562 
563  case LABEL_VECTOR_DOUBLE:
564  if (this->data.vectorValue->size() != obj.data.vectorValue->size())
565  return false;
566  for (size_t i = 0; i < this->data.vectorValue->size(); i++)
567  if (std::abs((*this->data.vectorValue)[i] - (*obj.data.vectorValue)[i]) > epsilon)
568  return false;
569  return true;
570 
571  case LABEL_VECTOR_SIZET:
572  return *(this->data.vectorValueLong) == *(obj.data.vectorValueLong);
573 
574  default:
575  throw std::logic_error("MDObject: unknown data type");
576  };
577 }
578 
579 bool MDObject::operator<=(const MDObject &obj) const {
580  // FIXME: allow to compare e.g. int & double & longint
581  if (this->type == LABEL_INT)
582  return this->data.intValue <= obj.data.intValue;
583  if (this->type == LABEL_BOOL)
584  return this->data.boolValue <= obj.data.boolValue;
585  if (this->type == LABEL_SIZET)
586  return this->data.longintValue <= obj.data.longintValue;
587  if (this->type == LABEL_DOUBLE)
588  return this->data.doubleValue <= obj.data.doubleValue;
589  if (this->type == LABEL_STRING)
590  return this->data.stringValue->compare(*obj.data.stringValue) <= 0;
591 
592  throw std::logic_error("MDObject: cannot compare this type on <=");
593 }
594 
595 bool MDObject::operator!=(const MDObject &obj) const {
596  return !(*this == obj);
597 }
598 
599 bool MDObject::operator>=(const MDObject &obj) const {
600  return (!(*this <= obj) || (*this == obj));
601 }
602 
603 bool MDObject::operator<(const MDObject &obj) const {
604  return ((*this <= obj) && (*this != obj));
605 }
606 
607 bool MDObject::operator>(const MDObject &obj) const {
608  return ((*this >= obj) && (*this != obj));
609 }
610 
611 double MDObject::safeDouble(const double v) const {
612  if (std::isnan(v)) {
613  // when saving NaN to sqlite3 db, the actually inserted value is sth very close to zero (0)
614  // this was causing incompatibilities between (non)sqlite versions of metadata
615  std::cerr << "Warning: trying to work with NaN in MDObject with label " << MDL::label2Str(this->label)
616  << ". Using std::numeric_limits<double>::min() instead for backward compatilibity.\n";
618  }
619  return v;
620  }
621 
622 float MDObject::safeFloat(const float v) const {
623  if (std::isnan(v)) {
624  // when saving NaN to sqlite3 db, the actually inserted value is sth very close to zero (0)
625  // this was causing incompatibilities between (non)sqlite versions of metadata
626  std::cerr << "Warning: trying to work with NaN in MDObject with label " << MDL::label2Str(this->label)
627  << ". Using std::numeric_limits<float>::min() instead for backward compatilibity.\n";
629  }
630  return v;
631  }
632 
633 //MDObject & MDRow::operator [](MDLabel label)
634 //{
635 // for (iterator it = begin(); it != end(); ++it)
636 // if ((*it)->label == label)
637 // return *(*it);
638 // MDObject * pObj = new MDObject(label);
639 // emplace_back(pObj);
640 //
641 // return *pObj;
642 //}
void labelTypeCheck(MDLabelType checkingType) const
#define _DQUOT
void min(Image< double > &op1, const Image< double > &op2)
std::vector< size_t > * vectorValueLong
const int & getValue2(int) const
MDLabelType
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
doublereal * c
static String labelType2Str(MDLabelType type)
Unexpected label.
Definition: xmipp_error.h:157
void abs(Image< double > &op)
bool operator>=(const MDObject &obj) const
bool operator<(const MDObject &obj) const
MDLabelType type
bool eq(const MDObject &obj, double epsilon) const
#define i
doublereal * d
void copy(const MDObject &obj)
bool operator>(const MDObject &obj) const
bool fromStream(std::istream &is, bool fromString=false)
static MDLabelType labelType(const MDLabel label)
double vv
MDObject(const MDObject &obj)
MDLabel label
size_t longintValue
friend std::istream & operator>>(std::istream &is, MDObject &value)
std::vector< double > * vectorValue
ObjectData data
bool fromString(const String &str)
#define DOUBLE2STREAM(d)
bool operator!=(const MDObject &obj) const
bool fromChar(const char *str)
bool operator<=(const MDObject &obj) const
basic_istream< char, std::char_traits< char > > istream
Definition: utilities.cpp:815
String toString(bool withFormat=false, bool isSql=false) const
#define _QUOT
#define _SPACE
std::vector< float > * vectorValueFloat
std::string String
Definition: xmipp_strings.h:34
String formatString(const char *format,...)
void setValue(const int &iv)
void toStream(std::ostream &os, bool withFormat=false, bool isSql=false, bool escape=true) const
double doubleValue
bool operator==(const MDObject &obj) const
~MDObject()
Destructor.
void(* obj)()
static String label2Str(const MDLabel &label)
friend std::ostream & operator<<(std::ostream &is, const MDObject &value)
String * stringValue
double epsilon
#define MDOBJECT_INIT()
Macro to do some basic initialization.
MDLabel
MDObject & operator=(const MDObject &obj)
#define INT2STREAM(i)