fork download
  1. #include <stdbool.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5.  
  6. struct partially_applied {
  7. void * data;
  8. void (*function)(void *);
  9. void (*store)(void *, char const *, void *);
  10. };
  11.  
  12. typedef struct partially_applied * FUN;
  13.  
  14. #define SPLICE_2(l,r) l##r
  15. #define SPLICE_1(l,r) SPLICE_2(l,r)
  16. #define SPLICE(l,r) SPLICE_1(l,r)
  17.  
  18. #define DATA_DEF_0(...)
  19. #define DATA_DEF_1(type, name) type name; bool name ## _valid;
  20. #define DATA_DEF_2(type, name, ...) type name; bool name ## _valid; DATA_DEF_1(__VA_ARGS__)
  21. #define DATA_DEF_3(type, name, ...) type name; bool name ## _valid; DATA_DEF_2(__VA_ARGS__)
  22. #define DATA_DEF_4(type, name, ...) type name; bool name ## _valid; DATA_DEF_3(__VA_ARGS__)
  23. // add more to support more parameters
  24. #define DATA_DEF(N, ...) SPLICE(DATA_DEF_,N)(__VA_ARGS__)
  25.  
  26. #define DATA_ACCESS_0(...)
  27. #define DATA_ACCESS_1(t, name) data->name
  28. #define DATA_ACCESS_2(t, name, ...) data->name, DATA_ACCESS_1(__VA_ARGS__)
  29. #define DATA_ACCESS_3(t, name, ...) data->name, DATA_ACCESS_2(__VA_ARGS__)
  30. #define DATA_ACCESS_4(t, name, ...) data->name, DATA_ACCESS_3(__VA_ARGS__)
  31. // add more to support more parameters
  32. #define DATA_ACCESS(N, ...) SPLICE(DATA_ACCESS_,N)(__VA_ARGS__)
  33.  
  34. #define DATA_CHECK_0(...) true
  35. #define DATA_CHECK_1(t, name) data->name ## _valid
  36. #define DATA_CHECK_2(t, name, ...) data->name ## _valid && DATA_CHECK_1(__VA_ARGS__)
  37. #define DATA_CHECK_3(t, name, ...) data->name ## _valid && DATA_CHECK_2(__VA_ARGS__)
  38. #define DATA_CHECK_4(t, name, ...) data->name ## _valid && DATA_CHECK_3(__VA_ARGS__)
  39. // add more to support more parameters
  40. #define DATA_CHECK(N, ...) SPLICE(DATA_CHECK_,N)(__VA_ARGS__)
  41.  
  42. #define DATA_INIT_0(...)
  43. #define DATA_INIT_1(t, name) data->name ## _valid = false;
  44. #define DATA_INIT_2(t, name, ...) data->name ## _valid = false; DATA_INIT_1(__VA_ARGS__)
  45. #define DATA_INIT_3(t, name, ...) data->name ## _valid = false; DATA_INIT_2(__VA_ARGS__)
  46. #define DATA_INIT_4(t, name, ...) data->name ## _valid = false; DATA_INIT_3(__VA_ARGS__)
  47. // add more to support more parameters
  48. #define DATA_INIT(N, ...) SPLICE(DATA_INIT_,N)(__VA_ARGS__)
  49.  
  50.  
  51. #define DATA_STORE_CODE_OP(type, name) \
  52. if (strcmp(id, #name) == 0) { data->name = *((type *) src); data->name ## _valid = true; return; }
  53.  
  54. #define DATA_STORE_CODE_0(...)
  55. #define DATA_STORE_CODE_1(type, name) DATA_STORE_CODE_OP(type, name)
  56. #define DATA_STORE_CODE_2(type, name, ...) DATA_STORE_CODE_OP(type, name) DATA_STORE_CODE_1(__VA_ARGS__)
  57. #define DATA_STORE_CODE_3(type, name, ...) DATA_STORE_CODE_OP(type, name) DATA_STORE_CODE_2(__VA_ARGS__)
  58. #define DATA_STORE_CODE_4(type, name, ...) DATA_STORE_CODE_OP(type, name) DATA_STORE_CODE_3(__VA_ARGS__)
  59. // more
  60. #define DATA_STORE_CODE(N, ...) SPLICE(DATA_STORE_CODE_,N)(__VA_ARGS__)
  61.  
  62. #define MAKE_PARTIAL(fn, N, ...) \
  63. struct partially_applied_ ## fn ## _data { \
  64. DATA_DEF(N, __VA_ARGS__) \
  65. }; \
  66. static void init_partially_applied_ ## fn ## _data (void * p) { \
  67. struct partially_applied_ ## fn ## _data * data = p; \
  68. DATA_INIT(N, __VA_ARGS__); \
  69. } \
  70. static void * allocate_partially_applied_ ## fn ## _data (void) { \
  71. void * data = malloc(sizeof(struct partially_applied_ ## fn ## _data)); \
  72. if (data == NULL) { \
  73. fprintf(stderr, "Allocation failure for " #fn " data\n"); \
  74. exit(1); \
  75. } \
  76. init_partially_applied_ ## fn ## _data(data); \
  77. return data; \
  78. } \
  79. static void partially_applied_ ## fn (void * p) { \
  80. struct partially_applied_ ## fn ## _data * data = p; \
  81. if (DATA_CHECK(N, __VA_ARGS__)) { \
  82. fn(DATA_ACCESS(N, __VA_ARGS__)); \
  83. } else { \
  84. fprintf(stderr, "Not all parameters for " #fn " are vaild\n"); \
  85. } \
  86. } \
  87. static void partially_applied_ ## fn ## _store ( \
  88. void * p, char const * id, void * src) { \
  89. struct partially_applied_ ## fn ## _data * data = p; \
  90. DATA_STORE_CODE(N, __VA_ARGS__) \
  91. fprintf(stderr, "Cannot store %s in " #fn "!\n", id); \
  92. }
  93.  
  94.  
  95.  
  96.  
  97.  
  98.  
  99.  
  100. #define DATA_STORE_OP(name, value) pfn->store(pfn->data, #name, &(value));
  101. #define DATA_STORE_0(...)
  102. #define DATA_STORE_1(name, value) DATA_STORE_OP(name, value)
  103. #define DATA_STORE_2(name, value, ...) DATA_STORE_OP(name, value) DATA_STORE_1(__VA_ARGS__)
  104. #define DATA_STORE_3(name, value, ...) DATA_STORE_OP(name, value) DATA_STORE_2(__VA_ARGS__)
  105. #define DATA_STORE_4(name, value, ...) DATA_STORE_OP(name, value) DATA_STORE_3(__VA_ARGS__)
  106. #define DATA_STORE(N, ...) SPLICE(DATA_STORE_,N)(__VA_ARGS__)
  107.  
  108.  
  109. #define APPLY(PFN, N, ...) \
  110. do { \
  111. struct partially_applied * pfn = (PFN); \
  112. DATA_STORE(N, __VA_ARGS__) \
  113. } while(0)
  114.  
  115.  
  116. FUN make_fun(void (*function)(void *), void (*store)(void *, char const *, void *), void * data) {
  117. FUN f = malloc(sizeof(*f));
  118. if (f == NULL) {
  119. fprintf(stderr, "Allocation of FUN failed\n");
  120. exit(1);
  121. }
  122. f->function = function;
  123. f->store = store;
  124. f->data = data;
  125. return f;
  126. }
  127. void free_fun(FUN f) {
  128. free(f->data);
  129. free(f);
  130. }
  131. #define PARTIAL(fn) make_fun(&(partially_applied_ ## fn), \
  132.   &(partially_applied_ ## fn ## _store), \
  133.   allocate_partially_applied_ ## fn ## _data())
  134.  
  135.  
  136.  
  137.  
  138.  
  139. #define DISCARD(fn) free_fn(fn)
  140.  
  141. #define CALL(fn) (fn)->function((fn)->data)
  142.  
  143. void foo(char * str, int i) {
  144. printf("FOO| str = %s, i = %d\n", str, i);
  145. }
  146. void bar(float f, int i, size_t s) {
  147. printf("BAR| f = %f, i = %d, s = %zu\n", f, i, s);
  148. }
  149. MAKE_PARTIAL(foo, 2, char *, string, int, integer)
  150. MAKE_PARTIAL(bar, 3, float, floating, int, INT, size_t, SOME_SIZE)
  151.  
  152.  
  153. int main() {
  154. FUN f = PARTIAL(foo);
  155. char * c = "Crazy";
  156. APPLY(f, 1, string, c);
  157. printf("doing other stuff\n");
  158. FUN g = PARTIAL(bar);
  159. size_t size = 99;
  160. APPLY(g, 1, SOME_SIZE, size);
  161. int answer = 42;
  162. APPLY(f, 1, integer, answer);
  163. answer = 21;
  164. float pi = 3.14;
  165. APPLY(g, 2, INT, answer, floating, pi);
  166. CALL(f);
  167. printf("done\n");
  168. CALL(g);
  169. printf("now completely done\n");
  170. return 0;
  171. }
Success #stdin #stdout 0s 2288KB
stdin
Standard input is empty
stdout
doing other stuff
FOO| str = Crazy, i = 42
done
BAR| f = 3.140000, i = 21, s = 99
now completely done