Josh Dybnis on 10 Jun 2003 14:22:01 -0000 |
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
[ALACPP] Generalized Functors in C |
I've ported Loki's generalized functors to C, using the preprocessor instead of templates. In C there are only two callable entities: - functions - pointers to functions We add a third: - functors Since C does not have operator overloading, functors are invoked with the syntax EXECUTE_FUNCTOR(), and are deleted with FREE_FUNCTOR(). Other than that the interface is elegant. The code the library generates respects the C typesystem. In otherwords it doesn't do anything dangerous like casting arguments to (void *). It has only been tested with gcc. But it should work on any C99 compliant compiler. I don't have a web page set up, so I've attached the files. It's a small list so I hope no one minds. -Josh Dybnis
/******************************************************************************/ /* C port of Generalized Functor from Chapter 5 of "Modern C++ Design" */ /******************************************************************************/ /**** functor.c **************************************************************/ #include <stdlib.h> #include <string.h> #include "functor.h" void I_free_functor_chain (I_functor_chain c) { I_functor f1, f2; f1 = c->f1; f2 = c->f2; free(c); FREE_FUNCTOR(f1); /* hopfully the compiler does tail-call optimization, or on a long chain * this could blow the stack */ FREE_FUNCTOR(f2); } void I_free_bound_functor (I_bound_functor f) { FREE_FUNCTOR(f->f); free(f); } I_functor I_clone_functor (I_functor f1) { I_functor f2; f2 = (I_functor) malloc(f1->size); memcpy(f2, f1, f1->size); return f2; } I_functor_chain I_clone_functor_chain (I_functor_chain c1) { I_functor_chain c2; c2 = (I_functor_chain) malloc(sizeof(*c2)); memcpy(c2, c1, sizeof(*c2)); c2->f1 = CLONE_FUNCTOR(c1->f1); c2->f2 = CLONE_FUNCTOR(c1->f2); return c2; } I_bound_functor I_clone_bound_functor (I_bound_functor f1) { I_bound_functor f2; f2 = (I_bound_functor) malloc(f1->size); memcpy(f2, f1, f1->size); f2->f = CLONE_FUNCTOR(f1->f); return f2; }
/****************************************************************************/ /* C port of Generalized Functor from Chapter 5 of "Modern C++ Design" */ /* */ /* Josh Dybnis: June 9, 2003 */ /****************************************************************************/ /* */ /* If my answers frighten you then you should cease asking scary questions. */ /* */ /* - Pulp Fiction (1994) */ /****************************************************************************/ #ifndef _FUNCTOR_H_ #define _FUNCTOR_H_ #include <stdlib.h> #define EXECUTE_FUNCTOR(functor, ...) \ (functor)->execute((functor), ## __VA_ARGS__) #define FREE_FUNCTOR(functor) \ (functor)->free(functor) #define CLONE_FUNCTOR(functor) \ (functor)->clone(functor) #define DEC_FUNCTOR_TYPE(...) I_DEC_FUNCTOR_TYPE(__VA_ARGS__) #define I_DEC_FUNCTOR_TYPE(ret, functor, n, ...) \ typedef struct functor *functor; \ struct functor \ { ret (*execute)(functor I_I##n __VA_ARGS__); \ void (*free) (functor); \ functor (*clone) (functor); \ size_t size; \ ret (*fp)(__VA_ARGS__); \ }; \ static inline functor new_##functor (ret (*fp)(__VA_ARGS__)) \ { static ret I_execute_##functor (functor I_I##n __VA_ARGS__); \ functor f = (functor) malloc(sizeof(*f)); \ f->execute = I_execute_##functor; \ f->free = (void (*)(functor)) free; \ f->clone = (functor (*)(functor)) I_clone_functor; \ f->size = sizeof(*f); \ f->fp = fp; \ return f; \ } \ static inline functor chain_##functor (functor f1, functor f2) \ { static void I_execute_##functor##_chain (); \ I_functor_chain c = (I_functor_chain)malloc(sizeof(*c)); \ c->execute = (I_void_fp)I_execute_##functor##_chain; \ c->free = (I_void_fp)I_free_functor_chain; \ c->clone = (I_void_fp)I_clone_functor_chain; \ c->f1 = CLONE_FUNCTOR((I_functor)f1); \ c->f2 = CLONE_FUNCTOR((I_functor)f2); \ return (functor)c; \ } #define DEF_FUNCTOR_TYPE(...) I_DEF_FUNCTOR_TYPE(__VA_ARGS__) #define I_DEF_FUNCTOR_TYPE(ret, functor, n, ...) \ ret I_execute_##functor \ (functor f I_MAP(0, n, I_D, I_D, __VA_ARGS__)) \ { f->fp(I_MAP(0, n, I_G1, I_G2, __VA_ARGS__)); \ } \ ret I_execute_##functor##_chain \ (I_functor_chain c I_MAP(0, n, I_D, I_D, __VA_ARGS__)) \ { I_APPLY0 \ ( EXECUTE_FUNCTOR, \ (functor)c->f1 \ I_MAP(0, n, I_F, I_F, __VA_ARGS__) \ ); \ return I_APPLY0 \ ( EXECUTE_FUNCTOR, \ (functor)c->f2 \ I_MAP(0, n, I_F, I_F, __VA_ARGS__) \ ); \ } #define LOC_FUNCTOR_TYPE(...) \ DEC_FUNCTOR_TYPE(__VA_ARGS__) \ DEF_FUNCTOR_TYPE(static __VA_ARGS__) #define DEC_FUNCTOR_FROM_FUNCTION(...) \ I_REORDER(I_DEC_FUNCTOR_FROM_FUNCTION, __VA_ARGS__) #define I_DEC_FUNCTOR_FROM_FUNCTION(r1, function, n, r2, functor, m, ...) \ typedef struct I_##functor##_##function *I_##functor##_##function; \ struct I_##functor##_##function \ { I_void_fp execute; \ I_void_fp free; \ I_void_fp clone; \ size_t size; \ I_MAP(0, n, I_A, I_A, __VA_ARGS__) \ }; \ static inline functor new_##functor##_from_##function \ (I_K##n I_MAP(0, n, I_B1, I_B2, __VA_ARGS__)) \ { r2 I_execute_##functor##_##function(); \ I_##functor##_##function f; \ f = (I_##functor##_##function)malloc(sizeof(*f)); \ f->execute = (I_void_fp) I_execute_##functor##_##function; \ f->free = (I_void_fp) free; \ f->clone = (I_void_fp) I_clone_functor; \ f->size = sizeof(*f); \ I_MAP(0, n, I_C, I_C, __VA_ARGS__) \ return (functor)f; \ } \ r1 function (__VA_ARGS__ I_J##n(m)); \ static inline functor new_##functor(r1 (*)(I_SKIP##n(__VA_ARGS__) I_K##m)); #define DEC_POINTER_TYPE(ret, name, ...) \ typedef ret (*name)(__VA_ARGS__); #define DEC_FUNCTOR_FROM_POINTER(...) \ I_REORDER(I_DEC_FUNCTOR_FROM_POINTER, __VA_ARGS__) #define I_DEC_FUNCTOR_FROM_POINTER(r1, type, n, r2, functor, m, ...) \ typedef struct I_##functor##_##type *I_##functor##_##type; \ struct I_##functor##_##type \ { I_void_fp execute; \ I_void_fp free; \ I_void_fp clone; \ size_t size; \ type fp; \ I_MAP(0, n, I_A, I_A, __VA_ARGS__) \ }; \ static inline functor new_##functor##_from_##type \ (type fp, I_MAP(0, n, I_D, I_D, __VA_ARGS__)) \ { r2 I_execute_##functor##_##type(); \ I_##functor##_##type f; \ f = (I_##functor##_##type)malloc(sizeof(*f)); \ f->execute = (I_void_fp) I_execute_##functor##_##type; \ f->free = (I_void_fp) free; \ f->clone = (I_void_fp) I_clone_functor; \ f->size = sizeof(*f); \ f->fp = fp; \ I_MAP(0, n, I_C, I_C, __VA_ARGS__) \ return (functor)f; \ } \ static inline functor new_##functor(r1 (*)(I_SKIP##n(__VA_ARGS__) I_K##m)); #define DEC_FUNCTOR_FROM_FUNCTOR(...) \ I_REORDER(I_DEC_FUNCTOR_FROM_FUNCTOR, __VA_ARGS__) #define I_DEC_FUNCTOR_FROM_FUNCTOR(r1, f1, n, r2, f2, m, ...) \ typedef struct I_##f2##_##f1 *I_##f2##_##f1; \ struct I_##f2##_##f1 \ { I_void_fp execute; \ I_void_fp free; \ I_void_fp clone; \ size_t size; \ f1 f; \ I_MAP(0, n, I_A, I_A, __VA_ARGS__) \ }; \ static inline f2 new_##f2##_from_##f1 \ (f1 b I_MAP(0, n, I_D, I_D, __VA_ARGS__)) \ { r2 I_execute_##f2##_##f1(); \ I_##f2##_##f1 f = (I_##f2##_##f1)malloc(sizeof(*f)); \ f->execute = (I_void_fp) I_execute_##f2##_##f1; \ f->free = (I_void_fp) I_free_bound_functor; \ f->clone = (I_void_fp) I_clone_bound_functor; \ f->size = sizeof(*f); \ f->f = CLONE_FUNCTOR(b); \ I_MAP(0, n, I_C, I_C, __VA_ARGS__) \ return (f2)f; \ } \ static inline f1 new_##f1(r1 (*)(__VA_ARGS__ I_J##n(m))); \ static inline f2 new_##f2(r1 (*)(I_SKIP##n(__VA_ARGS__) I_K##m)); #define DEF_FUNCTOR_FROM_FUNCTION(...) \ I_REORDER(I_DEF_FUNCTOR_FROM_FUNCTION, __VA_ARGS__) #define I_DEF_FUNCTOR_FROM_FUNCTION(r1, function, n, r2, functor, m, ...) \ r1 I_execute_##functor##_##function \ (I_##functor##_##function f I_MAP(n, m, I_D, I_D, __VA_ARGS__)) \ { return function(I_MAP(0, n, I_E1, I_E2, __VA_ARGS__) I_H##n(m) \ I_MAP(n, m, I_G1, I_G2, __VA_ARGS__)); \ } #define DEF_FUNCTOR_FROM_FUNCTOR(...) \ I_REORDER(I_DEF_FUNCTOR_FROM_FUNCTOR, __VA_ARGS__) #define I_DEF_FUNCTOR_FROM_FUNCTOR(r1, f1, n, r2, f2, m, ...) \ r2 I_execute_##f2##_##f1 \ (I_##f2##_##f1 f I_MAP(n, m, I_D, I_D, __VA_ARGS__)) \ { return EXECUTE_FUNCTOR \ ( f->f, \ I_MAP(0, n, I_E1, I_E2, __VA_ARGS__) I_H##n(m) \ I_MAP(n, m, I_G1, I_G2, __VA_ARGS__) \ ); \ } #define DEF_FUNCTOR_FROM_POINTER(...) \ I_REORDER(I_DEF_FUNCTOR_FROM_POINTER, __VA_ARGS__) #define I_DEF_FUNCTOR_FROM_POINTER(r1, type, n, r2, functor, m, ...) \ r2 I_execute_##functor##_##type \ (I_##functor##_##type f I_MAP(n, m, I_D, I_D, __VA_ARGS__)) \ { return f->fp(I_MAP(0, n, I_E1, I_E2, __VA_ARGS__) I_H##n(m) \ I_MAP(n, m, I_G1, I_G2, __VA_ARGS__)); \ } #define LOC_FUNCTOR_FROM_FUNCTION(...) \ DEC_FUNCTOR_FROM_FUNCTION(static __VA_ARGS__) \ DEF_FUNCTOR_FROM_FUNCTION(static __VA_ARGS__) #define LOC_FUNCTOR_FROM_POINTER(...) \ DEC_FUNCTOR_FROM_POINTER(static __VA_ARGS__) \ DEF_FUNCTOR_FROM_POINTER(static __VA_ARGS__) #define LOC_FUNCTOR_FROM_FUNCTOR(...) \ DEC_FUNCTOR_FROM_FUNCTOR(static __VA_ARGS__) \ DEF_FUNCTOR_FROM_FUNCTOR(static __VA_ARGS__) #define I_REORDER(macro, ret, functor, n, ...) \ I_APPLY3 \ ( macro, \ I_APPLY1(I_AT1, I_SKIP##n(__VA_ARGS__)), \ I_APPLY1(I_AT2, I_SKIP##n(__VA_ARGS__)), \ I_APPLY1(I_AT3, I_SKIP##n(__VA_ARGS__)), \ ret, \ functor, \ n \ I_APPLY2(I_H1, I_APPLY1(I_AT3, I_SKIP##n(__VA_ARGS__))) \ I_APPLY1(I_SKIP3, I_SKIP##n(__VA_ARGS__)) \ I_I##n I_TAKE##n(__VA_ARGS__) \ ) #define I_APPLY0(f, ...) f(__VA_ARGS__) #define I_APPLY1(f, ...) f(__VA_ARGS__) #define I_APPLY2(f, ...) f(__VA_ARGS__) #define I_APPLY3(f, ...) f(__VA_ARGS__) #define I_AT1(first, ...) first #define I_AT2(first, second, ...) second #define I_AT3(first, second, third, ...) third #define I_MAP(n, m, f, l, ...) \ I_APPLY0(I_MAP##m, f, l, I_SKIP##n(__VA_ARGS__)) #define I_MAP0(f, l, ...) #define I_MAP1(f, l, h, ...) l(h, 1) #define I_MAP2(f, l, h, ...) f(h, 2)I_MAP1(f, l, __VA_ARGS__) #define I_MAP3(f, l, h, ...) f(h, 3)I_MAP2(f, l, __VA_ARGS__) #define I_MAP4(f, l, h, ...) f(h, 4)I_MAP3(f, l, __VA_ARGS__) #define I_MAP5(f, l, h, ...) f(h, 5)I_MAP4(f, l, __VA_ARGS__) #define I_MAP6(f, l, h, ...) f(h, 6)I_MAP5(f, l, __VA_ARGS__) #define I_MAP7(f, l, h, ...) f(h, 7)I_MAP6(f, l, __VA_ARGS__) #define I_MAP8(f, l, h, ...) f(h, 8)I_MAP7(f, l, __VA_ARGS__) #define I_MAP9(f, l, h, ...) f(h, 9)I_MAP8(f, l, __VA_ARGS__) #define I_MAP10(f, l, h, ...) f(h, 10)I_MAP9(f, l, __VA_ARGS__) #define I_MAP11(f, l, h, ...) f(h, 11)I_MAP10(f, l, __VA_ARGS__) #define I_MAP12(f, l, h, ...) f(h, 12)I_MAP11(f, l, __VA_ARGS__) #define I_MAP13(f, l, h, ...) f(h, 13)I_MAP12(f, l, __VA_ARGS__) #define I_MAP14(f, l, h, ...) f(h, 14)I_MAP13(f, l, __VA_ARGS__) #define I_MAP15(f, l, h, ...) f(h, 15)I_MAP14(f, l, __VA_ARGS__) #define I_SKIP0(...) __VA_ARGS__ #define I_SKIP1(h, ...) I_SKIP0(__VA_ARGS__) #define I_SKIP2(h, ...) I_SKIP1(__VA_ARGS__) #define I_SKIP3(h, ...) I_SKIP2(__VA_ARGS__) #define I_SKIP4(h, ...) I_SKIP3(__VA_ARGS__) #define I_SKIP5(h, ...) I_SKIP4(__VA_ARGS__) #define I_SKIP6(h, ...) I_SKIP5(__VA_ARGS__) #define I_SKIP7(h, ...) I_SKIP6(__VA_ARGS__) #define I_SKIP8(h, ...) I_SKIP7(__VA_ARGS__) #define I_SKIP9(h, ...) I_SKIP8(__VA_ARGS__) #define I_SKIP10(h, ...) I_SKIP9(__VA_ARGS__) #define I_SKIP11(h, ...) I_SKIP10(__VA_ARGS__) #define I_SKIP12(h, ...) I_SKIP11(__VA_ARGS__) #define I_SKIP13(h, ...) I_SKIP12(__VA_ARGS__) #define I_SKIP14(h, ...) I_SKIP13(__VA_ARGS__) #define I_SKIP15(h, ...) I_SKIP14(__VA_ARGS__) #define I_TAKE0(...) #define I_TAKE1(h, ...) h #define I_TAKE2(h, ...) h, I_TAKE1(__VA_ARGS__) #define I_TAKE3(h, ...) h, I_TAKE2(__VA_ARGS__) #define I_TAKE4(h, ...) h, I_TAKE3(__VA_ARGS__) #define I_TAKE5(h, ...) h, I_TAKE4(__VA_ARGS__) #define I_TAKE6(h, ...) h, I_TAKE5(__VA_ARGS__) #define I_TAKE7(h, ...) h, I_TAKE6(__VA_ARGS__) #define I_TAKE8(h, ...) h, I_TAKE7(__VA_ARGS__) #define I_TAKE9(h, ...) h, I_TAKE8(__VA_ARGS__) #define I_TAKE10(h, ...) h, I_TAKE9(__VA_ARGS__) #define I_TAKE11(h, ...) h, I_TAKE10(__VA_ARGS__) #define I_TAKE12(h, ...) h, I_TAKE11(__VA_ARGS__) #define I_TAKE13(h, ...) h, I_TAKE12(__VA_ARGS__) #define I_TAKE14(h, ...) h, I_TAKE13(__VA_ARGS__) #define I_TAKE15(h, ...) h, I_TAKE14(__VA_ARGS__) #define I_A(type, n) type arg##n; #define I_B1(type, n) type arg##n, #define I_B2(type, n) type arg##n #define I_C(type, n) f->arg##n = arg##n; #define I_D(type, n) , type arg##n #define I_E1(type, n) f->arg##n, #define I_E2(type, n) f->arg##n #define I_F(type, n) , arg##n #define I_G1(type, n) arg##n, #define I_G2(type, n) arg##n #define I_H0(n) #define I_H1(n) I_I##n #define I_H2(n) I_I##n #define I_H3(n) I_I##n #define I_H4(n) I_I##n #define I_H5(n) I_I##n #define I_H6(n) I_I##n #define I_H7(n) I_I##n #define I_H8(n) I_I##n #define I_H9(n) I_I##n #define I_H10(n) I_I##n #define I_H11(n) I_I##n #define I_H12(n) I_I##n #define I_H13(n) I_I##n #define I_H14(n) I_I##n #define I_H15(n) I_I##n #define I_I0 #define I_I1 , #define I_I2 , #define I_I3 , #define I_I4 , #define I_I5 , #define I_I6 , #define I_I7 , #define I_I8 , #define I_I9 , #define I_I10 , #define I_I11 , #define I_I12 , #define I_I13 , #define I_I14 , #define I_I15 , #define I_J0(n) I_K##n #define I_J1(n) #define I_J2(n) #define I_J3(n) #define I_J4(n) #define I_J5(n) #define I_J6(n) #define I_J7(n) #define I_J8(n) #define I_J9(n) #define I_J10(n) #define I_J11(n) #define I_J12(n) #define I_J13(n) #define I_J14(n) #define I_J15(n) #define I_K0 void #define I_K1 #define I_K2 #define I_K3 #define I_K4 #define I_K5 #define I_K6 #define I_K7 #define I_K8 #define I_K9 #define I_K10 #define I_K11 #define I_K12 #define I_K13 #define I_K14 #define I_K15 typedef void (*I_void_fp)(void); typedef struct I_functor *I_functor; typedef struct I_bound_functor *I_bound_functor; typedef struct I_functor_chain *I_functor_chain; /* assuming 32-bit pointers, we could save 8 bytes per-object, by moving the * function pointers into static structures, at the cost of an extra pointer * dereference per functor invocation */ struct I_functor { I_void_fp execute; void (*free) (I_functor); I_functor (*clone)(I_functor); size_t size; }; struct I_bound_functor { I_void_fp execute; I_void_fp free; I_void_fp clone; size_t size; I_functor f; }; struct I_functor_chain { I_void_fp execute; I_void_fp free; I_void_fp clone; I_functor f1; I_functor f2; }; I_functor I_clone_functor (I_functor); I_functor_chain I_clone_functor_chain (I_functor_chain); I_bound_functor I_clone_bound_functor (I_bound_functor); void I_free_functor_chain (I_functor_chain); void I_free_bound_functor (I_bound_functor); #endif /* _FUNCTOR_H_ */
#include <stdio.h> #include "functor.h" /***** FUNCTORS *************************************************************/ /* functor prototype: void Alpha (int, int); */ #define ALPHA void, Alpha, 2, int, int LOC_FUNCTOR_TYPE(ALPHA); /* functor prototype: void Beta (void); */ #define BETA void, Beta, 0 LOC_FUNCTOR_TYPE(BETA); /***** FUNCTION PROTOTYPES **************************************************/ void Foo (int, int, int); void Bar (int, int); /* Declare a function that creates an Alpha functor by binding the first * argument of Foo(). */ LOC_FUNCTOR_FROM_FUNCTION(ALPHA, void, Foo, 1, int); /* Declare a function that creates a Beta functor by binding both arguments of * an Alpha functor */ LOC_FUNCTOR_FROM_FUNCTOR(BETA, ALPHA); /***** FUNCTION DEFINITIONS *************************************************/ void Foo (int x, int y, int z) { printf("Foo(%d %d %d)\n", x, y, z); } void Bar (int x, int y) { printf("Bar(%d %d)\n", x, y); } int main (void) { /* create an Alpha functor from the function Bar(). */ Alpha a1 = new_Alpha(&Bar); /* Create an Alpha functor by binding the first argument of Foo(). */ Alpha a2 = new_Alpha_from_Foo(1); /* Create an Alpha functor by chaining togeather two Alpha functors. */ Alpha a3 = chain_Alpha(a1, a2); /* Create a Beta functor by binding an Alpha functor with its first two * arguments */ Beta b1 = new_Beta_from_Alpha(a3, 2, 3); /* Create a Beta functor by chaining a functor with itself. */ Beta b2 = chain_Beta(b1, b1); /* Execute a bunch of functors. */ EXECUTE_FUNCTOR(a1, 4, 5); EXECUTE_FUNCTOR(a2, 6, 7); EXECUTE_FUNCTOR(a3, 8, 9); EXECUTE_FUNCTOR(b2); /* Cleanup. */ FREE_FUNCTOR(a1); FREE_FUNCTOR(a2); FREE_FUNCTOR(a3); FREE_FUNCTOR(b1); FREE_FUNCTOR(b2); return 0; }