Last active
May 3, 2020 17:08
-
-
Save johnmcfarlane/e3aa67df63b3a7c6217f to your computer and use it in GitHub Desktop.
Illustrates run-time polymorphism in C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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