matio-cpp  v0.2.6
A C++ wrapper of the matio library, with memory ownership handling, to read and write .mat files.
Variable.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2020 Fondazione Istituto Italiano di Tecnologia
3  *
4  * This software may be modified and distributed under the terms of the
5  * BSD-2-Clause license (https://opensource.org/licenses/BSD-2-Clause).
6  */
7 
8 #define _CRT_NONSTDC_NO_DEPRECATE //Silence warning on deprecation of strdup
9 
10 #include <matioCpp/Variable.h>
11 #include <matioCpp/CellArray.h>
12 #include <matioCpp/Struct.h>
13 #include <matioCpp/StructArray.h>
14 #include <matioCpp/Vector.h>
15 
16 bool matioCpp::Variable::initializeVariable(const std::string& name, const VariableType& variableType, const ValueType& valueType, matioCpp::Span<const size_t> dimensions, void* data)
17 {
18  std::string errorPrefix = "[ERROR][matioCpp::Variable::createVar] ";
19  if (name.empty())
20  {
21  std::cerr << errorPrefix << "The name should not be empty." << std::endl;
22  return false;
23  }
24 
25  if (dimensions.size() < 2)
26  {
27  std::cerr << errorPrefix << "The dimensions should be at least 2." << std::endl;
28  return false;
29  }
30 
31  matio_types matioType;
32  matio_classes matioClass;
33 
34  if(!get_matio_types(variableType, valueType, matioClass, matioType))
35  {
36  std::cerr << errorPrefix << "Either the variableType or the valueType are not supported." << std::endl;
37  return false;
38  }
39 
40  std::vector<size_t> dimensionsCopy;
41  dimensionsCopy.assign(dimensions.begin(), dimensions.end()); //This is needed since Mat_VarCreate needs a non-const pointer for the dimensions. This method already allocates memory
42 
43  int flags = 0;
44 
46  {
47  flags = flags | matio_flags::MAT_F_LOGICAL;
48  }
49 
50  matvar_t* newPtr = Mat_VarCreate(name.c_str(), matioClass, matioType, static_cast<int>(dimensionsCopy.size()), dimensionsCopy.data(), data, flags);
51 
52  if (m_handler)
53  {
54  if (!m_handler->importMatvar(newPtr))
55  {
56  std::cerr << errorPrefix << "Failed to modify the variable." << std::endl;
58  return false;
59  }
60  }
61  else
62  {
63  m_handler = new matioCpp::SharedMatvar(newPtr);
64  }
65 
66  if (!m_handler || !m_handler->get())
67  {
68  std::cerr << errorPrefix << "Failed to create the variable." << std::endl;
69  return false;
70  }
71 
72  return true;
73 }
74 
75 bool matioCpp::Variable::initializeComplexVariable(const std::string& name, const VariableType& variableType, const ValueType& valueType, matioCpp::Span<const size_t> dimensions, void *realData, void *imaginaryData)
76 {
77  std::string errorPrefix = "[ERROR][matioCpp::Variable::createComplexVar] ";
78  if (name.empty())
79  {
80  std::cerr << errorPrefix << "The name should not be empty." << std::endl;
81  return false;
82  }
83 
84  if (dimensions.size() < 2)
85  {
86  std::cerr << errorPrefix << "The dimensions should be at least 2." << std::endl;
87  return false;
88  }
89 
90  if (!realData)
91  {
92  std::cerr << errorPrefix << "The real data pointer is empty." << std::endl;
93  return false;
94  }
95 
96  if (!imaginaryData)
97  {
98  std::cerr << errorPrefix << "The imaginary data pointer is empty." << std::endl;
99  return false;
100  }
101 
102  matio_types matioType;
103  matio_classes matioClass;
104 
105  if (!get_matio_types(variableType, valueType, matioClass, matioType))
106  {
107  std::cerr << errorPrefix << "Either the variableType or the valueType are not supported." << std::endl;
108  return false;
109  }
110 
111  mat_complex_split_t matioComplexSplit;
112  matioComplexSplit.Re = realData;
113  matioComplexSplit.Im = imaginaryData;
114 
115  std::vector<size_t> dimensionsCopy;
116  dimensionsCopy.assign(dimensions.begin(), dimensions.end()); //This is needed since Mat_VarCreate needs a non-const pointer for the dimensions. This method already allocates memory
117 
118  int flags = MAT_F_COMPLEX;
119 
120  if (valueType == matioCpp::ValueType::LOGICAL)
121  {
122  flags = flags | matio_flags::MAT_F_LOGICAL;
123  }
124 
125  matvar_t* newPtr = Mat_VarCreate(name.c_str(), matioClass, matioType, static_cast<int>(dimensionsCopy.size()), dimensionsCopy.data(), &matioComplexSplit, flags); //Data is hard copied, since the flag MAT_F_DONT_COPY_DATA is not used
126 
127  if (m_handler)
128  {
129  if (!m_handler->importMatvar(newPtr))
130  {
131  std::cerr << errorPrefix << "Failed to modify the variable." << std::endl;
133  return false;
134  }
135  }
136  else
137  {
138  m_handler = new matioCpp::SharedMatvar(newPtr);
139  }
140 
141  if (!m_handler || !m_handler->get())
142  {
143  std::cerr << errorPrefix << "Failed to create the variable." << std::endl;
144  return false;
145  }
146 
147  return true;
148 }
149 
151 {
152  if (!isValid())
153  {
154  return false;
155  }
156 
157  char* previousName = m_handler->get()->name;
158 
159  if (previousName)
160  {
161  free(previousName);
162  }
163 
164  m_handler->get()->name = strdup(newName.c_str());
165 
166  return (name() == newName);
167 }
168 
170 {
171  size_t totalElements = 1;
172  for (size_t dim : dimensions())
173  {
174  totalElements *= dim;
175  }
176 
177  return totalElements;
178 }
179 
180 bool matioCpp::Variable::setCellElement(size_t linearIndex, const matioCpp::Variable &newValue)
181 {
182  if (!isValid())
183  {
184  std::cerr << "[ERROR][matioCpp::Variable::setCellElement] The variable is not valid." << std::endl;
185  return false;
186  }
187 
188  Variable copiedNonOwning(matioCpp::WeakMatvar(matioCpp::MatvarHandler::GetMatvarDuplicate(newValue.toMatio()), m_handler));
189  if (!copiedNonOwning.isValid())
190  {
191  std::cerr << "[ERROR][matioCpp::Variable::setCellElement] Could not copy the new value. ";
192  if (!newValue.isValid())
193  {
194  std::cerr << "The new value is not valid. " << std::endl;
195  }
196  else
197  {
198  std::cerr << "Matio internal problem. " << std::endl;
199  }
200  return false;
201  }
202 
203  matvar_t* previousCell = Mat_VarSetCell(m_handler->get(), static_cast<int>(linearIndex), copiedNonOwning.toMatio());
204 
205  m_handler->dropOwnedPointer(previousCell); //This avoids that any variable that was using this pointer before tries to access it.
206  MatvarHandler::DeleteMatvar(previousCell);
207 
208  return Mat_VarGetCell(m_handler->get(), static_cast<int>(linearIndex));
209 }
210 
212 {
213  assert(isValid());
214  return Variable(matioCpp::WeakMatvar(Mat_VarGetCell(m_handler->get(), static_cast<int>(linearIndex)), m_handler));
215 }
216 
218 {
219  assert(isValid());
220  return Variable(matioCpp::WeakMatvar(Mat_VarGetCell(m_handler->get(), static_cast<int>(linearIndex)), m_handler));
221 }
222 
224 {
225  assert(isValid());
226  return Mat_VarGetNumberOfFields(m_handler->get());
227 }
228 
230 {
231  assert(isValid());
232  return Mat_VarGetStructFieldnames(m_handler->get());
233 }
234 
235 bool matioCpp::Variable::getStructFieldIndex(const std::string& field, size_t& index) const
236 {
237  size_t i = 0;
238  size_t numberOfFields = getStructNumberOfFields();
239  char * const * fields = getStructFields();
240  index = numberOfFields;
241 
242  if (!fields)
243  {
244  return false;
245  }
246 
247  while (i < numberOfFields && (strcmp(fields[i], field.c_str()) != 0))
248  {
249  ++i;
250  }
251 
252  index = i;
253 
254  return index < numberOfFields;
255 }
256 
257 bool matioCpp::Variable::setStructField(size_t index, const matioCpp::Variable &newValue, size_t structPositionInArray)
258 {
259  if (!isValid())
260  {
261  std::cerr << "[ERROR][matioCpp::Variable::setStructField] The variable is not valid." << std::endl;
262  return false;
263  }
264 
265  if (!m_handler->isShared())
266  {
267  std::cerr << "[ERROR][matioCpp::Variable::setStructField] Cannot set the field if the variable is not owning the memory." << std::endl;
268  return false;
269  }
270 
271  Variable copiedNonOwning(matioCpp::WeakMatvar(matioCpp::MatvarHandler::GetMatvarDuplicate(newValue.toMatio()), m_handler));
272  if (!copiedNonOwning.isValid())
273  {
274  return false;
275  }
276 
277  matvar_t* previousField = Mat_VarSetStructFieldByIndex(m_handler->get(), index, structPositionInArray, copiedNonOwning.toMatio());
278 
279  m_handler->dropOwnedPointer(previousField); //This avoids that any variable that was using this pointer before tries to access it.
280  MatvarHandler::DeleteMatvar(previousField);
281 
282  return Mat_VarGetStructFieldByIndex(m_handler->get(), index, structPositionInArray);
283 }
284 
286 {
287  if (!isValid())
288  {
289  std::cerr << "[ERROR][matioCpp::Variable::addStructField] The variable is not valid." << std::endl;
290  return false;
291  }
292 
293  if (m_handler->isShared()) //This means that the variable is not part of an array
294  {
295  int err = Mat_VarAddStructField(m_handler->get(), newField.c_str());
296 
297  if (err)
298  {
299  return false;
300  }
301  }
302  else
303  {
304  return false;
305  }
306 
307  return true;
308 }
309 
310 bool matioCpp::Variable::setStructField(const std::string& field, const matioCpp::Variable &newValue, size_t structPositionInArray)
311 {
312  if (!isValid())
313  {
314  std::cerr << "[ERROR][matioCpp::Variable::setStructField] The variable is not valid." << std::endl;
315  return false;
316  }
317 
318  size_t fieldindex;
319 
320  if (!getStructFieldIndex(field, fieldindex) && !((getArrayNumberOfElements() == 1) && addStructField(field)))
321  {
322  //This is the case when the field has not been found and, either there are more than one elements (i.e. it is part of an array), or there was an error in adding the field
323  return false;
324  }
325  //If it was not found, but the field has been added, the fieldindex is the last one
326 
327  return setStructField(fieldindex, newValue, structPositionInArray);
328 }
329 
330 matioCpp::Variable matioCpp::Variable::getStructField(size_t index, size_t structPositionInArray)
331 {
332  assert(isValid());
333  return Variable(matioCpp::WeakMatvar(Mat_VarGetStructFieldByIndex(m_handler->get(), index, structPositionInArray), m_handler));
334 }
335 
336 const matioCpp::Variable matioCpp::Variable::getStructField(size_t index, size_t structPositionInArray) const
337 {
338  assert(isValid());
339  return Variable(matioCpp::WeakMatvar(Mat_VarGetStructFieldByIndex(m_handler->get(), index, structPositionInArray), m_handler));
340 }
341 
343 {
344  assert(isValid());
345 
346  size_t numberOfFields = getStructNumberOfFields();
347  std::vector<matvar_t*> fields(numberOfFields + 1, nullptr);
348  for (size_t field = 0; field < numberOfFields; ++field)
349  {
350  fields[field] = Mat_VarGetStructFieldByIndex(m_handler->get(), field, linearIndex);
351  }
352  std::string newName = name() + std::to_string(linearIndex);
353  size_t dimensions[] = {1,1};
354  matvar_t* rawStruct = Mat_VarCreate(newName.c_str(), matio_classes::MAT_C_STRUCT, matio_types::MAT_T_STRUCT, 2, dimensions, fields.data(), MAT_F_DONT_COPY_DATA);
356 }
357 
359 {
360  assert(isValid());
361 
362  size_t numberOfFields = getStructNumberOfFields();
363  std::vector<matvar_t*> fields(numberOfFields + 1, nullptr);
364  for (size_t field = 0; field < numberOfFields; ++field)
365  {
366  fields[field] = Mat_VarGetStructFieldByIndex(m_handler->get(), field, linearIndex);
367  }
368  std::string newName = name() + "_" + std::to_string(linearIndex);
369  size_t dimensions[] = {1,1};
370  matvar_t* rawStruct = Mat_VarCreate(newName.c_str(), matio_classes::MAT_C_STRUCT, matio_types::MAT_T_STRUCT, 2, dimensions, fields.data(), MAT_F_DONT_COPY_DATA);
372 }
373 
375 {
376  return inputPtr;
377 }
378 
380  : m_handler(new matioCpp::SharedMatvar())
381 {
382 
383 }
384 
385 matioCpp::Variable::Variable(const matvar_t *inputVar)
386  : m_handler(new matioCpp::SharedMatvar())
387 {
388  m_handler->duplicateMatvar(inputVar);
389 }
390 
392  : m_handler(new matioCpp::SharedMatvar())
393 {
394  if (other.isValid())
395  {
396  m_handler->duplicateMatvar(other.toMatio());
397  }
398 }
399 
401 {
402  m_handler = other.m_handler;
403  other.m_handler = nullptr;
404 }
405 
407  : m_handler(handler.pointerToDuplicate())
408 {
409 
410 }
411 
413 {
414  if (m_handler)
415  {
416  delete m_handler;
417  }
418  m_handler = nullptr;
419 }
420 
422 {
423  bool ok = fromOther(other);
424  assert(ok);
425  matioCpp::unused(ok);
426  return *this;
427 }
428 
430 {
431  bool ok = fromOther(std::forward<matioCpp::Variable>(other));
432  assert(ok);
433  matioCpp::unused(ok);
434  return *this;
435 }
436 
437 bool matioCpp::Variable::fromMatio(const matvar_t *inputVar)
438 {
439  if (!inputVar)
440  {
441  std::cerr << "[matioCpp::Variable::fromMatio] The input pointer is null." << std::endl;
442  return false;
443  }
444 
447  get_types_from_matvart(inputVar, outputVariableType, outputValueType);
448 
449  if (!checkCompatibility(inputVar, outputVariableType, outputValueType))
450  {
451  return false;
452  }
453 
454  return m_handler->duplicateMatvar(inputVar);
455 }
456 
458 {
459  return fromMatio(other.toMatio());
460 }
461 
463 {
464  if (!other.isValid())
465  {
466  std::cerr << "[matioCpp::Variable::fromOther] The input variable is not valid." << std::endl;
467  return false;
468  }
469 
470  if (!checkCompatibility(other.toMatio(), other.variableType(), other.valueType()))
471  {
472  return false;
473  }
474 
475  if (m_handler)
476  {
477  delete m_handler;
478  }
479  m_handler = other.m_handler;
480  other.m_handler = nullptr;
481  return isValid();
482 }
483 
484 const matvar_t *matioCpp::Variable::toMatio() const
485 {
486  assert(isValid());
487 
488  return m_handler->get();
489 }
490 
492 {
493  assert(isValid());
494 
495  return m_handler->get();
496 }
497 
499 {
500  if (isValid())
501  {
502  return m_handler->get()->name;
503  }
504  else
505  {
506  return "";
507  }
508 }
509 
511 {
512  return m_handler->variableType();
513 }
514 
516 {
517  return m_handler->valueType();
518 }
519 
521 {
522  if (isValid())
523  {
524  return m_handler->get()->isComplex;
525  }
526  else
527  {
528  return false;
529  }
530 }
531 
533 {
534  assert(isValid());
535 
536  if (isValid())
537  {
538  return matioCpp::make_span(m_handler->get()->dims, m_handler->get()->rank);
539  }
540  else
541  {
543  }
544 }
545 
547 {
548  return m_handler->get() && checkCompatibility(m_handler->get(), m_handler->variableType(), m_handler->valueType());
549 }
550 
552 {
553  if (variableType() != matioCpp::VariableType::Struct)
554  {
555  std::cerr << "[ERROR][matioCpp::Variable::operator[]] The operator[](string) can be used only with structs." << std::endl;
556  assert(false);
557  return matioCpp::Variable();
558  }
559  size_t index;
560  if (!getStructFieldIndex(el, index))
561  {
562  std::cerr << "[ERROR][matioCpp::Variable::operator[]] The field " << el << " does not exist." << std::endl;
563  assert(false);
564  return matioCpp::Variable();
565  }
566  return getStructField(index);
567 }
568 
570 {
571  if (variableType() != matioCpp::VariableType::Struct)
572  {
573  std::cerr << "[ERROR][matioCpp::Variable::operator[]] The operator[](string) can be used only with structs." << std::endl;
574  assert(false);
575  return matioCpp::Variable();
576  }
577  size_t index;
578  if (!getStructFieldIndex(el, index))
579  {
580  std::cerr << "[ERROR][matioCpp::Variable::operator[]] The field " << el << " does not exist." << std::endl;
581  assert(false);
582  return matioCpp::Variable();
583  }
584  return getStructField(index);
585 }
586 
588 {
589  return matioCpp::CellArray(*m_handler);
590 }
591 
593 {
594  return matioCpp::CellArray(*m_handler);
595 }
596 
598 {
599  return matioCpp::Struct(*m_handler);
600 }
601 
603 {
604  return matioCpp::Struct(*m_handler);
605 }
606 
608 {
609  return matioCpp::StructArray(*m_handler);
610 }
611 
613 {
614  return matioCpp::StructArray(*m_handler);
615 }
616 
618 {
619  return matioCpp::Vector<char>(*m_handler);
620 }
621 
623 {
624  return matioCpp::Vector<char>(*m_handler);
625 }
626 
628 {
629  return matioCpp::Vector<char16_t>(*m_handler);
630 }
631 
633 {
634  return matioCpp::Vector<char16_t>(*m_handler);
635 }
636 
638 {
639  return matioCpp::Vector<char32_t>(*m_handler);
640 }
641 
643 {
644  return matioCpp::Vector<char32_t>(*m_handler);
645 }
T assign(T... args)
T c_str(T... args)
CellArray is a particular type of Variable specialized for cell arrays.
Definition: CellArray.h:18
virtual bool duplicateMatvar(const matvar_t *inputPtr)=0
Perform a deep copy of the input pointer.
static matvar_t * GetMatvarDuplicate(const matvar_t *inputPtr)
Get a duplicate of the input matvar pointer/.
virtual bool importMatvar(matvar_t *inputPtr)=0
Import the input pointer.
static void DeleteMatvar(matvar_t *pointerToDelete, DeleteMode mode=DeleteMode::Delete)
Delete the specified Matvar.
virtual matvar_t * get() const =0
Get the shared matvar_t pointer.
MATIOCPP_CONSTEXPR iterator begin() const noexcept
Definition: Span.h:553
MATIOCPP_CONSTEXPR index_type size() const noexcept
Definition: Span.h:526
MATIOCPP_CONSTEXPR iterator end() const noexcept
Definition: Span.h:554
StructArray is a particular type of Variable specialized for array of structs.
Definition: StructArray.h:21
Struct is a particular type of Variable specialized for structs.
Definition: Struct.h:18
The matioCpp::Variable class is the equivalent of matvar_t in matio.
Definition: Variable.h:23
bool setStructField(size_t index, const Variable &newValue, size_t structPositionInArray=0)
Set the field of the struct at the specified position.
Definition: Variable.cpp:257
matioCpp::String16 asString16()
Cast the variable as a String16.
Definition: Variable.cpp:627
Struct getStructArrayElement(size_t linearIndex)
Get an element of the variable, considered as a StructArray.
Definition: Variable.cpp:342
char *const * getStructFields() const
Get the list of fields in the variable, considered as a struct.
Definition: Variable.cpp:229
bool getStructFieldIndex(const std::string &field, size_t &index) const
Get the index of the specified field in the variable, considered as a struct.
Definition: Variable.cpp:235
matioCpp::String32 asString32()
Cast the variable as a String32.
Definition: Variable.cpp:637
size_t getArrayNumberOfElements() const
Get the total number of elements in the array.
Definition: Variable.cpp:169
Variable & operator=(const Variable &other)
Copy assignement.
Definition: Variable.cpp:421
Variable()
Default constructor.
Definition: Variable.cpp:379
matioCpp::StructArray asStructArray()
Cast the variable as a StructArray.
Definition: Variable.cpp:607
bool setCellElement(size_t linearIndex, const Variable &newValue)
Set a cell element at a specified linear position.
Definition: Variable.cpp:180
size_t getStructNumberOfFields() const
Get the total number of fields in the variable, considered as a struct.
Definition: Variable.cpp:223
~Variable()
Destructor.
Definition: Variable.cpp:412
std::string name() const
Get the name of the Variable.
Definition: Variable.cpp:498
virtual bool checkCompatibility(const matvar_t *inputPtr, matioCpp::VariableType variableType, matioCpp::ValueType valueType) const
Check if an input matio pointer is compatible with the specified variable.
Definition: Variable.cpp:374
bool addStructField(const std::string &newField)
Add a new field to the variable, considered as a struct.
Definition: Variable.cpp:285
const matvar_t * toMatio() const
Convert this Variable to a matio variable.
Definition: Variable.cpp:484
bool changeName(const std::string &newName)
Change the name of the variable.
Definition: Variable.cpp:150
bool fromMatio(const matvar_t *inputVar)
Set this variable from an existing matio variable.
Definition: Variable.cpp:437
matioCpp::Span< const size_t > dimensions() const
Get the dimensions of this object.
Definition: Variable.cpp:532
bool isValid() const
Check if the variable is valid.
Definition: Variable.cpp:546
matioCpp::VariableType variableType() const
Get the VariableType.
Definition: Variable.cpp:510
bool fromOther(const Variable &other)
Set this variable from another variable.
Definition: Variable.cpp:457
matioCpp::Variable operator[](const std::string &el)
Access field with specific name.
Definition: Variable.cpp:551
bool initializeVariable(const std::string &name, const VariableType &variableType, const ValueType &valueType, matioCpp::Span< const size_t > dimensions, void *data)
Initialize the variable.
Definition: Variable.cpp:16
matioCpp::ValueType valueType() const
Get the ValueType.
Definition: Variable.cpp:515
Variable getCellElement(size_t linearIndex)
Get a cell element at a specified linear position.
Definition: Variable.cpp:211
Variable getStructField(size_t index, size_t structPositionInArray=0)
Get the specified field in the variable, considered as a struct.
Definition: Variable.cpp:330
bool isComplex() const
Get if the variable is complex.
Definition: Variable.cpp:520
matioCpp::CellArray asCellArray()
Cast the variable as a CellArray.
Definition: Variable.cpp:587
matioCpp::Struct asStruct()
Cast the variable as a Struct.
Definition: Variable.cpp:597
bool initializeComplexVariable(const std::string &name, const VariableType &variableType, const ValueType &valueType, matioCpp::Span< const size_t > dimensions, void *realData, void *imaginaryData)
Initialize a complex variable.
Definition: Variable.cpp:75
matioCpp::String asString()
Cast the variable as a String.
Definition: Variable.cpp:617
Vector is a particular type of Variable specialized for 1-D arrays of a generic type T.
Definition: Vector.h:23
T data(T... args)
T empty(T... args)
T endl(T... args)
MATIOCPP_CONSTEXPR Span< ElementType > make_span(ElementType *ptr, typename Span< ElementType >::index_type count)
Definition: Span.h:714
@ Delete
The handler deletes the pointer but not the data.
bool get_matio_types(const VariableType &inputVariableType, const ValueType &inputValueType, matio_classes &outputMatioClasses, matio_types &outputMatioType)
Get both the matio type and class from the input VariableType and ValueType.
void unused(Args &&...)
Utility metafunction to avoid compiler warnings about unused variables.
VariableType
Define the type of variable.
bool get_types_from_matvart(const matvar_t *input, VariableType &outputVariableType, ValueType &outputValueType)
Get the VariableType and the ValueType from a matvar_t pointer.
ValueType
The list of types for an element of a certain variable type.
T size(T... args)
T to_string(T... args)