lib: os: cbprintf: Improve C++ support in static packaging

Added C++ replacements for macros that are using _Generic
keyword.

Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruscinski 2021-04-29 12:15:43 +02:00 committed by Anas Nashif
commit 6f227698bb
3 changed files with 178 additions and 21 deletions

View file

@ -16,17 +16,16 @@
#include <stdio.h>
#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 <sys/cbprintf_internal.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup cbprintf_apis Formatted Output APIs
* @ingroup support_apis

131
include/sys/cbprintf_cxx.h Normal file
View file

@ -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_ */

View file

@ -15,10 +15,6 @@
#include <sys/util.h>
#include <sys/__assert.h>
#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 <sys/cbprintf_cxx.h>
#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; \
} \