diff --git a/include/macros.h b/include/macros.h index 402ae94..cdd13ee 100644 --- a/include/macros.h +++ b/include/macros.h @@ -23,11 +23,12 @@ #define noinline __attribute__((noinline)) #define always_inline __attribute__((always_inline)) +#define force_inline __attribute__((gnu_inline)) #ifdef DEBUG -#define _mixin static inline always_inline +#define _mixin static inline force_inline #else -#define _mixin extern inline always_inline +#define _mixin extern inline force_inline #endif #define unrestrict __attribute__((may_alias)) diff --git a/include/version.h b/include/version.h index 7d0789a..020d121 100644 --- a/include/version.h +++ b/include/version.h @@ -41,39 +41,23 @@ _mixin uint32_t v_ctoraw(version_t ver) #define VERSION_STRING_MAX AS(3 + 3 + 3 + 3 + 3, usize) // maj + min + bf + rev + (..r) -//TODO: Move the below functions to `version.c` and have them prototyped, not mixins. - /// Print a version to a string buffer `out`. Return the number of bytes written. /// /// Has the same semantics as `snprintf`; to calculate the length of the string needed to allocate, invoke like: `size_t sz = v_ctosn(vers, 0, NULL)`. The buffer should be allocated as `sz + 1`, and then the next call to `v_ctosn` should be like: `v_ctosn(vers, sz+1, buffer); -_mixin usize v_ctosn(version_t ver, usize max, char out[static pOUT max]) +//XXX: Specifying `str[static ...` tells the compiler this function expects a non-null pointer. When in reality, a `NULL` pointer is used here as a sentinel value to not print... The mixin below is a hack around this, but this might introduce invalid optimisations. We should either: split the size getting function into its own thing (`v_ctosn_sz` would become a real function) that does the exact same thing as `v_ctosn(_,0,NULL)`, and not pass `NULL` to str here ever. OR, change str to regular `char *pOUT str`. The latter would be easier, but we might potentially lose out on some obscure non-NULL snprintf optimisation? For now, just use the `v_ctosn_sz` hack below. If we go with the latter, we can #define it to be just `v_ctosn(v, 0, NULL)`, otherwise move it to version.c and implement it with `snprintf(NULL, 0, ...)`. +usize v_ctosn(version_t ver, usize max, char str[static pOUT max]); +_mixin usize v_ctosn_sz(version_t ver) { - struct v_comp comp = ver.comp; - const char* const fmt = comp.revision ? "%hhu.%hhu.%hhur%hhu" : "%hhu.%hhu.%hhu"; - - - return snprintf(out, max, fmt, - comp.major, - comp.minor, - comp.bugfix, - comp.revision); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" + return v_ctosn(ver, 0, NULL); +#pragma GCC diagnostic pop } /// Print a version to a static string buffer. The string buffer is thread local. The next call to this function on the same thread will overwrite the returned buffer. -_mixin const char* v_ctoss(version_t ver) -{ - _Thread_local static char buffer[VERSION_STRING_MAX+1]; - buffer[v_ctosn(ver, VERSION_STRING_MAX+1, buffer)] = 0; - return buffer; -} +const char* v_ctoss(version_t ver); /// Print a version to a `malloc()`d string buffer. The buffer is unique and owned by the callee. The buffer must be `free()`d. -_mixin char* v_ctos(version_t ver) -{ - usize sz = v_ctosn(ver, 0, NULL); - char* buf = malloc(sz+1); - v_ctosn(ver, sz+1, buf); - return buf; -} +char* v_ctos(version_t ver); #endif /* _VERSION_H */ diff --git a/src/main.c b/src/main.c index cfce1ae..d5c4bca 100644 --- a/src/main.c +++ b/src/main.c @@ -13,10 +13,10 @@ int main(int argc, char** argv) IGNORE(argc); IGNORE(argv); - const u32 vraw = VERSION(1,2,3,240); + const u32 vraw = VERSION(100,200,101,255); version_t vers = v_rawtoc(vraw); - usize sz = v_ctosn(vers, 0, NULL); + usize sz = v_ctosn_sz(vers); char verstr[sz+1]; v_ctosn(vers, sz+1, verstr); diff --git a/src/version.c b/src/version.c new file mode 100644 index 0000000..44a4ce7 --- /dev/null +++ b/src/version.c @@ -0,0 +1,34 @@ +#include +#include +#include + +#include + +usize v_ctosn(version_t ver, usize max, char out[static pOUT max]) +{ + struct v_comp comp = ver.comp; + const char* const fmt = comp.revision ? "%hhu.%hhu.%hhur%hhu" : "%hhu.%hhu.%hhu"; + + + return snprintf(out, max, fmt, + comp.major, + comp.minor, + comp.bugfix, + comp.revision); +} + +const char* v_ctoss(version_t ver) +{ + _Thread_local static char buffer[VERSION_STRING_MAX+1]; + buffer[v_ctosn(ver, VERSION_STRING_MAX+1, buffer)] = 0; + return buffer; +} + +char* v_ctos(version_t ver) +{ + usize sz = v_ctosn_sz(ver); + char* buf = malloc(sz+1); + v_ctosn(ver, sz+1, buf); + return buf; +} +