Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: os: cbprintf: Add C++ support for static packaging #34697

Merged
merged 2 commits into from
May 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions include/sys/cbprintf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
131 changes: 131 additions & 0 deletions include/sys/cbprintf_cxx.h
Original file line number Diff line number Diff line change
@@ -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_ */
55 changes: 39 additions & 16 deletions include/sys/cbprintf_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@
#include <sys/util.h>
#include <sys/__assert.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
* Special alignment cases
*/
Expand Down Expand Up @@ -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
Expand All @@ -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, \
Expand All @@ -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.
*
Expand Down Expand Up @@ -123,27 +137,27 @@ 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), \
default : \
/* 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.
*
* @param buf Buffer.
*
* @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.*/ \
Expand All @@ -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 { \
Expand All @@ -176,13 +190,17 @@ 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.
*
* @param _arg Argument
*
* @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), \
Expand All @@ -192,15 +210,20 @@ 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.
*
* @param x Argument.
*
* @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.
*
Expand All @@ -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; \
Expand Down Expand Up @@ -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; \
Expand All @@ -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; \
} \
Expand Down
3 changes: 1 addition & 2 deletions tests/lib/cbprintf_package/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ cmake_minimum_required(VERSION 3.13.1)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(cbprintf_package)

FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
target_sources(app PRIVATE src/main.c src/maincxx.cxx)
Loading