I'm trying to build a managed wrapper for a native C++ class that holds an Eigen::MatrixXi
. Let's say the native class has one member matrix
that it stores and gets through its constructor, and a method that uses that member at a later time:
#include <Eigen/Dense>
#include <Eigen/Core>
#include <iostream>
using Eigen::MatrixXi;
class Foo
{
public:
const MatrixXi matrix;
Foo(const MatrixXi &matrix);
void Bar();
};
Foo::Foo(const MatrixXi &matrix)
: matrix(matrix) {}
void Foo::Bar()
{
for (int y = 0; y < matrix.rows(); y++)
{
for (int x = 0; x < matrix.cols(); x++)
{
std::cout << matrix(y, x);
}
std::cout << std::endl;
}
}
I made the following wrapper:
using namespace MathNet::Numerics::LinearAlgebra;
using namespace MathNet::Numerics::LinearAlgebra::Single;
template<class T>
public ref class ManagedObject
{
protected:
T* m_Instance;
public:
ManagedObject(T* instance)
: m_Instance(instance)
{
}
virtual ~ManagedObject()
{
if (m_Instance != nullptr)
{
delete m_Instance;
}
}
!ManagedObject()
{
if (m_Instance != nullptr)
{
delete m_Instance;
}
}
T* GetInstance()
{
return m_Instance;
}
};
public ref class ManagedFoo : public ManagedObject<Foo>
{
public:
ManagedFoo(MathNet::Numerics::LinearAlgebra::Matrix<float>^ matrix);
void Bar();
};
ManagedFoo::ManagedFoo(MathNet::Numerics::LinearAlgebra::Matrix<float>^ matrix)
: ManagedObject(new Foo(mathnet_to_eigen(matrix))) {}
void ManagedFoo::Bar()
{
m_Instance->Bar();
}
What would the mathnet_to_eigen
method look like? I've tried the following:
#include <vector>
#include <Eigen/Dense>
#include <Eigen/Core>
using Eigen::MatrixXi;
static Eigen::MatrixXi mathnet_to_eigen(MathNet::Numerics::LinearAlgebra::Matrix<float>^ data)
{
int length = data->RowCount * data->ColumnCount;
std::vector<int> data_converted(length);
for (size_t i = 0; i < data->RowCount; i++)
{
for (size_t j = 0; j < data->ColumnCount; j++)
{
data_converted[i * data->ColumnCount + j] = data[i, j];
}
}
Eigen::MatrixXi mat = Eigen::Map<Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>(&data_converted[0], data->RowCount, data->ColumnCount);
return mat;
}
This seems to work, but I'm uncertain about the memory management and efficiency. Should I use pinning? And what would that look like? I have the feeling that I'm not doing it correctly and might be using a pointer to memory that is garbage collected.
I don't care in this case about how the float to int conversion is done (rounding/taking integer part).
I found this to be the cleanest way to do it:
static Eigen::MatrixXf MathNetToEigen(MathNet::Numerics::LinearAlgebra::Matrix<float>^ data)
{
auto mat = Eigen::MatrixXf(data->RowCount, data->ColumnCount);
for (size_t i = 0; i < data->RowCount; i++)
for (size_t j = 0; j < data->ColumnCount; j++)
mat(i, j) = data[i, j];
return mat;
}
And converting back:
static MathNet::Numerics::LinearAlgebra::Matrix<float>^ EigenToMathNet(Eigen::MatrixXf& data)
{
auto mat = MathNet::Numerics::LinearAlgebra::Matrix<float>::Build->Dense(data.rows(), data.cols());
for (size_t i = 0; i < data.rows(); i++)
for (size_t j = 0; j < data.cols(); j++)
mat[i, j] = data(i, j);
return mat;
}