Skip to content

Commit

Permalink
fix warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
pthom committed Feb 13, 2024
1 parent 478a5d4 commit 4eede85
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 109 deletions.
220 changes: 112 additions & 108 deletions cvnp/cvnp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,130 +113,134 @@ namespace cvnp
return true;
}

//
// This class is a MatAllocator that uses a numpy array as the data pointer
// --------------------------------------------------------------------------------------------
// The implementation is quite tricky:
// - A collection of all instances is kept in a static vector (see register_instance and unregister_instance)
// - The constructor:
// * keeps a reference to the numpy array
// * registers itself via register_instance()
// - allocate:
// * creates a new UMatData object
// "steals" the data pointer from the numpy array
// - deallocate will:
// * decrements the reference count and deletes the UMatData object if no more references
// * unregisters itself via unregister_instance() which will *destroy* this instance!
// *The destructor is called via deallocate()*
//
// As a consequence, MatAllocator_LinkArray is created via a *naked* new() and will be destroyed via deallocate()
//
namespace // anonymous namespace to hide MatAllocator_LinkArray from other translation units
{
//
// This class is a MatAllocator that uses a numpy array as the data pointer
// --------------------------------------------------------------------------------------------
// The implementation is quite tricky:
// - A collection of all instances is kept in a static vector (see register_instance and unregister_instance)
// - The constructor:
// * keeps a reference to the numpy array
// * registers itself via register_instance()
// - allocate:
// * creates a new UMatData object
// "steals" the data pointer from the numpy array
// - deallocate will:
// * decrements the reference count and deletes the UMatData object if no more references
// * unregisters itself via unregister_instance() which will *destroy* this instance!
// *The destructor is called via deallocate()*
//
// As a consequence, MatAllocator_LinkArray is created via a *naked* new() and will be destroyed via deallocate()
//
//#define DEBUG_MATALLOCATOR 0
#ifdef DEBUG_MATALLOCATOR
static int nbInstances = 0;
static int nbInstances = 0;
#endif
class MatAllocator_LinkArray: public cv::MatAllocator
{
public:
MatAllocator_LinkArray(pybind11::array& a) : m_linked_array(a)

class MatAllocator_LinkArray: public cv::MatAllocator
{
register_instance(this);
#ifdef DEBUG_MATALLOCATOR
++nbInstances;
public:
MatAllocator_LinkArray(pybind11::array& a) : m_linked_array(a)
{
register_instance(this);
#ifdef DEBUG_MATALLOCATOR
++nbInstances;
printf("MatAllocator_LinkArray constructor %p / nbInstances=%d\n", this, nbInstances);
#endif
}
#endif
}

~MatAllocator_LinkArray()
{
#ifdef DEBUG_MATALLOCATOR
--nbInstances;
~MatAllocator_LinkArray()
{
#ifdef DEBUG_MATALLOCATOR
--nbInstances;
printf("MatAllocator_LinkArray destructor %p / nbInstances=%d\n", this, nbInstances);
#endif
}
#endif
}

cv::UMatData* allocate(
int dims, const int* sizes, int type,
void* data, size_t* step, cv::AccessFlag flags, cv::UMatUsageFlags usageFlags) const override
{
// This is the allocation that will be called by cv::Mat::create
#ifdef DEBUG_MATALLOCATOR
printf("Allocate 1\n");
#endif

// Create a new UMatData object
cv::UMatData *u = new cv::UMatData(this);
// "Steal" the data pointer from the numpy array
u->data = (uchar*)m_linked_array.mutable_data(0);

// Set the reference counts to 0
// (since UMatData is not documented, this is based on a reverse engineering of the OpenCV code)
// (deallocate won't be called if refcount or urefcount is set to 1 here)
u->refcount = u->urefcount = 0; // What is the difference between refcount and urefcount? this is undocumented

return u;
}
cv::UMatData* allocate(
int dims, const int* sizes, int type,
void* data, size_t* step, cv::AccessFlag flags, cv::UMatUsageFlags usageFlags) const override
{
// This is the allocation that will be called by cv::Mat::create
#ifdef DEBUG_MATALLOCATOR
printf("Allocate 1\n");
#endif

bool allocate(cv::UMatData* data, cv::AccessFlag accessflags, cv::UMatUsageFlags usageFlags) const override
{
// We never reach here (I guess)
#ifdef DEBUG_MATALLOCATOR
printf("Allocate 2\n");
#endif
data->urefcount++;
return true;
}
// Create a new UMatData object
cv::UMatData *u = new cv::UMatData(this);
// "Steal" the data pointer from the numpy array
u->data = (uchar*)m_linked_array.mutable_data(0);

void deallocate(cv::UMatData* data) const override
{
#ifdef DEBUG_MATALLOCATOR
printf("Deallocate\n");
#endif
// Decrement the reference count
data->urefcount--;

// If no more references, delete the UMatData object
if (data->urefcount <= 0)
// Set the reference counts to 0
// (since UMatData is not documented, this is based on a reverse engineering of the OpenCV code)
// (deallocate won't be called if refcount or urefcount is set to 1 here)
u->refcount = u->urefcount = 0; // What is the difference between refcount and urefcount? this is undocumented

return u;
}

bool allocate(cv::UMatData* data, cv::AccessFlag accessflags, cv::UMatUsageFlags usageFlags) const override
{
delete data;
unregister_instance(const_cast<MatAllocator_LinkArray*>(this));
// We never reach here (I guess)
#ifdef DEBUG_MATALLOCATOR
printf("Allocate 2\n");
#endif
data->urefcount++;
return true;
}
}

void deallocate(cv::UMatData* data) const override
{
#ifdef DEBUG_MATALLOCATOR
printf("Deallocate\n");
#endif
// Decrement the reference count
data->urefcount--;

// If no more references, delete the UMatData object
if (data->urefcount <= 0)
{
delete data;
unregister_instance(const_cast<MatAllocator_LinkArray*>(this));
}
}

private:
mutable pybind11::array m_linked_array;

private:
static std::vector<MatAllocator_LinkArray*> m_all_instances;
static std::mutex m_all_instances_mutex;
private:
mutable pybind11::array m_linked_array;

private:
static std::vector<MatAllocator_LinkArray*> m_all_instances;
static std::mutex m_all_instances_mutex;

static void register_instance(MatAllocator_LinkArray* instance)
{
#ifdef DEBUG_MATALLOCATOR
printf("register_instance %p\n", instance);
#endif
std::lock_guard<std::mutex> lock(m_all_instances_mutex);
m_all_instances.push_back(instance);
}
static void unregister_instance(MatAllocator_LinkArray* instance)
{
#ifdef DEBUG_MATALLOCATOR
printf("unregister_instance %p\n", instance);
#endif

std::lock_guard<std::mutex> lock(m_all_instances_mutex);
delete instance;
auto it = std::find(m_all_instances.begin(), m_all_instances.end(), instance);
if (it != m_all_instances.end())
m_all_instances.erase(it);
else
throw std::runtime_error("MatAllocator_LinkArray::unregister_instance / instance not found");
}
};
std::vector<MatAllocator_LinkArray*> MatAllocator_LinkArray::m_all_instances; // C++ at its best syntactic terseness
std::mutex MatAllocator_LinkArray::m_all_instances_mutex; // with static members

static void register_instance(MatAllocator_LinkArray* instance)
{
#ifdef DEBUG_MATALLOCATOR
printf("register_instance %p\n", instance);
#endif
std::lock_guard<std::mutex> lock(m_all_instances_mutex);
m_all_instances.push_back(instance);
}
static void unregister_instance(MatAllocator_LinkArray* instance)
{
#ifdef DEBUG_MATALLOCATOR
printf("unregister_instance %p\n", instance);
#endif

std::lock_guard<std::mutex> lock(m_all_instances_mutex);
delete instance;
auto it = std::find(m_all_instances.begin(), m_all_instances.end(), instance);
if (it != m_all_instances.end())
m_all_instances.erase(it);
else
throw std::runtime_error("MatAllocator_LinkArray::unregister_instance / instance not found");
}
};
std::vector<MatAllocator_LinkArray*> MatAllocator_LinkArray::m_all_instances; // C++ at its best syntactic terseness
std::mutex MatAllocator_LinkArray::m_all_instances_mutex; // with static members
} // anonymous namespace


cv::Mat nparray_to_mat(pybind11::array& a)
Expand All @@ -263,7 +267,7 @@ namespace cvnp
// which will
// - keep a reference to the numpy array
// - create a cv::UMatData object that uses the numpy array data pointer
// - auto-destruct when the cv::Mat is destroyed (we hope...)
// - auto-destruct when the cv::Mat is destroyed
auto allocator = new MatAllocator_LinkArray(a);
cv::Mat m;
m.allocator = allocator;
Expand Down
3 changes: 2 additions & 1 deletion tests/test_cvnp_cpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ void test_nparray_to_mat()
}


//Python seems to fail with the following C++ function:
// See https://github.com/pthom/cvnp/issues/13
// Python seems to fail with the following C++ function:
//cpp:
// m.def("test", [](cv::Mat mat) {
// return mat;
Expand Down

0 comments on commit 4eede85

Please sign in to comment.