An open API service indexing awesome lists of open source software.

https://github.com/gilzoide/functor2c

Single header templates for wrapping C++ functors as opaque userdata plus function pointers for C interop
https://github.com/gilzoide/functor2c

c-interop cpp cpp11 cpp17 function-pointer function-pointers functor single-file single-file-library single-header single-header-library

Last synced: 2 months ago
JSON representation

Single header templates for wrapping C++ functors as opaque userdata plus function pointers for C interop

Awesome Lists containing this project

README

          

# functor2c
Single header templates for wrapping C++ functors as opaque userdata plus function pointers for C interop.

## Features
- Easily wrap functors such as `std::function` or lambdas as function pointers to use in C APIs
- Supports functors with parameters and return values of any type
- Provides deleter functionality to avoid memory leaks, including overloads that return smart pointers
- Requires C++11 or newer
- Automatic arguments / return type deduction when used in C++17

## Example usage
```cpp
#include "functor2c.hpp"

// Let's use as an example Lua's allocator function `lua_Alloc`
// Note that it accepts an opaque userdata as the first parameter (prefix)
typedef void *(*lua_Alloc)(void *ud, void *ptr, size_t osize, size_t nsize);

// 1. Define the functor for it
auto alloc_func = [](void *ptr, size_t osize, size_t nsize) {
ptr = /* implementation ... */;
return ptr;
};

// 2. Now create the opaque userdata + function pointers for it
// 2.a) C++17 supports type deduction and structured bindings
auto [userdata, invoke_fptr, delete_fptr] = functor2c::prefix_invoker_deleter(alloc_func);
// 2.b) C++11 requires specifying functor type as
void *userdata;
lua_Alloc invoke_fptr;
void (*delete_fptr)(void*);
std::tie(userdata, invoke_fptr, delete_fptr) = functor2c::prefix_invoker_deleter(alloc_func);

// 3. Pass the invoke function pointer + opaque userdata to C APIs
lua_setallocf(L, invoke_fptr, userdata);

// 4. Delete userdata to avoid memory leaks.
// Note: optionally use `prefix_invoker_unique` to get userdata as a unique_ptr
// and `prefix_invoker_shared` to get userdata as a shared_ptr.
delete_fptr(userdata);
```

In case the C API expects the opaque userdata as last argument instead of first, use `suffix_invoker_*` functions instead of `prefix_invoker_*`.
```cpp
// For example Box2D 3.1.0 custom filter callback.
// Note that it accepts an opaque userdata as the last parameter (suffix)
typedef bool b2CustomFilterFcn(b2ShapeId shapeIdA, b2ShapeId shapeIdB, void* context);

auto filter_callback = [](b2ShapeId shapeIdA, b2ShapeId shapeIdB) {
/* implementation ... */
return true;
};
auto [userdata, invoke_fptr] = functor2c::suffix_invoker_unique(filter_callback);
b2World_SetCustomFilterCallback(world_id, invoke_fptr, userdata.get());
```

## Integrating with CMake
You can integrate functor2c with CMake targets by adding a copy of this repository and linking with the `functor2c` target:
```cmake
add_subdirectory(path/to/functor2c)
target_link_libraries(my_awesome_target functor2c)
```