matio-cpp  v0.2.5
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 
236 {
237  size_t i = 0;
238  size_t numberOfFields = getStructNumberOfFields();
239  char * const * fields = getStructFields();
240 
241  if (!fields)
242  {
243  return numberOfFields;
244  }
245 
246  while (i < numberOfFields && (strcmp(fields[i], field.c_str()) != 0))
247  {
248  ++i;
249  }
250 
251  return i;
252 }
253 
254 bool matioCpp::Variable::setStructField(size_t index, const matioCpp::Variable &newValue, size_t structPositionInArray)
255 {
256  if (!isValid())
257  {
258  std::cerr << "[ERROR][matioCpp::Variable::setStructField] The variable is not valid." << std::endl;
259  return false;
260  }
261 
262  if (!m_handler->isShared())
263  {
264  std::cerr << "[ERROR][matioCpp::Variable::setStructField] Cannot set the field if the variable is not owning the memory." << std::endl;
265  return false;
266  }
267 
268  Variable copiedNonOwning(matioCpp::WeakMatvar(matioCpp::MatvarHandler::GetMatvarDuplicate(newValue.toMatio()), m_handler));
269  if (!copiedNonOwning.isValid())
270  {
271  return false;
272  }
273 
274  matvar_t* previousField = Mat_VarSetStructFieldByIndex(m_handler->get(), index, structPositionInArray, copiedNonOwning.toMatio());
275 
276  m_handler->dropOwnedPointer(previousField); //This avoids that any variable that was using this pointer before tries to access it.
277  MatvarHandler::DeleteMatvar(previousField);
278 
279  return Mat_VarGetStructFieldByIndex(m_handler->get(), index, structPositionInArray);
280 }
281 
283 {
284  if (!isValid())
285  {
286  std::cerr << "[ERROR][matioCpp::Variable::addStructField] The variable is not valid." << std::endl;
287  return false;
288  }
289 
290  if (m_handler->isShared()) //This means that the variable is not part of an array
291  {
292  int err = Mat_VarAddStructField(m_handler->get(), newField.c_str());
293 
294  if (err)
295  {
296  return false;
297  }
298  }
299  else
300  {
301  return false;
302  }
303 
304  return true;
305 }
306 
307 bool matioCpp::Variable::setStructField(const std::string& field, const matioCpp::Variable &newValue, size_t structPositionInArray)
308 {
309  if (!isValid())
310  {
311  std::cerr << "[ERROR][matioCpp::Variable::setStructField] The variable is not valid." << std::endl;
312  return false;
313  }
314 
315  size_t fieldindex = getStructFieldIndex(field);
316 
317  if ((fieldindex == getStructNumberOfFields()) && !((getArrayNumberOfElements() == 1) && addStructField(field)))
318  {
319  //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
320  return false;
321  }
322 
323  return setStructField(fieldindex, newValue, structPositionInArray);
324 }
325 
326 matioCpp::Variable matioCpp::Variable::getStructField(size_t index, size_t structPositionInArray)
327 {
328  assert(isValid());
329  return Variable(matioCpp::WeakMatvar(Mat_VarGetStructFieldByIndex(m_handler->get(), index, structPositionInArray), m_handler));
330 }
331 
332 const matioCpp::Variable matioCpp::Variable::getStructField(size_t index, size_t structPositionInArray) const
333 {
334  assert(isValid());
335  return Variable(matioCpp::WeakMatvar(Mat_VarGetStructFieldByIndex(m_handler->get(), index, structPositionInArray), m_handler));
336 }
337 
339 {
340  assert(isValid());
341 
342  size_t numberOfFields = getStructNumberOfFields();
343  std::vector<matvar_t*> fields(numberOfFields + 1, nullptr);
344  for (size_t field = 0; field < numberOfFields; ++field)
345  {
346  fields[field] = Mat_VarGetStructFieldByIndex(m_handler->get(), field, linearIndex);
347  }
348  std::string newName = name() + std::to_string(linearIndex);
349  size_t dimensions[] = {1,1};
350  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);
352 }
353 
355 {
356  assert(isValid());
357 
358  size_t numberOfFields = getStructNumberOfFields();
359  std::vector<matvar_t*> fields(numberOfFields + 1, nullptr);
360  for (size_t field = 0; field < numberOfFields; ++field)
361  {
362  fields[field] = Mat_VarGetStructFieldByIndex(m_handler->get(), field, linearIndex);
363  }
364  std::string newName = name() + "_" + std::to_string(linearIndex);
365  size_t dimensions[] = {1,1};
366  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);
368 }
369 
371 {
372  return inputPtr;
373 }
374 
376  : m_handler(new matioCpp::SharedMatvar())
377 {
378 
379 }
380 
381 matioCpp::Variable::Variable(const matvar_t *inputVar)
382  : m_handler(new matioCpp::SharedMatvar())
383 {
384  m_handler->duplicateMatvar(inputVar);
385 }
386 
388  : m_handler(new matioCpp::SharedMatvar())
389 {
390  if (other.isValid())
391  {
392  m_handler->duplicateMatvar(other.toMatio());
393  }
394 }
395 
397 {
398  m_handler = other.m_handler;
399  other.m_handler = nullptr;
400 }
401 
403  : m_handler(handler.pointerToDuplicate())
404 {
405 
406 }
407 
409 {
410  if (m_handler)
411  {
412  delete m_handler;
413  }
414  m_handler = nullptr;
415 }
416 
418 {
419  bool ok = fromOther(other);
420  assert(ok);
421  matioCpp::unused(ok);
422  return *this;
423 }
424 
426 {
427  bool ok = fromOther(std::forward<matioCpp::Variable>(other));
428  assert(ok);
429  matioCpp::unused(ok);
430  return *this;
431 }
432 
433 bool matioCpp::Variable::fromMatio(const matvar_t *inputVar)
434 {
435  if (!inputVar)
436  {
437  std::cerr << "[matioCpp::Variable::fromMatio] The input pointer is null." << std::endl;
438  return false;
439  }
440 
443  get_types_from_matvart(inputVar, outputVariableType, outputValueType);
444 
445  if (!checkCompatibility(inputVar, outputVariableType, outputValueType))
446  {
447  return false;
448  }
449 
450  return m_handler->duplicateMatvar(inputVar);
451 }
452 
454 {
455  return fromMatio(other.toMatio());
456 }
457 
459 {
460  if (!other.isValid())
461  {
462  std::cerr << "[matioCpp::Variable::fromOther] The input variable is not valid." << std::endl;
463  return false;
464  }
465 
466  if (!checkCompatibility(other.toMatio(), other.variableType(), other.valueType()))
467  {
468  return false;
469  }
470 
471  if (m_handler)
472  {
473  delete m_handler;
474  }
475  m_handler = other.m_handler;
476  other.m_handler = nullptr;
477  return isValid();
478 }
479 
480 const matvar_t *matioCpp::Variable::toMatio() const
481 {
482  assert(isValid());
483 
484  return m_handler->get();
485 }
486 
488 {
489  assert(isValid());
490 
491  return m_handler->get();
492 }
493 
495 {
496  if (isValid())
497  {
498  return m_handler->get()->name;
499  }
500  else
501  {
502  return "";
503  }
504 }
505 
507 {
508  return m_handler->variableType();
509 }
510 
512 {
513  return m_handler->valueType();
514 }
515 
517 {
518  if (isValid())
519  {
520  return m_handler->get()->isComplex;
521  }
522  else
523  {
524  return false;
525  }
526 }
527 
529 {
530  assert(isValid());
531 
532  if (isValid())
533  {
534  return matioCpp::make_span(m_handler->get()->dims, m_handler->get()->rank);
535  }
536  else
537  {
539  }
540 }
541 
543 {
544  return m_handler->get() && checkCompatibility(m_handler->get(), m_handler->variableType(), m_handler->valueType());
545 }
546 
548 {
549  return matioCpp::CellArray(*m_handler);
550 }
551 
553 {
554  return matioCpp::CellArray(*m_handler);
555 }
556 
558 {
559  return matioCpp::Struct(*m_handler);
560 }
561 
563 {
564  return matioCpp::Struct(*m_handler);
565 }
566 
568 {
569  return matioCpp::StructArray(*m_handler);
570 }
571 
573 {
574  return matioCpp::StructArray(*m_handler);
575 }
576 
578 {
579  return matioCpp::Vector<char>(*m_handler);
580 }
581 
583 {
584  return matioCpp::Vector<char>(*m_handler);
585 }
586 
588 {
589  return matioCpp::Vector<char16_t>(*m_handler);
590 }
591 
593 {
594  return matioCpp::Vector<char16_t>(*m_handler);
595 }
596 
598 {
599  return matioCpp::Vector<char32_t>(*m_handler);
600 }
601 
603 {
604  return matioCpp::Vector<char32_t>(*m_handler);
605 }
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:254
matioCpp::String16 asString16()
Cast the variable as a String16.
Definition: Variable.cpp:587
Struct getStructArrayElement(size_t linearIndex)
Get an element of the variable, considered as a StructArray.
Definition: Variable.cpp:338
char *const * getStructFields() const
Get the list of fields in the variable, considered as a struct.
Definition: Variable.cpp:229
matioCpp::String32 asString32()
Cast the variable as a String32.
Definition: Variable.cpp:597
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:417
Variable()
Default constructor.
Definition: Variable.cpp:375
matioCpp::StructArray asStructArray()
Cast the variable as a StructArray.
Definition: Variable.cpp:567
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:408
std::string name() const
Get the name of the Variable.
Definition: Variable.cpp:494
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:370
bool addStructField(const std::string &newField)
Add a new field to the variable, considered as a struct.
Definition: Variable.cpp:282
const matvar_t * toMatio() const
Convert this Variable to a matio variable.
Definition: Variable.cpp:480
size_t getStructFieldIndex(const std::string &field) const
Get the index of the specified field in the variable, considered as a struct.
Definition: Variable.cpp:235
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:433
matioCpp::Span< const size_t > dimensions() const
Get the dimensions of this object.
Definition: Variable.cpp:528
bool isValid() const
Check if the variable is valid.
Definition: Variable.cpp:542
matioCpp::VariableType variableType() const
Get the VariableType.
Definition: Variable.cpp:506
bool fromOther(const Variable &other)
Set this variable from another variable.
Definition: Variable.cpp:453
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:511
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:326
bool isComplex() const
Get if the variable is complex.
Definition: Variable.cpp:516
matioCpp::CellArray asCellArray()
Cast the variable as a CellArray.
Definition: Variable.cpp:547
matioCpp::Struct asStruct()
Cast the variable as a Struct.
Definition: Variable.cpp:557
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:577
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)