#ifndef MAG_HANDLE_H #define MAG_HANDLE_H /* Simple single-header library that makes you have RAII in gcc (also works in C++ compilers) */ /** Tells your constructor/destructor handler function about the state */ enum HANDLE_STATE { HANDLE_CREAT, HANDLE_DESTR }; #ifndef __cplusplus #define creat(TNAME, VNAME, VINIT) \ [[gnu::always_inline]] inline void VNAME##_cleanuper(struct TNAME *v) { \ TNAME##_lifetime_handler(HANDLE_DESTR, v, NULL); \ } \ [[gnu::cleanup(VNAME##_cleanuper)]] struct TNAME VNAME; \ TNAME##_lifetime_handler(HANDLE_CREAT, & VNAME, VINIT); #define handle(TNAME) \ static inline void TNAME##_lifetime_handler( \ enum HANDLE_STATE state, \ struct TNAME *self, \ void *data) #else /* C++ compilers better be able to compile code written with us */ #define creat(TNAME, VNAME, VINIT) \ TNAME##_raiicpp VNAME(VINIT); #define handle(TNAME) \ struct TNAME##_raiicpp; \ static inline void TNAME##_lifetime_handler( \ enum HANDLE_STATE state, \ struct TNAME##_raiicpp *self, \ void *data); \ struct TNAME##_raiicpp : public TNAME { \ inline TNAME##_raiicpp(void *data) { \ TNAME##_lifetime_handler(HANDLE_CREAT, this, data); \ } \ inline ~TNAME##_raiicpp() { \ TNAME##_lifetime_handler(HANDLE_DESTR, this, nullptr); \ } \ }; \ static inline void TNAME##_lifetime_handler( \ enum HANDLE_STATE state, \ struct TNAME##_raiicpp *self, \ void *data) #endif /* __cplusplus */ /* * EXAMPLE: * * struct Meaning { * int a; * int b; * }; * // You should not typedef this EVER! * * handle(Meaning) { * if(state == HANDLE_CREAT) { * self->a = *(int*) data; * self->b = 2; * } else { * printf("%d\n", self->a + self->b); * } * } * * // Now you can use a handle in your local scopes * // Should print 42: * int main() { * int initializer = 40; * creat(Meaning, d, &initializer); * } * * Rem.: Unrelated trick, but you can typedef struct A A; // both typedef and forward declare */ #endif /* MAG_HANDLE_H */