/* -*- Mode: C; -*- * ---------------------------------------------------------------------------- * Title: Dynamic Bind Syntactic Sugar * Created: 2020-05-23 * Author: Gilbert Baumann * ---------------------------------------------------------------------------- * (c) copyright 2020 by Gilbert Baumann */ #include #include struct dynbind_frame { void *addr; /* pointer to lvalue bound */ const void *old; /* pointer to saved value */ size_t sz; /* size of value */ }; static void dynbind_cleanup (const struct dynbind_frame *frame) { memcpy (frame->addr, frame->old, frame->sz); } #define dynbind(lvalue, val) \ for (int run##__LINE__ = 1; run##__LINE__; ) \ for ( __typeof__(lvalue) * const addr##__LINE__ = &(lvalue); \ run##__LINE__; ) \ for (const __typeof__(lvalue) old##__LINE__ = *addr##__LINE__; \ run##__LINE__;) \ for (const struct dynbind_frame save##__LINE__ \ __attribute__ ((cleanup (dynbind_cleanup))) \ = { addr##__LINE__, \ &old##__LINE__, \ sizeof (lvalue) }; \ run##__LINE__;) \ for (*addr##__LINE__ = (val); \ run##__LINE__; \ run##__LINE__ = 0) /* -- Demo ----------------------------------------------------------------- */ int xyz = 0; struct point { int x, y; } pt; extern struct point *quux (void); extern int bar (void); void foo (void) { dynbind (xyz, 46) { bar (); } } void foo_pt (void) { struct point q = { 100, 200 }; dynbind (pt, q) { bar (); } } void foo_eval (void) { dynbind (quux()->x, 100) bar (); } /* -- Changes -------------------------------------------------------------- */ /* * - renamed a few things * * - what was a struct for k, addr, and old value is now three * separate for()s * * - spend a few 'const' in the hope to help the compiler. * * - renamed 'k' to 'run' and made it a flag insted of a counter. * * - fixed it, so that lvalue is evaluated just once. * */