MATLAB ® Data API, используемый функциями C++ MEX, обеспечивает ту же семантику копирования при записи, что и функции, написанные непосредственно в MATLAB. Функция MEX может дублировать переданный ей массив данных, но этот дубликат является общей копией исходной переменной. Отдельная копия данных создается, когда функция MEX изменяет значения в массиве .
При вызове функции MEX matlab::data::Array входные данные являются общими копиями переменных MATLAB, передаваемых функции MEX. Общие копии обеспечивают преимущество, если функция MEX:
Не изменяет большой массив, переданный функции MEX.
Изменяет определенные поля структуры, передаваемые в качестве входных данных без создания копии всей структуры.
Модификация ячейки в массиве ячеек, передаваемой в качестве входных данных, без создания глубокой копии массива ячеек
Изменение свойства объекта, передаваемого в качестве входных данных без создания глубокой копии объекта.
В этом примере код получает преимущества от использования общих копий при вычислении среднего значения массива изображений. Копирование входного массива в const
matlab::data::TypedArray<T>, который поддерживает итераторы, позволяет использовать диапазон for для выполнения вычисления, но гарантирует, что массив не будет скопирован.
#include "mex.hpp"
#include "mexAdapter.hpp"
using matlab::mex::ArgumentList;
using namespace matlab::data;
class MexFunction : public matlab::mex::Function {
ArrayFactory factory;
public:
void operator()(ArgumentList outputs, ArgumentList inputs) {
double sm = 0;
const TypedArray<uint8_t> inArray = inputs[0];
for (auto& elem : inArray) {
sm += elem;
}
outputs[0] = factory.createScalar(sm / inArray.getNumberOfElements());
}
};Сохранение исходного кода функции MEX в файле с именем aveImage.cpp. Эту функцию можно использовать для поиска среднего значения массива топографических данных. Загрузить topo.mat в рабочую область MATLAB и передать массив данных функции MEX.
mex aveImage.cpp load topo d = uint8(topo); % convert data to use aveImage m = aveImage(d)
m = 73.5487
При передаче массива ячеек в функцию MEX, ее представление MATLAB Data API, matlab::data::CellArray, является по существу matlab::data::Array который содержит matlab::data::Array в каждой ячейке. Эта конструкция позволяет каждому содержащемуся массиву быть общей копией до тех пор, пока она не будет изменена.
При изменении ячейки массива ячеек в функции MEX только массив, содержащийся в этой ячейке, не используется совместно, а не весь массив ячеек. Например, предположим, что массив ячейки A копируется в массив ячейки B. Значение каждой ячейки является общим.

При изменении Cell1 в массиве B ячеек массив в этой ячейке больше не используется совместно с Cell1 в массиве ячеек A. Однако значения всех остальных ячеек остаются общими, поэтому копировать весь массив ячеек не требуется.

В этом примере показано, как передать массив ячеек функции MEX и изменить одну ячейку в массиве ячеек без создания копий данных в других ячейках. Пример загружает данные изображения в рабочую область MATLAB и создает массив ячеек, содержащий данные изображения, подписи и карту цветов.
load durer
whosName Size Bytes Class X 648x509 2638656 double caption 2x28 112 char map 128x3 3072 double
Назначьте каждую переменную отдельной ячейке.
durerCell{1} = X;
durerCell{2} = caption;
durerCell{3} = map;Эта функция MEX использует std::move для перемещения массива входных ячеек в matlab::data::CellArray, которая обеспечивает доступ к отдельным ячейкам. Единственными измененными данными являются подписи, хранящиеся в одной ячейке массива ячеек. Чтобы изменить эту ячейку, выполните следующие действия.
Получить matlab::data::Reference<TypedArray<T>> ссылка на массив в ячейке, содержащей подпись.
Назначение нового значения ссылке в качестве matlab::data::CharArray поскольку возвращаемое значение является символьным вектором MATLAB.
#include "mex.hpp"
#include "mexAdapter.hpp"
using matlab::mex::ArgumentList;
using namespace matlab::data;
class MexFunction : public matlab::mex::Function {
ArrayFactory factory;
public:
void operator()(ArgumentList outputs, ArgumentList inputs) {
checkArguments(inputs);
CellArray imageCell = std::move(inputs[0]);
TypedArrayRef<char16_t> cellRef = imageCell[1];
cellRef = factory.createCharArray("Albrecht Durer's Melancolia with a magic square" );
outputs[0] = imageCell;
}
void checkArguments(ArgumentList inputs) {
std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
if (inputs[0].getType() != ArrayType::CELL) {
matlabPtr->feval(u"error", 0, std::vector<Array>
({ factory.createScalar("Input must be cell array") }));
}
}
};Сохранить этот код в файле с именем modifyCellArray.cpp, создайте файл MEX и вызовите функцию.
mex modifyCellArray.cpp
durerCell = modifyCellArray(durerCell);Возвращенный массив ячеек содержит новый массив символов, назначенный в функции MEX.
durerCell{2}ans =
'Albrecht Durer's Melancolia with a magic square'Дополнительные сведения о работе с массивами ячеек см. в разделе Массивы ячеек C++.
API данных MATLAB определяет matlab::data::StructArray для представления MATLAB struct массивы. Каждое поле в StructArray сам содержит массив. Таким образом, можно изменить поле StructArray передается функции MEX без копирования всего массива. Поля, которые не были изменены, остаются общими с полями входного массива.
StructArray класс предоставляет функции-члены для доступа к полям структуры:
getFieldNames возвращает итераторы начала и конца, предоставляющие доступ к именам полей.
getNumberOfFields возвращает количество полей в структуре.
Например, можно создать вектор имен полей и использовать эти имена для доступа к данным в структуре. Этот код предполагает, что поле содержит массив типа double.
auto fields = myStruct.getFieldNames();
std::vector<matlab::data::MATLABFieldIdentifier> fieldNames(fields.begin(), fields.end());
// Get the data from one field
matlab::data::TypedArray<double> field1 = myStruct[0][fieldNames[0]]Назначение новых значений полю путем создания массива правильного типа.
myStruct[0][fieldNames[0]] = factory.createArray<double>({ 1,5 }, { 1, 2, 3, 4, 5 });Создание ссылки на поле структуры с помощью matlab::data::Reference<T>, которые можно передать функциям, получающим доступ к значениям в поле. Ссылки позволяют получить значение поля, назначить новое значение полю и создать другой массив, ссылающийся на это значение. Например, этот код создает ссылку на поле, содержащее массив двойников.
auto fields = myStruct.getFieldNames(); std::vector<matlab::data::MATLABFieldIdentifier> fieldNames(fields.begin(), fields.end()); matlab::data::TypedArrayRef<double> field1Reference = myStruct[0][fieldNames[0]]
Назначьте новые значения полю с помощью этой ссылки.
field1Reference = factory.createArray<double>({ 1,5 }, { 1, 2, 3, 4, 5 });В этом примере структура MATLAB передается функции MEX. Структура содержит два больших поля данных и два поля, содержащие скалярные значения, назначенные функцией MEX. Функция MEX вычисляет среднее значение для чисел в каждом массиве и присваивает эти значения Average поле соответствующей структуры.
Этот код MATLAB создает массив структуры и передает его функции MEX, созданной из modifyStruct.cpp файл, описанный здесь.
s = struct('Average',{[],[]},... 'Data',{rand(1,1000),randi([1,9],1,1000)}); s = modifyStruct(s);
Вот MexFunction::operator() функция. Он выполняет следующие операции:
Позвоните в checkArgument функция для проверки входов и выходов на размер и тип.
Назначение входных данных matlab::data::StructArray переменная.
Позвоните в calcMean для вычисления средних значений.
Назначьте обновленный массив структуры выходу функции MEX.
#include "mex.hpp"
#include "mexAdapter.hpp"
using matlab::mex::ArgumentList;
using namespace matlab::data;
class MexFunction : public matlab::mex::Function {
public:
void operator()(ArgumentList outputs, ArgumentList inputs) {
checkArguments(outputs, inputs);
StructArray inStruct(inputs[0]);
calcMean(inStruct);
outputs[0] = inStruct;
} checkArguments функция выполняет следующие проверки:
Количество входов равно единице.
Количество выходов не больше одного.
Входные данные представляют собой массив структуры MATLAB.
void checkArguments(ArgumentList outputs, ArgumentList inputs) {
std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
ArrayFactory factory;
if (inputs.size() != 1) {
matlabPtr->feval(u"error", 0,
std::vector<Array>({ factory.createScalar("One input required") }));
}
if (outputs.size() > 1) {
matlabPtr->feval(u"error", 0,
std::vector<Array>({ factory.createScalar("Too many outputs specified") }));
}
if (inputs[0].getType() != ArrayType::STRUCT) {
matlabPtr->feval(u"error", 0,
std::vector<Array>({ factory.createScalar("Input must be structure") }));
}
} calcMean функция вычисляет среднее значение для каждого набора чисел в Data и присваивает эти значения Average поле соответствующей структуры.
void calcMean(StructArray& inStruct) {
ArrayFactory factory;
auto fields = inStruct.getFieldNames();
std::vector<MATLABFieldIdentifier> fieldNames(fields.begin(), fields.end());
double sm = 0;
for (auto i = 0; i < 2; i++) {
const TypedArray<double> data = inStruct[i][fieldNames[1]];
for (auto& elem : data) {
sm += elem;
}
inStruct[i][fieldNames[0]] = factory.createScalar(sm / data.getNumberOfElements());
}
}
};Для связанного примера, в котором используются массивы ячеек и структур, откройте этот исходный файл в редакторе MATLAB. phonebook.cpp.
matlab::data::MATLABFieldIdentifier