diff options
Diffstat (limited to 'libmisc/include')
-rw-r--r-- | libmisc/include/libmisc/fmt.h | 52 | ||||
-rw-r--r-- | libmisc/include/libmisc/macro.h | 34 | ||||
-rw-r--r-- | libmisc/include/libmisc/obj.h | 74 |
3 files changed, 93 insertions, 67 deletions
diff --git a/libmisc/include/libmisc/fmt.h b/libmisc/include/libmisc/fmt.h index 6c04d99..135e48b 100644 --- a/libmisc/include/libmisc/fmt.h +++ b/libmisc/include/libmisc/fmt.h @@ -113,27 +113,27 @@ struct fmt_buf { }; LO_IMPLEMENTATION_H(fmt_dest, struct fmt_buf, fmt_buf); -#define fmt_snprint(buf, n, ...) ({ \ - struct fmt_buf _w = { .dat = buf, .cap = n }; \ - lo_interface fmt_dest w = lo_box_fmt_buf_as_fmt_dest(&_w); \ - fmt_print(w, __VA_ARGS__); \ - if (_w.len < _w.cap) \ - ((char *)_w.dat)[_w.len] = '\0'; \ - _w.len; \ +#define fmt_snprint(buf, n, ...) ({ \ + struct fmt_buf _w = { .dat = buf, .cap = n }; \ + lo_interface fmt_dest w = LO_BOX(fmt_dest, &_w); \ + fmt_print(w, __VA_ARGS__); \ + if (_w.len < _w.cap) \ + ((char *)_w.dat)[_w.len] = '\0'; \ + _w.len; \ }) -#define fmt_asprint(...) ({ \ - struct fmt_buf _w = {}; \ - lo_interface fmt_dest w = lo_box_fmt_buf_as_fmt_dest(&_w); \ - fmt_print(w, __VA_ARGS__); \ - while (_w.cap <= _w.len) { \ - _w.cap = _w.len + 1; \ - _w.len = 0; \ - _w.dat = realloc(_w.dat, _w.cap); \ - fmt_print(w, __VA_ARGS__); \ - } \ - ((char *)_w.dat)[_w.len] = '\0'; \ - _w.dat; \ +#define fmt_asprint(...) ({ \ + struct fmt_buf _w = {}; \ + lo_interface fmt_dest w = LO_BOX(fmt_dest, &_w); \ + fmt_print(w, __VA_ARGS__); \ + while (_w.cap <= _w.len) { \ + _w.cap = _w.len + 1; \ + _w.len = 0; \ + _w.dat = realloc(_w.dat, _w.cap); \ + fmt_print(w, __VA_ARGS__); \ + } \ + ((char *)_w.dat)[_w.len] = '\0'; \ + _w.dat; \ }) /* justify ********************************************************************/ @@ -145,13 +145,13 @@ LO_IMPLEMENTATION_H(fmt_dest, struct fmt_buf, fmt_buf); fmt_print_byte(w, fillchar); \ } while (0) -#define fmt_print_rjust(w, width, fillchar, ...) do { \ - struct fmt_buf _discard = {}; \ - lo_interface fmt_dest discard = lo_box_fmt_buf_as_fmt_dest(&_discard); \ - fmt_print2(discard, __VA_ARGS__); \ - while (_discard.len++ < width) \ - fmt_print_byte(w, fillchar); \ - fmt_print2(w, __VA_ARGS__); \ +#define fmt_print_rjust(w, width, fillchar, ...) do { \ + struct fmt_buf _discard = {}; \ + lo_interface fmt_dest discard = LO_BOX2(fmt_dest, &_discard); \ + fmt_print2(discard, __VA_ARGS__); \ + while (_discard.len++ < width) \ + fmt_print_byte(w, fillchar); \ + fmt_print2(w, __VA_ARGS__); \ } while (0) void fmt_print_base16_u8_(lo_interface fmt_dest w, uint8_t x); diff --git a/libmisc/include/libmisc/macro.h b/libmisc/include/libmisc/macro.h index a2d4264..48f52e5 100644 --- a/libmisc/include/libmisc/macro.h +++ b/libmisc/include/libmisc/macro.h @@ -9,6 +9,8 @@ #include <libmisc/assert.h> +/* C: syntax ******************************************************************/ + #define LM_FORCE_SEMICOLON static_assert(1, "force semicolon") #define LM_PARTIAL_SWITCH(VAL) \ @@ -17,14 +19,14 @@ switch (VAL) \ _Pragma("GCC diagnostic pop") \ -/* for function definitions */ +/* C: function definitions ****************************************************/ #define LM_UNUSED(argname) #define LM_ALWAYS_INLINE [[gnu::always_inline]] inline #define LM_NEVER_INLINE [[gnu::noinline]] #define LM_FLATTEN [[gnu::flatten]] -/* types */ +/* C: types *******************************************************************/ /* If it's a pointer instead of an array, then typeof(&ptr[0]) == typeof(ptr) */ #define _LM_IS_ARRAY(ary) (!__builtin_types_compatible_p(typeof(&(ary)[0]), typeof(ary))) @@ -38,7 +40,7 @@ : NULL; \ }) -/* numeric */ +/* C: numeric *****************************************************************/ #define LM_CEILDIV(n, d) ( ((n)+(d)-1) / (d) ) /** Return ceil(n/d) */ #define LM_ROUND_UP(n, d) ( LM_CEILDIV(n, d) * (d) ) /** Return `n` rounded up to the nearest multiple of `d` */ @@ -46,12 +48,12 @@ #define LM_NEXT_POWER_OF_2(x) ( (x) ? 1ULL<<((sizeof(unsigned long long)*8)-__builtin_clzll(x)) : 1) /** Return the lowest power of 2 that is > x */ #define LM_FLOORLOG2(x) ((sizeof(unsigned long long)*8)-__builtin_clzll(x)-1) /** Return floor(log_2(x) */ -/* strings */ +/* CPP: strings ***************************************************************/ #define LM_STR(x) #x #define LM_STR_(x) LM_STR(x) -/* token pasting */ +/* CPP: token pasting *********************************************************/ #define LM_CAT2(a, b) a ## b #define LM_CAT3(a, b, c) a ## b ## c @@ -59,7 +61,7 @@ #define LM_CAT2_(a, b) LM_CAT2(a, b) #define LM_CAT3_(a, b, c) LM_CAT3(a, b, c) -/* macro arguments */ +/* CPP: macro arguments *******************************************************/ #define LM_FIRST(a, ...) a #define LM_SECOND(a, b, ...) b @@ -70,7 +72,7 @@ #define LM_EAT(...) #define LM_EXPAND(...) __VA_ARGS__ -/* conditionals */ +/* CPP: conditionals **********************************************************/ #define LM_T xxTxx #define LM_F xxFxx @@ -82,7 +84,7 @@ #define _LM_IF__xxTxx(...) __VA_ARGS__ LM_EAT #define _LM_IF__xxFxx(...) LM_EXPAND -/* tuples */ +/* CPP: tuples ****************************************************************/ #define LM_IS_TUPLE(x) LM_IS_SENTINEL(_LM_IS_TUPLE x) #define _LM_IS_TUPLE(...) LM_SENTINEL() @@ -112,7 +114,7 @@ #define LM_TUPLES_HEAD(tuples) LM_EXPAND(LM_FIRST LM_EAT() (_LM_TUPLES_COMMA tuples)) #define LM_TUPLES_TAIL(tuples) LM_EAT tuples -/* iteration */ +/* CPP: iteration *************************************************************/ /* The desire to support a high number of iterations is in competition * with the desire for short compile times. 16 is the lowest @@ -168,4 +170,18 @@ /** The same as LM_FOREACH_TUPLE(), but callable from inside of LM_FOREACH_TUPLE(). */ #define LM_FOREACH_TUPLE2(...) _LM_DEFER2(_LM_FOREACH_TUPLE_indirect)()(__VA_ARGS__) +/* CPP: wrap-cc extensions ****************************************************/ + +#ifdef __LIBMISC_ENHANCED_CPP__ +/** + * `LM_DEFAPPEND(macro, val)` is like `#define macro val`, but can (1) + * be used from inside of a macro, and (2) appends to a value if it is + * already defined with LM_DEFAPPEND. There are lots of edge-cases, + * don't get cute. + */ +#define LM_DEFAPPEND(macro, ...) __xx__LM_DEFAPPEND__xx__(#macro, #__VA_ARGS__) LM_FORCE_SEMICOLON +#define LM_DEFAPPEND_(macro, ...) _LM_DEFAPPEND_(#macro, __VA_ARGS__) +#define _LM_DEFAPPEND_(macrostr, ...) __xx__LM_DEFAPPEND__xx__(macrostr, #__VA_ARGS__) LM_FORCE_SEMICOLON +#endif + #endif /* _LIBMISC_MACRO_H_ */ diff --git a/libmisc/include/libmisc/obj.h b/libmisc/include/libmisc/obj.h index 6645db7..6afa391 100644 --- a/libmisc/include/libmisc/obj.h +++ b/libmisc/include/libmisc/obj.h @@ -30,10 +30,6 @@ * * Use `lo_interface {iface_name}` as the type of this interface; it * should not be a pointer type. - * - * If there are any LO_NEST interfaces, this will define a - * `lo_box_{iface_name}_as_{wrapped_iface_name}(obj)` function for - * each. */ #define LO_NEST(_ARG_child_iface_name) \ (lo_nest, _ARG_child_iface_name) @@ -50,28 +46,48 @@ }; \ LM_FOREACH_TUPLE(_ARG_iface_name##_LO_IFACE, \ _LO_IFACE_PROTO, _ARG_iface_name) \ - extern int LM_CAT2_(_HIDDEN_BOGUS_, __COUNTER__) + LM_FORCE_SEMICOLON -#define _LO_IFACE_VTABLE(_tuple_typ, ...) _LO_IFACE_VTABLE_##_tuple_typ(__VA_ARGS__) -#define _LO_IFACE_VTABLE_lo_nest(_ARG_child_iface_name) const struct _lo_##_ARG_child_iface_name##_vtable *_lo_##_ARG_child_iface_name##_vtable; LM_FOREACH_TUPLE2(_ARG_child_iface_name##_LO_IFACE, _LO_IFACE_VTABLE2) -#define _LO_IFACE_VTABLE_lo_func(_ARG_ret_type, _ARG_func_name, ...) _ARG_ret_type (*_ARG_func_name)(void * __VA_OPT__(,) __VA_ARGS__); +#define _LO_IFACE_VTABLE(_tuple_typ, ...) _LO_IFACE_VTABLE_##_tuple_typ(__VA_ARGS__) +#define _LO_IFACE_VTABLE_lo_nest(_ARG_child_iface_name) \ + const struct _lo_##_ARG_child_iface_name##_vtable *_lo_##_ARG_child_iface_name##_vtable; \ + LM_FOREACH_TUPLE2(_ARG_child_iface_name##_LO_IFACE, _LO_IFACE_VTABLE2) +#define _LO_IFACE_VTABLE_lo_func(_ARG_ret_type, _ARG_func_name, ...) \ + _ARG_ret_type (*_ARG_func_name)(void * __VA_OPT__(,) __VA_ARGS__); #define _LO_IFACE_VTABLE_indirect() _LO_IFACE_VTABLE #define _LO_IFACE_VTABLE2(...) _LM_DEFER2(_LO_IFACE_VTABLE_indirect)()(__VA_ARGS__) -#define _LO_IFACE_PROTO(_ARG_iface_name, _tuple_typ, ...) _LO_IFACE_PROTO_##_tuple_typ(_ARG_iface_name, __VA_ARGS__) -#define _LO_IFACE_PROTO_lo_nest(_ARG_iface_name, _ARG_child_iface_name) \ - LM_ALWAYS_INLINE static lo_interface _ARG_child_iface_name \ - box_##_ARG_iface_name##_as_##_ARG_child_iface_name(lo_interface _ARG_iface_name obj) { \ - return (lo_interface _ARG_child_iface_name){ \ - .self = obj.self, \ - .vtable = obj.vtable->_lo_##_ARG_child_iface_name##_vtable, \ - }; \ - } +#define _LO_IFACE_PROTO(_ARG_iface_name, _tuple_typ, ...) _LO_IFACE_PROTO_##_tuple_typ(_ARG_iface_name, __VA_ARGS__) +#define _LO_IFACE_PROTO_lo_nest(_ARG_iface_name, _ARG_child_iface_name) \ + LM_DEFAPPEND(_LO_REGISTRY_##_ARG_child_iface_name, \ + (lo_interface _ARG_iface_name, _LO_BOX_##_ARG_iface_name##_as_##_ARG_child_iface_name)); \ + LM_DEFAPPEND(_LO_BOX_##_ARG_iface_name##_as_##_ARG_child_iface_name(obj), \ + { .self = obj.self, .vtable = obj.vtable->_lo_##_ARG_child_iface_name##_vtable }); #define _LO_IFACE_PROTO_lo_func(_ARG_iface_name, _ARG_ret_type, _ARG_func_name, ...) \ /* empty */ /** + * `LO_BOX(iface_name, obj)` boxes `obj` as a `lo_interface + * iface_name`. `obj` must be one of: + * + * - A pointer to a value that implements `lo_interface iface_name` + * - An already-boxed instance of `lo_interface iface_name` + * - An already-boxed instance of another interface that + * `iface_name` inherits from. + */ +#define LO_BOX(_ARG_iface_name, obj) _Generic((obj), \ + lo_interface _ARG_iface_name: obj \ + LM_FOREACH_TUPLE(_LO_REGISTRY_##_ARG_iface_name, \ + _LO_BOX, _ARG_iface_name, obj)) +#define LO_BOX2(_ARG_iface_name, obj) _Generic((obj), \ + lo_interface _ARG_iface_name: obj \ + LM_FOREACH_TUPLE2(_LO_REGISTRY_##_ARG_iface_name, \ + _LO_BOX, _ARG_iface_name, obj)) +#define _LO_BOX(_ARG_iface_name, obj, typ, boxfn) \ + , typ: (lo_interface _ARG_iface_name)boxfn(obj) + +/** * `LO_NULL(iface_name)` is the null/nil/zero value for `lo_interface {iface_name}`. */ #define LO_NULL(_ARG_iface_name) ((lo_interface _ARG_iface_name){}) @@ -99,23 +115,17 @@ * file to declare that `{impl_type}` implements the `{iface_name}` * interface with functions named `{impl_name}_{method_name}`. * - * This will also define a `lo_box_{impl_name}_as_{iface_name}(obj)` - * function. - * * You must also call the LO_IMPLEMENTATION_C in a single .c file. */ -#define LO_IMPLEMENTATION_H(_ARG_iface_name, _ARG_impl_type, _ARG_impl_name) \ - /* Vtable. */ \ - extern const struct _lo_##_ARG_iface_name##_vtable \ - _lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable; \ - /* Boxing. */ \ - LM_ALWAYS_INLINE static lo_interface _ARG_iface_name \ - lo_box_##_ARG_impl_name##_as_##_ARG_iface_name(_ARG_impl_type *self) { \ - return (lo_interface _ARG_iface_name){ \ - .self = self, \ - .vtable = &_lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable, \ - }; \ - } \ +#define LO_IMPLEMENTATION_H(_ARG_iface_name, _ARG_impl_type, _ARG_impl_name) \ + /* Vtable. */ \ + extern const struct _lo_##_ARG_iface_name##_vtable \ + _lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable; \ + /* Boxing. */ \ + LM_DEFAPPEND(_LO_REGISTRY_##_ARG_iface_name, \ + (_ARG_impl_type *, _LO_BOX_##_ARG_impl_name##_as_##_ARG_iface_name)); \ + LM_DEFAPPEND(_LO_BOX_##_ARG_impl_name##_as_##_ARG_iface_name(obj), \ + { .self = obj, .vtable = &_lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable }); \ LM_FORCE_SEMICOLON /** |