Skip to content

Instantly share code, notes, and snippets.

@johnmcfarlane
Last active May 3, 2020 17:08
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnmcfarlane/e3aa67df63b3a7c6217f to your computer and use it in GitHub Desktop.
Save johnmcfarlane/e3aa67df63b3a7c6217f to your computer and use it in GitHub Desktop.
Illustrates run-time polymorphism in C
// functor.c : Illustrates run-time polymorphism in C.
//
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
////////////////////////////////////////////////////////////////////////////////
// APIs
// Functor
// the type of the function pointer stored in Functor::function
// and called with a pointer to Functor::capture_buffer
typedef void (Function)(void const *);
// The function object; a homogeneous type which can be passed around by
// reference and dispatched to cause heterogeneous function code to be run
typedef struct {
Function * function;
char capture_buffer[];
} Functor;
// given a function which takes a pointer to a struct pointer to by capture,
// allocates a Functor object and returns a pointer to it
Functor * allocateFunctor(Function * function, void const * capture, size_t capture_size) {
size_t functor_size = sizeof(function) + capture_size;
Functor * functor = malloc(functor_size);
functor->function = function;
memcpy(functor->capture_buffer, capture, capture_size);
return functor;
}
// invokes the given functor
void dispatchFunctor(Functor const * functor) {
(*functor->function)(functor->capture_buffer);
}
// deallocates a given functor that was previously returned by allocateFunctor
void freeFunctor(Functor * functor) {
free(functor);
}
// FunctorRange
// a contiguous range of Functor pointers;
// used for operating on multiple Functor instances in a succession
typedef struct {
Functor * const * begin;
Functor const * const * end;
} FunctorRange;
// invokes the given functors
void dispatchFunctors(FunctorRange functors) {
while (functors.begin != functors.end) {
dispatchFunctor(*functors.begin++);
}
}
// deallocates a given functors by calling freeFunctor on each one
void freeFunctors(FunctorRange functors) {
while (functors.begin != functors.end) {
freeFunctor(*functors.begin++);
}
}
////////////////////////////////////////////////////////////////////////////////
// example usage
// functor #1
typedef struct {
float f;
} PrintFloat_Capture;
void printFloat(PrintFloat_Capture const * capture) {
printf("%f\n", capture->f);
}
// functor #2
typedef struct {
int a, b;
} AddAndPrintTwoInts_Capture;
void addAndPrintTwoInts(AddAndPrintTwoInts_Capture const * capture) {
printf("%d + %d = %d\n", capture->a, capture->b, capture->a + capture->b);
}
// functor #3
typedef struct {
char const * s;
} ConvertStringToFloat_Capture;
void convertStringToFloat(ConvertStringToFloat_Capture const * capture) {
printf("'%s' -> %f\n", capture->s, atof(capture->s));
}
// application
FunctorRange makeExampleFunctors() {
static const num_examples = 3;
Functor ** functors = malloc(sizeof(Functor*) * num_examples);
functors[0] = allocateFunctor(printFloat, &(PrintFloat_Capture) { 3.141f }, sizeof(PrintFloat_Capture));
functors[1] = allocateFunctor(addAndPrintTwoInts, &(AddAndPrintTwoInts_Capture) { 3, 5 }, sizeof(AddAndPrintTwoInts_Capture));
functors[2] = allocateFunctor(convertStringToFloat, &(ConvertStringToFloat_Capture) { "2.71828182845904" }, sizeof(ConvertStringToFloat_Capture));
return (FunctorRange) { functors, functors + num_examples };
}
int main()
{
// make example range of functors
FunctorRange functors = makeExampleFunctors();
// execute functors
dispatchFunctors(functors);
// free functors
freeFunctors(functors);
// free range
free(functors.begin);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment