| 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;
}