Skip to content

Instantly share code, notes, and snippets.

@Jookia
Created October 30, 2013 02:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Jookia/7226220 to your computer and use it in GitHub Desktop.
Save Jookia/7226220 to your computer and use it in GitHub Desktop.
A hack to convert C++'s std::function to C callbacks. A little bit like currying.
/*
Copyright (C) 2013 Jookia
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: The above copyright
notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FUNCTIONTOPTR_HPP
#define FUNCTIONTOPTR_HPP
#include <functional>
#include <exception>
namespace _functionToPtr
{
/*
Here's the amount of C functions per C++ function type, and a way to loop
through them at compile-time using macros, to supply template arguments.
Make sure when you change both macros at a time.
*/
#define _FUNCS_PER_TYPE 16
#define _LOOP_FUNC(X) \
X(0) X( 1) X( 2) X( 3) X( 4) X( 5) X( 6) X( 7) X( 8) \
X( 9) X(10) X(11) X(12) X(13) X(14) X(15) X(16)
// An array of std::functions, used by each C function.
template <typename StdFunc>
struct std_functions
{
static StdFunc func[_FUNCS_PER_TYPE];
};
// Implementation of the array, since it's static.
template <typename StdFunc>
StdFunc std_functions<StdFunc>::func[_FUNCS_PER_TYPE];
// A C function that uses an std::function by an ID from the functions array.
template <int ID, class StdFunc, class Ret, class... Args>
Ret c_function(Args... args)
{
return std_functions<StdFunc>::func[ID](args...);
}
// Tries to allocate a function from the functions array for use.
template <class CFunc, class StdFunc>
CFunc try_array_alloc(StdFunc function)
{
#define _TEST_ALLOC(ID) \
if(!std_functions<StdFunc>::func[ID]) \
{ \
std_functions<StdFunc>::func[ID] = function; \
return c_function<ID, StdFunc>; \
}
_LOOP_FUNC(_TEST_ALLOC);
#undef _TEST_ALLOC
throw std::runtime_error("No available C functions to use!");
}
// Tries to free a C function for use for future functions.
template <class CFunc, class StdFunc>
bool try_array_free(CFunc function)
{
#define _TEST_FREE(ID) \
{ \
CFunc arrayFunc = c_function<ID, StdFunc>; \
if(arrayFunc == function) \
{ \
std_functions<StdFunc>::func[ID] = nullptr; \
return true; \
} \
}
_LOOP_FUNC(_TEST_FREE);
#undef _TEST_FREE
return false;
}
#undef _FUNCS_PER_TYPE
#undef _LOOP_FUNC
}
// Public API time!
// Allocates a C function pointer that runs an std::function.
template <class CFunc, class StdFunc>
CFunc allocFunctionPtr(StdFunc function)
{
return _functionToPtr::try_array_alloc<CFunc, StdFunc>(function);
}
// Frees a C function pointer used by an std::function.
template <class CFunc, class StdFunc>
bool freeFunctionPtr(CFunc function)
{
return _functionToPtr::try_array_free<CFunc, StdFunc>(function);
}
#endif
#include "functionToPtr.hpp"
#include <iostream>
class printer
{
public:
printer(char const* printerName)
: name(printerName)
{
}
void print(char const* text)
{
std::cout << name << " says: " << text << std::endl;
}
private:
char const* name;
};
int main(void)
{
typedef std::function<void(char const*)> boundFunction;
typedef void (*callback)(char const*);
printer myPrinter("Jookia's Printer");
boundFunction bound =
std::bind(&printer::print, &myPrinter, std::placeholders::_1);
bound("Hello!");
callback CFunc = allocFunctionPtr<callback>(bound);
CFunc("What's up?");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment