From 6f227698bb07e91d9eb4475cc8b94a65bf4c995d Mon Sep 17 00:00:00 2001 From: Krzysztof Chruscinski Date: Thu, 29 Apr 2021 12:15:43 +0200 Subject: [PATCH] lib: os: cbprintf: Improve C++ support in static packaging Added C++ replacements for macros that are using _Generic keyword. Signed-off-by: Krzysztof Chruscinski --- include/sys/cbprintf.h | 13 ++-- include/sys/cbprintf_cxx.h | 131 ++++++++++++++++++++++++++++++++ include/sys/cbprintf_internal.h | 55 ++++++++++---- 3 files changed, 178 insertions(+), 21 deletions(-) create mode 100644 include/sys/cbprintf_cxx.h diff --git a/include/sys/cbprintf.h b/include/sys/cbprintf.h index e366829add4..9830363676b 100644 --- a/include/sys/cbprintf.h +++ b/include/sys/cbprintf.h @@ -16,17 +16,16 @@ #include #endif /* CONFIG_CBPRINTF_LIBC_SUBSTS */ -#ifdef __cplusplus -extern "C" { -#endif - /* Determine if _Generic is supported. * In general it's a C11 feature but it was added also in: * - GCC 4.9.0 https://gcc.gnu.org/gcc-4.9/changes.html * - Clang 3.0 https://releases.llvm.org/3.0/docs/ClangReleaseNotes.html + * + * @note Z_C_GENERIC is also set for C++ where functionality is implemented + * using overloading and templates. */ #ifndef Z_C_GENERIC -#if !defined(__cplusplus) && (((__STDC_VERSION__ >= 201112L) || \ +#if defined(__cplusplus) || (((__STDC_VERSION__ >= 201112L) || \ ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40900) || \ ((__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) >= 30000))) #define Z_C_GENERIC 1 @@ -38,6 +37,10 @@ extern "C" { /* Z_C_GENERIC is used there */ #include +#ifdef __cplusplus +extern "C" { +#endif + /** * @defgroup cbprintf_apis Formatted Output APIs * @ingroup support_apis diff --git a/include/sys/cbprintf_cxx.h b/include/sys/cbprintf_cxx.h new file mode 100644 index 00000000000..40333319125 --- /dev/null +++ b/include/sys/cbprintf_cxx.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SYS_CBPRINTF_CXX_H_ +#define ZEPHYR_INCLUDE_SYS_CBPRINTF_CXX_H_ +#ifdef __cplusplus + +/* C++ version for detecting a pointer to a string. */ +static inline int z_cbprintf_cxx_is_pchar(char *) +{ + return 1; +} + +static inline int z_cbprintf_cxx_is_pchar(const char *) +{ + return 1; +} + +static inline int z_cbprintf_cxx_is_pchar(volatile char *) +{ + return 1; +} + +static inline int z_cbprintf_cxx_is_pchar(const volatile char *) +{ + return 1; +} + +static inline int z_cbprintf_cxx_is_pchar(wchar_t *) +{ + return 1; +} + +static inline int z_cbprintf_cxx_is_pchar(const wchar_t *) +{ + return 1; +} + +static inline int z_cbprintf_cxx_is_pchar(volatile wchar_t *) +{ + return 1; +} + +static inline int z_cbprintf_cxx_is_pchar(const volatile wchar_t *) +{ + return 1; +} + +template < typename T > +static inline int z_cbprintf_cxx_is_pchar(T arg) +{ + return 0; +} + +/* C++ version for calculating argument size. */ +static inline size_t z_cbprintf_cxx_arg_size(float f) +{ + return sizeof(double); +} + +template < typename T > +static inline size_t z_cbprintf_cxx_arg_size(T arg) +{ + return sizeof(arg + 0); +} + +/* C++ version for storing arguments. */ +static inline void z_cbprintf_cxx_store_arg(uint8_t *dst, float arg) +{ + double d = (double)arg; + + z_cbprintf_wcpy((int *)dst, (int *)&d, sizeof(d) / sizeof(int)); +} + +template < typename T > +static inline void z_cbprintf_cxx_store_arg(uint8_t *dst, T arg) +{ + size_t wlen = z_cbprintf_cxx_arg_size(arg) / sizeof(int); + + z_cbprintf_wcpy((int *)dst, (int *)&arg, wlen); +} + +/* C++ version for long double detection. */ +static inline int z_cbprintf_cxx_is_longdouble(long double arg) +{ + return 1; +} + +template < typename T > +static inline int z_cbprintf_cxx_is_longdouble(T arg) +{ + return 0; +} + +/* C++ version for caluculating argument alignment. */ +static inline size_t z_cbprintf_cxx_alignment(float arg) +{ + return VA_STACK_ALIGN(double); +} + +static inline size_t z_cbprintf_cxx_alignment(double arg) +{ + return VA_STACK_ALIGN(double); +} + +static inline size_t z_cbprintf_cxx_alignment(long double arg) +{ + return VA_STACK_ALIGN(long double); +} + +static inline size_t z_cbprintf_cxx_alignment(long long arg) +{ + return VA_STACK_ALIGN(long long); +} + +static inline size_t z_cbprintf_cxx_alignment(unsigned long long arg) +{ + return VA_STACK_ALIGN(long long); +} + +template < typename T > +static inline size_t z_cbprintf_cxx_alignment(T arg) +{ + return MAX(__alignof__(arg), VA_STACK_MIN_ALIGN); +} + +#endif /* __cplusplus */ +#endif /* ZEPHYR_INCLUDE_SYS_CBPRINTF_CXX_H_ */ diff --git a/include/sys/cbprintf_internal.h b/include/sys/cbprintf_internal.h index 5082cabbf03..b6e9f2a0cd2 100644 --- a/include/sys/cbprintf_internal.h +++ b/include/sys/cbprintf_internal.h @@ -15,10 +15,6 @@ #include #include -#ifdef __cplusplus -extern "C" { -#endif - /* * Special alignment cases */ @@ -49,6 +45,20 @@ extern "C" { #define VA_STACK_ALIGN(type) MAX(VA_STACK_MIN_ALIGN, __alignof__(type)) #endif +static inline void z_cbprintf_wcpy(int *dst, int *src, size_t len) +{ + for (size_t i = 0; i < len; i++) { + dst[i] = src[i]; + } +} + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + #if defined(__sparc__) /* The SPARC V8 ABI guarantees that the arguments of a variable argument * list function are stored on the stack at addresses which are 32-bit @@ -71,6 +81,9 @@ extern "C" { * * @return 1 if char * or wchar_t *, 0 otherwise. */ +#ifdef __cplusplus +#define Z_CBPRINTF_IS_PCHAR(x) z_cbprintf_cxx_is_pchar(x) +#else #define Z_CBPRINTF_IS_PCHAR(x) _Generic((x), \ char * : 1, \ const char * : 1, \ @@ -82,6 +95,7 @@ extern "C" { const volatile wchar_t * : 1, \ default : \ 0) +#endif /** @brief Calculate number of char * or wchar_t * arguments in the arguments. * @@ -123,6 +137,9 @@ extern "C" { * * @return Number of bytes used for storing the argument. */ +#ifdef __cplusplus +#define Z_CBPRINTF_ARG_SIZE(v) z_cbprintf_cxx_arg_size(v) +#else #define Z_CBPRINTF_ARG_SIZE(v) \ _Generic((v), \ float : sizeof(double), \ @@ -130,13 +147,7 @@ extern "C" { /* coverity[bad_sizeof] */ \ sizeof((v) + 0) \ ) - -static inline void cbprintf_wcpy(int *dst, int *src, size_t len) -{ - for (size_t i = 0; i < len; i++) { - dst[i] = src[i]; - } -} +#endif /** @brief Promote and store argument in the buffer. * @@ -144,6 +155,9 @@ static inline void cbprintf_wcpy(int *dst, int *src, size_t len) * * @param arg Argument. */ +#ifdef __cplusplus +#define Z_CBPRINTF_STORE_ARG(buf, arg) z_cbprintf_cxx_store_arg(buf, arg) +#else #define Z_CBPRINTF_STORE_ARG(buf, arg) do { \ if (Z_CBPRINTF_VA_STACK_LL_DBL_MEMCPY) { \ /* If required, copy arguments by word to avoid unaligned access.*/ \ @@ -154,7 +168,7 @@ static inline void cbprintf_wcpy(int *dst, int *src, size_t len) 0.0); \ size_t arg_size = Z_CBPRINTF_ARG_SIZE(arg); \ size_t _wsize = arg_size / sizeof(int); \ - cbprintf_wcpy((int *)buf, \ + z_cbprintf_wcpy((int *)buf, \ (int *) _Generic((arg) + 0, float : &_d, default : &_v), \ _wsize); \ } else { \ @@ -176,6 +190,7 @@ static inline void cbprintf_wcpy(int *dst, int *src, size_t len) (const void **)buf) = arg; \ } \ } while (0) +#endif /** @brief Return alignment needed for given argument. * @@ -183,6 +198,9 @@ static inline void cbprintf_wcpy(int *dst, int *src, size_t len) * * @return Alignment in bytes. */ +#ifdef __cplusplus +#define Z_CBPRINTF_ALIGNMENT(_arg) z_cbprintf_cxx_alignment(_arg) +#else #define Z_CBPRINTF_ALIGNMENT(_arg) \ MAX(_Generic((_arg) + 0, \ float : VA_STACK_ALIGN(double), \ @@ -192,6 +210,7 @@ static inline void cbprintf_wcpy(int *dst, int *src, size_t len) unsigned long long : VA_STACK_ALIGN(long long), \ default : \ __alignof__((_arg) + 0)), VA_STACK_MIN_ALIGN) +#endif /** @brief Detect long double variable. * @@ -199,8 +218,12 @@ static inline void cbprintf_wcpy(int *dst, int *src, size_t len) * * @return 1 if @p x is a long double, 0 otherwise. */ +#ifdef __cplusplus +#define Z_CBPRINTF_IS_LONGDOUBLE(x) z_cbprintf_cxx_is_longdouble(x) +#else #define Z_CBPRINTF_IS_LONGDOUBLE(x) \ _Generic((x) + 0, long double : 1, default : 0) +#endif /** @brief Safely package arguments to a buffer. * @@ -227,7 +250,7 @@ static inline void cbprintf_wcpy(int *dst, int *src, size_t len) _align_offset += sizeof(int); \ } \ uint32_t _arg_size = Z_CBPRINTF_ARG_SIZE(_arg); \ - if (_buf && _idx < _max) { \ + if (_buf && _idx < (int)_max) { \ Z_CBPRINTF_STORE_ARG(&_buf[_idx], _arg); \ } \ _idx += _arg_size; \ @@ -302,7 +325,7 @@ do { \ "Buffer must be aligned."); \ } \ uint8_t *_pbuf = buf; \ - size_t _pmax = (buf != NULL) ? _inlen : SIZE_MAX; \ + size_t _pmax = (buf != NULL) ? _inlen : INT32_MAX; \ int _pkg_len = 0; \ int _pkg_offset = _align_offset; \ union z_cbprintf_hdr *_len_loc; \ @@ -317,11 +340,11 @@ do { \ /* Pack remaining arguments */\ FOR_EACH(Z_CBPRINTF_PACK_ARG, (;), __VA_ARGS__);\ /* Store length */ \ - _outlen = (_pkg_len > _pmax) ? -ENOSPC : _pkg_len; \ + _outlen = (_pkg_len > (int)_pmax) ? -ENOSPC : _pkg_len; \ /* Store length in the header, set number of dumped strings to 0 */ \ if (_pbuf) { \ union z_cbprintf_hdr hdr = { \ - .desc = {.len = _pkg_len / sizeof(int) } \ + .desc = {.len = (uint8_t)(_pkg_len / sizeof(int)) } \ }; \ *_len_loc = hdr; \ } \