我有一个字节矩阵,或者对于这个例子,我们可以假设我已经转换为 uint16。我很好奇如何将数据元素的子集复制到 MATLABString(即使用 mex C++ 接口)。我问 ChatGPT 但它使用的是 charArray 而不是字符串。看起来它最后还进行了不必要的数据复制(我可能是错的)。还不清楚为什么我需要迭代器,但这可能是因为我习惯于 C 并更多地使用指针。这是最好的方法吗?原始解决方案有一个循环来复制/转换每个元素,但我要求它使用
memcpy
,因为我的印象是 memcpy
可能更快,而且看起来它应该是复制大量元素的正确方法从一个数组到另一个数组的数据。
#include "mex.hpp"
#include "mexAdapter.hpp"
class MexFunction : public matlab::mex::Function {
public:
void operator()(matlab::mex::ArgumentList outputs, matlab::mex::ArgumentList inputs) override {
// Check input and output arguments
checkArguments(outputs, inputs);
// Get input arguments
matlab::data::TypedArray<uint16_t> data = std::move(inputs[0]);
double startIndex = inputs[1][0];
double endIndex = inputs[2][0];
size_t subsetLength = static_cast<size_t>(endIndex - startIndex + 1);
// Check bounds
size_t dataSize = data.getNumberOfElements();
if (startIndex < 1 || endIndex >= dataSize || startIndex > endIndex) {
matlab::engine::MATLABException::throwAsCaller("Subset indices are out of bounds.");
}
// Extract subset of uint16 array
matlab::data::TypedArray<uint16_t>::iterator subsetData = data.begin() + static_cast<size_t>(startIndex) - 1;
// Convert subset to character array using memcpy
std::string charArray(subsetLength, '\0');
memcpy(&charArray[0], subsetData, subsetLength * sizeof(uint16_t));
// Create MATLABString
outputs[0] = factory.createCharArray(charArray);
}
private:
matlab::data::ArrayFactory factory;
void checkArguments(matlab::mex::ArgumentList outputs, matlab::mex::ArgumentList inputs) {
if (inputs.size() != 3) {
matlab::engine::MATLABException::throwAsCaller("Three input arguments required.");
}
if (outputs.size() != 1) {
matlab::engine::MATLABException::throwAsCaller("One output argument required.");
}
if (!inputs[0].isUint16() || !inputs[1].isDouble() || !inputs[2].isDouble()) {
matlab::engine::MATLABException::throwAsCaller("Inputs must be uint16 and double arrays.");
}
}
};
这是我想出的答案。请注意,它不是高性能的(详细信息如下)。我也不是 C++ MATLAB 接口方面的专家,所以这主要仅供参考,希望它可以帮助其他人解决相关问题。
代码:
#include "mex.hpp"
#include "mexAdapter.hpp"
#include <cstring>
namespace md = matlab::data;
namespace mx = matlab::mex;
class MexFunction : public mx::Function {
md::ArrayFactory factory;
std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
public:
void operator()(mx::ArgumentList outputs, mx::ArgumentList inputs) {
checkArguments(outputs, inputs);
//Prep of the input
//--------------------------------
md::TypedArray<uint16_t> input_matrix = std::move(inputs[0]);
size_t n_rows = input_matrix.getDimensions()[0];
size_t n_cols = input_matrix.getDimensions()[1];
md::buffer_ptr_t<uint16_t> input_buffer = input_matrix.release();
uint16_t *input_pointer = (uint16_t *)input_buffer.get();
uint16_t *input_pointer2 = input_pointer;
//Prep of the output
//---------------------------------------------------
md::StringArray myArray = factory.createArray<md::MATLABString>({n_cols,1});
for (size_t i = 0; i < n_cols; ++i){
md::buffer_ptr_t<char16_t> temp_buffer = factory.createBuffer<char16_t>(n_rows);
std::memcpy(temp_buffer.get(), input_pointer2, n_rows*2);
myArray[i] = temp_buffer.get();
input_pointer2 += n_rows;
}
outputs[0] = myArray;
}
private:
void checkArguments(mx::ArgumentList outputs, mx::ArgumentList inputs) {
//https://www.mathworks.com/help/matlab/matlab_external/handling-inputs-and-outputs.html
if (inputs.size() != 1) {
mexErrMsgIdAndTxt(u"copy_test:invalid_input:one_input_check",u"there must be 1 input to copy_test4");
}
if (inputs[0].getType() != md::ArrayType::UINT16) {
mexErrMsgIdAndTxt(u"copy_test:invalid_input:uint16_check", u"Input must be a matrix of type uint16");
}
if (inputs[0].getDimensions().size() != 2) {
mexErrMsgIdAndTxt(u"copy_test:invalid_input:2d_check", u"Input must be a 2D matrix.");
}
if (outputs.size() != 1) {
mexErrMsgIdAndTxt(u"copy_test:invalid_input:one_output_check",u"there must be 1 output to copy_test4");
}
}
void mexErrMsgIdAndTxt(md::String id, md::String error_string){
matlabPtr->feval(u"error", 0, std::vector<md::Array>({factory.createScalar(id),factory.createScalar(error_string)}));
}
};
这是一些测试代码:
temp = reshape(uint16(41:1040),10,100);
temp = repmat(temp,1,10000);
N = 10;
tic
for i = 1:N
temp2 = copy_test5(temp);
end
toc/N
tic
for i = 1:N
temp3 = string(char(temp'));
end
toc/N
我没有方便的确切时间,但我们发现代码比简单调用
char
然后 string
慢两倍。我的猜测是,提供的方法有足够的开销,因此 mex 代码不值得。
我也打算将字符串剥离放入代码中,但决定不这样做,因为在 mex 中简单地从矩阵到单个字符串的转换太慢了。
在此过程中我会注意到,我忘记了运行此代码时的很多延迟涉及大量字符串分配,而不是其他因素。