2025-04-24 20:06:09 +02:00
|
|
|
#ifndef MAG_HANDLE_H
|
|
|
|
#define MAG_HANDLE_H
|
2025-04-25 00:05:39 +02:00
|
|
|
/* Simple single-header library that makes you have RAII in gcc (also works in C++ compilers) */
|
2025-04-25 21:44:24 +02:00
|
|
|
/* Licence: CC-BY */
|
2025-04-24 20:06:09 +02:00
|
|
|
|
|
|
|
/** Tells your constructor/destructor handler function about the state */
|
|
|
|
enum HANDLE_STATE {
|
|
|
|
HANDLE_CREAT,
|
2025-04-24 20:58:06 +02:00
|
|
|
HANDLE_DESTR
|
2025-04-24 20:06:09 +02:00
|
|
|
};
|
|
|
|
|
2025-04-25 00:05:39 +02:00
|
|
|
#ifndef __cplusplus
|
|
|
|
|
2025-04-24 20:58:06 +02:00
|
|
|
#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, \
|
2025-04-25 00:05:39 +02:00
|
|
|
struct TNAME *self, \
|
2025-04-24 20:58:06 +02:00
|
|
|
void *data)
|
2025-04-25 00:05:39 +02:00
|
|
|
|
|
|
|
#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 */
|
2025-04-24 20:58:06 +02:00
|
|
|
/*
|
|
|
|
* EXAMPLE:
|
2025-04-24 20:06:09 +02:00
|
|
|
*
|
|
|
|
* struct Meaning {
|
|
|
|
* int a;
|
|
|
|
* int b;
|
|
|
|
* };
|
2025-04-24 20:58:06 +02:00
|
|
|
* // You should not typedef this EVER!
|
2025-04-24 20:06:09 +02:00
|
|
|
*
|
2025-04-24 20:58:06 +02:00
|
|
|
* handle(Meaning) {
|
2025-04-24 20:06:09 +02:00
|
|
|
* if(state == HANDLE_CREAT) {
|
2025-04-25 00:05:39 +02:00
|
|
|
* self->a = *(int*) data;
|
|
|
|
* self->b = 2;
|
2025-04-24 20:06:09 +02:00
|
|
|
* } else {
|
2025-04-25 00:05:39 +02:00
|
|
|
* printf("%d\n", self->a + self->b);
|
2025-04-24 20:06:09 +02:00
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* // Now you can use a handle in your local scopes
|
|
|
|
* // Should print 42:
|
|
|
|
* int main() {
|
|
|
|
* int initializer = 40;
|
2025-04-24 20:58:06 +02:00
|
|
|
* creat(Meaning, d, &initializer);
|
2025-04-24 20:06:09 +02:00
|
|
|
* }
|
|
|
|
*
|
|
|
|
* Rem.: Unrelated trick, but you can typedef struct A A; // both typedef and forward declare
|
|
|
|
*/
|
2025-04-25 00:05:39 +02:00
|
|
|
#endif /* MAG_HANDLE_H */
|