cosmopolitan/third_party/nsync/testing/closure.h
Justine Tunney fa20edc44d
Reduce header complexity
- Remove most __ASSEMBLER__ __LINKER__ ifdefs
- Rename libc/intrin/bits.h to libc/serialize.h
- Block pthread cancelation in fchmodat() polyfill
- Remove `clang-format off` statements in third_party
2023-11-28 14:39:42 -08:00

184 lines
6.9 KiB
C

#ifndef NSYNC_TESTING_CLOSURE_H_
#define NSYNC_TESTING_CLOSURE_H_
#include "libc/mem/mem.h"
/* A run-once, self-freeing closure. */
typedef struct closure_s {
void (*f0) (void *);
} closure;
/* Run the closure *cl, and free it. */
void closure_run (closure *cl);
/* Fork a new thread running the closure *cl, which will be freed when the
thread exits. */
void closure_fork (closure *cl);
/* To create a closure, declare a closure constructor with the right function arguments.
For functions taking no arguments, use
CLOSURE_DECL_BODY0 (foo)
to generate the static routine:
static closure *closure_foo (void (*f) (void));
that will return a closure for any function *f that takes no argument.
For an 1-argument function, use
CLOSURE_DECL_BODY1 (foo, type)
to generate the static routine:
static closure *closure_foo (void (*f) (type), type x);
that will return a closure for any function taking a single argument of the
specified type.
For an 2-argument function, use
CLOSURE_DECL_BODY2 (foo, type0, type1)
to generate the static routine:
static closure *closure_foo (void (*f) (type0, type1), type0 x0, type1 x1);
that will return a closure for any function taking a "type0" argument, and
a "type1" argument.
And so on, up to 9 arguments.
For example, to make closures out of qsort():
// First, just once (per module) define:
// static closure *closure_qsort_args (
// void (*f) (void *, size_t, size_t, int (*)(const void *, const void *))
// void *x0, size_t x1, size_t x2, int (*x3)(const void *, const void *));
// by writing:
CLOSURE_DECL_BODY4 (qsort_args, void *, size_t, size_t, int (*)(const void *, const void *))
// Second, for each closure to be created, write something like this:
closure *cl = closure_qsort_args (array, n_elements, sizeof (array[0]), &elem_cmp);
// Then to run (and free) each closure:
closure_run (cl);
// This is like calling
// qsort (array, n_elements, sizeof (array[0]), &elem_cmp);
// free (cl);
*/
/* ------------------------------------------------------------------ */
/* Internal macro details follow. */
#define CLOSURE_S0(x,e) e
#define CLOSURE_S1(x,e) x##0
#define CLOSURE_S2(x,e) x##0, x##1
#define CLOSURE_S3(x,e) x##0, x##1, x##2
#define CLOSURE_S4(x,e) x##0, x##1, x##2, x##3
#define CLOSURE_S5(x,e) x##0, x##1, x##2, x##3, x##4
#define CLOSURE_S6(x,e) x##0, x##1, x##2, x##3, x##4, x##5
#define CLOSURE_S7(x,e) x##0, x##1, x##2, x##3, x##4, x##5, x##6
#define CLOSURE_S8(x,e) x##0, x##1, x##2, x##3, x##4, x##5, x##6, x##7
#define CLOSURE_S9(x,e) x##0, x##1, x##2, x##3, x##4, x##5, x##6, x##7, x##8
#define CLOSURE_P0(x,y,p,s,t)
#define CLOSURE_P1(x,y,p,s,t) p x##0 y##0 t
#define CLOSURE_P2(x,y,p,s,t) p x##0 y##0 s x##1 y##1 t
#define CLOSURE_P3(x,y,p,s,t) p x##0 y##0 s x##1 y##1 s x##2 y##2 t
#define CLOSURE_P4(x,y,p,s,t) p x##0 y##0 s x##1 y##1 s x##2 y##2 s x##3 y##3 t
#define CLOSURE_P5(x,y,p,s,t) p x##0 y##0 s x##1 y##1 s x##2 y##2 s x##3 y##3 s x##4 y##4 t
#define CLOSURE_P6(x,y,p,s,t) p x##0 y##0 s x##1 y##1 s x##2 y##2 s x##3 y##3 s x##4 y##4 s \
x##5 y##5 t
#define CLOSURE_P7(x,y,p,s,t) p x##0 y##0 s x##1 y##1 s x##2 y##2 s x##3 y##3 s x##4 y##4 s \
x##5 y##5 s x##6 y##6 t
#define CLOSURE_P8(x,y,p,s,t) p x##0 y##0 s x##1 y##1 s x##2 y##2 s x##3 y##3 s x##4 y##4 s \
x##5 y##5 s x##6 y##6 s x##7 y##7 t
#define CLOSURE_P9(x,y,p,s,t) p x##0 y##0 s x##1 y##1 s x##2 y##2 s x##3 y##3 s x##4 y##4 s \
x##5 y##5 s x##6 y##6 s x##7 y##7 s x##8 y##8 t
#define CLOSURE_COMMA_ ,
#define CLOSURE_SEMI_ ;
#define CLOSURE_BLANK_
#define CLOSURE_DECL_BODY_N_(name, n) \
struct closure_s_##name { \
void (*f0) (void *); /* must be first; matches closure. */ \
void (*f) (CLOSURE_S##n (closure_t_##name##_,void)); \
CLOSURE_P##n (closure_t_##name##_, a, CLOSURE_BLANK_, \
CLOSURE_SEMI_, CLOSURE_SEMI_) \
}; \
static void closure_f0_##name (void *v) { \
struct closure_s_##name *a = (struct closure_s_##name *) v; \
(*a->f) (CLOSURE_S##n (a->a,CLOSURE_BLANK_)); \
free (a); \
} \
static closure *closure_##name (void (*f) (CLOSURE_S##n (closure_t_##name##_,void)) \
CLOSURE_P##n (closure_t_##name##_, a, CLOSURE_COMMA_, \
CLOSURE_COMMA_, CLOSURE_BLANK_)) { \
struct closure_s_##name *cl = (struct closure_s_##name *) malloc (sizeof (*cl)); \
cl->f0 = &closure_f0_##name; \
cl->f = f; \
CLOSURE_P##n (cl->a, = a, CLOSURE_BLANK_, CLOSURE_SEMI_, CLOSURE_SEMI_) \
return ((closure *) cl); \
}
#define CLOSURE_DECL_BODY0(name) \
CLOSURE_DECL_BODY_N_ (name, 0)
#define CLOSURE_DECL_BODY1(name, t0) \
typedef t0 closure_t_##name##_0; \
CLOSURE_DECL_BODY_N_ (name, 1)
#define CLOSURE_DECL_BODY2(name, t0, t1) \
typedef t0 closure_t_##name##_0; \
typedef t1 closure_t_##name##_1; \
CLOSURE_DECL_BODY_N_ (name, 2)
#define CLOSURE_DECL_BODY3(name, t0, t1, t2) \
typedef t0 closure_t_##name##_0; \
typedef t1 closure_t_##name##_1; \
typedef t2 closure_t_##name##_2; \
CLOSURE_DECL_BODY_N_ (name, 3)
#define CLOSURE_DECL_BODY4(name, t0, t1, t2, t3) \
typedef t0 closure_t_##name##_0; \
typedef t1 closure_t_##name##_1; \
typedef t2 closure_t_##name##_2; \
typedef t3 closure_t_##name##_3; \
CLOSURE_DECL_BODY_N_ (name, 4)
#define CLOSURE_DECL_BODY5(name, t0, t1, t2, t3, t4) \
typedef t0 closure_t_##name##_0; \
typedef t1 closure_t_##name##_1; \
typedef t2 closure_t_##name##_2; \
typedef t3 closure_t_##name##_3; \
typedef t4 closure_t_##name##_4; \
CLOSURE_DECL_BODY_N_ (name, 5)
#define CLOSURE_DECL_BODY6(name, t0, t1, t2, t3, t4, t5) \
typedef t0 closure_t_##name##_0; \
typedef t1 closure_t_##name##_1; \
typedef t2 closure_t_##name##_2; \
typedef t3 closure_t_##name##_3; \
typedef t4 closure_t_##name##_4; \
typedef t5 closure_t_##name##_5; \
CLOSURE_DECL_BODY_N_ (name, 6)
#define CLOSURE_DECL_BODY7(name, t0, t1, t2, t3, t4, t5, t6) \
typedef t0 closure_t_##name##_0; \
typedef t1 closure_t_##name##_1; \
typedef t2 closure_t_##name##_2; \
typedef t3 closure_t_##name##_3; \
typedef t4 closure_t_##name##_4; \
typedef t5 closure_t_##name##_5; \
typedef t6 closure_t_##name##_6; \
CLOSURE_DECL_BODY_N_ (name, 7)
#define CLOSURE_DECL_BODY8(name, t0, t1, t2, t3, t4, t5, t6, t7) \
typedef t0 closure_t_##name##_0; \
typedef t1 closure_t_##name##_1; \
typedef t2 closure_t_##name##_2; \
typedef t3 closure_t_##name##_3; \
typedef t4 closure_t_##name##_4; \
typedef t5 closure_t_##name##_5; \
typedef t6 closure_t_##name##_6; \
typedef t7 closure_t_##name##_7; \
CLOSURE_DECL_BODY_N_ (name, 8)
#define CLOSURE_DECL_BODY9(name, t0, t1, t2, t3, t4, t5, t6, t7, t8) \
typedef t0 closure_t_##name##_0; \
typedef t1 closure_t_##name##_1; \
typedef t2 closure_t_##name##_2; \
typedef t3 closure_t_##name##_3; \
typedef t4 closure_t_##name##_4; \
typedef t5 closure_t_##name##_5; \
typedef t6 closure_t_##name##_6; \
typedef t7 closure_t_##name##_7; \
typedef t8 closure_t_##name##_8; \
CLOSURE_DECL_BODY_N_ (name, 9)
#endif /*NSYNC_TESTING_CLOSURE_H_*/