shared/c-stdaux: merge initial import of 'shared/c-stdaux'

Imported c-stdaux code with command:

  git subtree add --prefix shared/c-stdaux git@github.com:c-util/c-stdaux.git master --squash

To update the library use:

  git subtree pull --prefix shared/c-stdaux git@github.com:c-util/c-stdaux.git master --squash
This commit is contained in:
Thomas Haller 2019-04-14 11:16:55 +02:00
commit 5eab3c9987
11 changed files with 1377 additions and 0 deletions

View file

@ -0,0 +1,12 @@
#!/bin/bash
set -e
rm -Rf "./ci-build"
mkdir "./ci-build"
cd "./ci-build"
${CHERRY_LIB_MESONSETUP} . "${CHERRY_LIB_SRCDIR}"
${CHERRY_LIB_NINJABUILD}
${CHERRY_LIB_MESONTEST}
(( ! CHERRY_LIB_VALGRIND )) || ${CHERRY_LIB_MESONTEST} "--wrapper=${CHERRY_LIB_VALGRINDWRAP}"

View file

@ -0,0 +1,11 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
[*.{c,h}]
indent_style = space
indent_size = 8

View file

@ -0,0 +1,21 @@
os: linux
dist: trusty
language: c
services:
- docker
before_install:
- curl -O -L "https://raw.githubusercontent.com/cherry-pick/cherry-images/v1/scripts/vmrun"
- curl -O -L "https://raw.githubusercontent.com/cherry-pick/cherry-ci/v1/scripts/cherryci"
- chmod +x "./vmrun" "./cherryci"
jobs:
include:
- stage: test
script:
- ./vmrun -- ../src/cherryci -d ../src/.cherryci -s c-util -m
- script:
- ./vmrun -T armv7hl -- ../src/cherryci -d ../src/.cherryci -s c-util
- script:
- ./vmrun -T i686 -- ../src/cherryci -d ../src/.cherryci -s c-util

38
shared/c-stdaux/AUTHORS Normal file
View file

@ -0,0 +1,38 @@
LICENSE:
This project is dual-licensed under both the Apache License, Version
2.0, and the GNU Lesser General Public License, Version 2.1+.
AUTHORS-ASL:
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
AUTHORS-LGPL:
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.
COPYRIGHT: (ordered alphabetically)
Copyright (C) 2018-2019 Red Hat, Inc.
AUTHORS: (ordered alphabetically)
David Rheinsberg <david.rheinsberg@gmail.com>
Thomas Haller <thaller@redhat.com>
Tom Gundersen <teg@jklm.no>

11
shared/c-stdaux/NEWS.md Normal file
View file

@ -0,0 +1,11 @@
# c-stdaux - Auxiliary macros and functions for the C standard library
## CHANGES WITH 1:
* Initial release of c-stdaux.
* TBD
Contributions from: TBD
- TBD, YYYY-MM-DD

53
shared/c-stdaux/README.md Normal file
View file

@ -0,0 +1,53 @@
c-stdaux
========
Auxiliary macros and functions for the C standard library
The c-stdaux project contains support-macros and auxiliary functions around the
functionality of common C standard libraries. This includes helpers for the
ISO-C Standard Library, but also other common specifications like POSIX or
common extended features of wide-spread compilers like gcc and clang.
### Project
* **Website**: <https://c-util.github.io/c-stdaux>
* **Bug Tracker**: <https://github.com/c-util/c-stdaux/issues>
### Requirements
The requirements for this project are:
* `libc` (e.g., `glibc >= 2.16`)
At build-time, the following software is required:
* `meson >= 0.41`
* `pkg-config >= 0.29`
### Build
The meson build-system is used for this project. Contact upstream
documentation for detailed help. In most situations the following
commands are sufficient to build and install from source:
```sh
mkdir build
cd build
meson setup ..
ninja
meson test
ninja install
```
No custom configuration options are available.
### Repository:
- **web**: <https://github.com/c-util/c-stdaux>
- **https**: `https://github.com/c-util/c-stdaux.git`
- **ssh**: `git@github.com:c-util/c-stdaux.git`
### License:
- **Apache-2.0** OR **LGPL-2.1-or-later**
- See AUTHORS file for details.

View file

@ -0,0 +1,15 @@
project(
'c-stdaux',
'c',
version: '1',
license: 'Apache',
default_options: [
'c_std=c11'
],
)
project_description = 'Auxiliary macros and functions for the C standard library'
add_project_arguments('-D_GNU_SOURCE', language: 'c')
mod_pkgconfig = import('pkgconfig')
subdir('src')

View file

@ -0,0 +1,544 @@
#pragma once
/*
* Auxiliary macros and functions for the C standard library
*
* The `c-stdaux.h` header contains a collection of auxiliary macros and helper
* functions around the functionality provided by the different C standard
* library implementations, as well as other specifications implemented by
* them.
*
* Most of the helpers provided here provide aliases for common library and
* compiler features. Furthermore, several helpers simply provide other calling
* conventions than their standard counterparts (e.g., they allow for NULL to
* be passed with an object length of 0 where it makes sense to accept empty
* input).
*
* The namespace used by this project is:
*
* * `c_*` for all common C symbols or definitions that behave like proper C
* entities (e.g., macros that protect against double-evaluation would use
* lower-case names)
*
* * `C_*` for all constants, as well as macros that may not be safe against
* double evaluation.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <stdalign.h>
#include <stdarg.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdnoreturn.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
/*
* Shortcuts for gcc attributes. See GCC manual for details. They're 1-to-1
* mappings to the GCC equivalents. No additional magic here. They are
* supported by other compilers as well.
*/
#define _c_cleanup_(_x) __attribute__((__cleanup__(_x)))
#define _c_const_ __attribute__((__const__))
#define _c_deprecated_ __attribute__((__deprecated__))
#define _c_hidden_ __attribute__((__visibility__("hidden")))
#define _c_likely_(_x) (__builtin_expect(!!(_x), 1))
#define _c_packed_ __attribute__((__packed__))
#define _c_printf_(_a, _b) __attribute__((__format__(printf, _a, _b)))
#define _c_public_ __attribute__((__visibility__("default")))
#define _c_pure_ __attribute__((__pure__))
#define _c_sentinel_ __attribute__((__sentinel__))
#define _c_unlikely_(_x) (__builtin_expect(!!(_x), 0))
#define _c_unused_ __attribute__((__unused__))
/**
* C_EXPR_ASSERT() - create expression with assertion
* @_expr: expression to evaluate to
* @_assertion: arbitrary assertion
* @_message: message associated with the assertion
*
* This macro simply evaluates to @_expr. That is, it can be used in any
* context that expects an expression like @_expr. Additionally, it takes an
* assertion as @_assertion and evaluates it through _Static_assert(), using
* @_message as debug message.
*
* The _Static_assert() builtin of C11 is defined as statement and thus cannot
* be used in expressions. This macro circumvents this restriction.
*
* Return: Evaluates to @_expr.
*/
#define C_EXPR_ASSERT(_expr, _assertion, _message) \
/* indentation and line-split to get better diagnostics */ \
(__builtin_choose_expr( \
!!(1 + 0 * sizeof( \
struct { \
_Static_assert(_assertion, _message); \
} \
)), \
(_expr), \
((void)0) \
))
/**
* C_STRINGIFY() - stringify a token, but evaluate it first
* @_x: token to evaluate and stringify
*
* Return: Evaluates to a constant string literal
*/
#define C_STRINGIFY(_x) C_INTERNAL_STRINGIFY(_x)
#define C_INTERNAL_STRINGIFY(_x) #_x
/**
* C_CONCATENATE() - concatenate two tokens, but evaluate them first
* @_x: first token
* @_y: second token
*
* Return: Evaluates to a constant identifier
*/
#define C_CONCATENATE(_x, _y) C_INTERNAL_CONCATENATE(_x, _y)
#define C_INTERNAL_CONCATENATE(_x, _y) _x ## _y
/**
* C_EXPAND() - expand a tuple to a series of its values
* @_x: tuple to expand
*
* Return: Evaluates to the expanded tuple
*/
#define C_EXPAND(_x) C_INTERNAL_EXPAND _x
#define C_INTERNAL_EXPAND(...) __VA_ARGS__
/**
* C_VAR() - generate unique variable name
* @_x: name of variable, optional
* @_uniq: unique prefix, usually provided by __COUNTER__, optional
*
* This macro shall be used to generate unique variable names, that will not be
* shadowed by recursive macro invocations. It is effectively a
* C_CONCATENATE of both arguments, but also provides a globally separated
* prefix and makes the code better readable.
*
* The second argument is optional. If not given, __LINE__ is implied, and as
* such the macro will generate the same identifier if used multiple times on
* the same code-line (or within a macro). This should be used if recursive
* calls into the macro are not expected. In fact, no argument is necessary in
* this case, as a mere `C_VAR` will evaluate to a valid variable name.
*
* This helper may be used by macro implementations that might reasonable well
* be called in a stacked fasion, like:
*
* c_max(foo, c_max(bar, baz))
*
* Such a stacked call of c_max() might cause compiler warnings of shadowed
* variables in the definition of c_max(). By using C_VAR(), such warnings
* can be silenced as each evaluation of c_max() uses unique variable names.
*
* Return: This evaluates to a constant identifier.
*/
#define C_VAR(...) C_INTERNAL_VAR(__VA_ARGS__, 2, 1)
#define C_INTERNAL_VAR(_x, _uniq, _num, ...) C_VAR ## _num (_x, _uniq)
#define C_VAR1(_x, _unused) C_VAR2(_x, C_CONCATENATE(line, __LINE__))
#define C_VAR2(_x, _uniq) C_CONCATENATE(c_internal_var_unique_, C_CONCATENATE(_uniq, _x))
/**
* C_CC_MACRO1() - provide safe environment to a macro
* @_call: macro to call
* @_x1: first argument
* @...: further arguments to forward unmodified to @_call
*
* This function simplifies the implementation of macros. Whenever you
* implement a macro, provide the internal macro name as @_call and its
* argument as @_x1. Inside of your internal macro, you...
*
* - ...are safe against multiple evaluation errors, since C_CC_MACRO1 will
* store the initial parameters in temporary variables.
*
* - ...support constant folding, as C_CC_MACRO1 takes care to invoke your
* macro with the original values, if they are compile-time constant.
*
* - ...have unique variable names for recursive callers and will not run into
* variable-shadowing-warnings accidentally.
*
* - ...have properly typed arguments as C_CC_MACRO1 stores the original
* arguments in an `__auto_type` temporary variable.
*
* Return: Result of @_call is returned.
*/
#define C_CC_MACRO1(_call, _x1, ...) C_INTERNAL_CC_MACRO1(_call, __COUNTER__, (_x1), ## __VA_ARGS__)
#define C_INTERNAL_CC_MACRO1(_call, _x1q, _x1, ...) \
__builtin_choose_expr( \
__builtin_constant_p(_x1), \
_call(_x1, ## __VA_ARGS__), \
__extension__ ({ \
const __auto_type C_VAR(X1, _x1q) = (_x1); \
_call(C_VAR(X1, _x1q), ## __VA_ARGS__); \
}))
/**
* C_CC_MACRO2() - provide safe environment to a macro
* @_call: macro to call
* @_x1: first argument
* @_x2: second argument
* @...: further arguments to forward unmodified to @_call
*
* This is the 2-argument equivalent of C_CC_MACRO1().
*
* Return: Result of @_call is returned.
*/
#define C_CC_MACRO2(_call, _x1, _x2, ...) C_INTERNAL_CC_MACRO2(_call, __COUNTER__, (_x1), __COUNTER__, (_x2), ## __VA_ARGS__)
#define C_INTERNAL_CC_MACRO2(_call, _x1q, _x1, _x2q, _x2, ...) \
__builtin_choose_expr( \
(__builtin_constant_p(_x1) && __builtin_constant_p(_x2)), \
_call((_x1), (_x2), ## __VA_ARGS__), \
__extension__ ({ \
const __auto_type C_VAR(X1, _x1q) = (_x1); \
const __auto_type C_VAR(X2, _x2q) = (_x2); \
_call(C_VAR(X1, _x1q), C_VAR(X2, _x2q), ## __VA_ARGS__); \
}))
/**
* C_CC_MACRO3() - provide safe environment to a macro
* @_call: macro to call
* @_x1: first argument
* @_x2: second argument
* @_x3: third argument
* @...: further arguments to forward unmodified to @_call
*
* This is the 3-argument equivalent of C_CC_MACRO1().
*
* Return: Result of @_call is returned.
*/
#define C_CC_MACRO3(_call, _x1, _x2, _x3, ...) C_INTERNAL_CC_MACRO3(_call, __COUNTER__, (_x1), __COUNTER__, (_x2), __COUNTER__, (_x3), ## __VA_ARGS__)
#define C_INTERNAL_CC_MACRO3(_call, _x1q, _x1, _x2q, _x2, _x3q, _x3, ...) \
__builtin_choose_expr( \
(__builtin_constant_p(_x1) && __builtin_constant_p(_x2) && __builtin_constant_p(_x3)), \
_call((_x1), (_x2), (_x3), ## __VA_ARGS__), \
__extension__ ({ \
const __auto_type C_VAR(X1, _x1q) = (_x1); \
const __auto_type C_VAR(X2, _x2q) = (_x2); \
const __auto_type C_VAR(X3, _x3q) = (_x3); \
_call(C_VAR(X1, _x1q), C_VAR(X2, _x2q), C_VAR(X3, _x3q), ## __VA_ARGS__); \
}))
/**
* C_ARRAY_SIZE() - calculate number of array elements at compile time
* @_x: array to calculate size of
*
* Return: Evaluates to a constant integer expression.
*/
#define C_ARRAY_SIZE(_x) \
C_EXPR_ASSERT(sizeof(_x) / sizeof((_x)[0]), \
/* \
* Verify that `_x' is an array, not a pointer. Rely on \
* `&_x[0]' degrading arrays to pointers. \
*/ \
!__builtin_types_compatible_p( \
__typeof__(_x), \
__typeof__(&(*(__typeof__(_x)*)0)[0]) \
), \
"C_ARRAY_SIZE() called with non-array argument" \
)
/**
* C_DECIMAL_MAX() - calculate maximum length of the decimal
* representation of an integer
* @_type: integer variable/type
*
* This calculates the bytes required for the decimal representation of an
* integer of the given type. It accounts for a possible +/- prefix, but it
* does *NOT* include the trailing terminating zero byte.
*
* Return: Evaluates to a constant integer expression
*/
#define C_DECIMAL_MAX(_arg) \
(_Generic((__typeof__(_arg)){ 0 }, \
char: C_INTERNAL_DECIMAL_MAX(sizeof(char)), \
signed char: C_INTERNAL_DECIMAL_MAX(sizeof(signed char)), \
unsigned char: C_INTERNAL_DECIMAL_MAX(sizeof(unsigned char)), \
signed short: C_INTERNAL_DECIMAL_MAX(sizeof(signed short)), \
unsigned short: C_INTERNAL_DECIMAL_MAX(sizeof(unsigned short)), \
signed int: C_INTERNAL_DECIMAL_MAX(sizeof(signed int)), \
unsigned int: C_INTERNAL_DECIMAL_MAX(sizeof(unsigned int)), \
signed long: C_INTERNAL_DECIMAL_MAX(sizeof(signed long)), \
unsigned long: C_INTERNAL_DECIMAL_MAX(sizeof(unsigned long)), \
signed long long: C_INTERNAL_DECIMAL_MAX(sizeof(signed long long)), \
unsigned long long: C_INTERNAL_DECIMAL_MAX(sizeof(unsigned long long))))
#define C_INTERNAL_DECIMAL_MAX(_bytes) \
C_EXPR_ASSERT( \
1 + ((_bytes) <= 1 ? 3 : \
(_bytes) <= 2 ? 5 : \
(_bytes) <= 4 ? 10 : \
20), \
(_bytes) <= 8, \
"Invalid use of C_INTERNAL_DECIMAL_MAX()" \
)
/**
* c_container_of() - cast a member of a structure out to the containing structure
* @_ptr: pointer to the member or NULL
* @_type: type of the container struct this is embedded in
* @_member: name of the member within the struct
*
* This uses `offsetof(3)` to turn a pointer to a structure-member into a
* pointer to the surrounding structure.
*
* Return: Pointer to the surrounding object.
*/
#define c_container_of(_ptr, _type, _member) C_CC_MACRO1(C_CONTAINER_OF, (_ptr), _type, _member)
#define C_CONTAINER_OF(_ptr, _type, _member) \
__extension__ ({ \
/* trigger warning if types do not match */ \
(void)(&((_type *)0)->_member == (_ptr)); \
_ptr ? (_type*)( (char*)_ptr - offsetof(_type, _member) ) : NULL; \
})
/**
* c_max() - compute maximum of two values
* @_a: value A
* @_b: value B
*
* Calculate the maximum of both passed values. Both arguments are evaluated
* exactly once, under all circumstances. Furthermore, if both values are
* constant expressions, the result will be constant as well.
*
* The comparison of their values is performed with the types given by the
* caller. It is the caller's responsibility to convert them to suitable types
* if necessary.
*
* Return: Maximum of both values is returned.
*/
#define c_max(_a, _b) C_CC_MACRO2(C_MAX, (_a), (_b))
#define C_MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
/**
* c_min() - compute minimum of two values
* @_a: value A
* @_b: value B
*
* Calculate the minimum of both passed values. Both arguments are evaluated
* exactly once, under all circumstances. Furthermore, if both values are
* constant expressions, the result will be constant as well.
*
* The comparison of their values is performed with the types given by the
* caller. It is the caller's responsibility to convert them to suitable types
* if necessary.
*
* Return: Minimum of both values is returned.
*/
#define c_min(_a, _b) C_CC_MACRO2(C_MIN, (_a), (_b))
#define C_MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))
/**
* c_less_by() - calculate clamped difference of two values
* @_a: minuend
* @_b: subtrahend
*
* Calculate [_a - _b], but clamp the result to 0. Both arguments are evaluated
* exactly once, under all circumstances. Furthermore, if both values are
* constant expressions, the result will be constant as well.
*
* The comparison of their values is performed with the types given by the
* caller. It is the caller's responsibility to convert them to suitable types
* if necessary.
*
* Return: This computes [_a - _b], if [_a > _b]. Otherwise, 0 is returned.
*/
#define c_less_by(_a, _b) C_CC_MACRO2(C_LESS_BY, (_a), (_b))
#define C_LESS_BY(_a, _b) ((_a) > (_b) ? (_a) - (_b) : 0)
/**
* c_clamp() - clamp value to lower and upper boundary
* @_x: value to clamp
* @_low: lower boundary
* @_high: higher boundary
*
* This clamps @_x to the lower and higher bounds given as @_low and @_high.
* All arguments are evaluated exactly once, and yield a constant expression if
* all arguments are constant as well.
*
* The comparison of their values is performed with the types given by the
* caller. It is the caller's responsibility to convert them to suitable types
* if necessary.
*
* Return: Clamped integer value.
*/
#define c_clamp(_x, _low, _high) C_CC_MACRO3(C_CLAMP, (_x), (_low), (_high))
#define C_CLAMP(_x, _low, _high) ((_x) > (_high) ? (_high) : (_x) < (_low) ? (_low) : (_x))
/**
* c_div_round_up() - calculate integer quotient but round up
* @_x: dividend
* @_y: divisor
*
* Calculates [x / y] but rounds up the result to the next integer. All
* arguments are evaluated exactly once, and yield a constant expression if all
* arguments are constant.
*
* Note:
* [(x + y - 1) / y] suffers from an integer overflow, even though the
* computation should be possible in the given type. Therefore, we use
* [x / y + !!(x % y)]. Note that on most CPUs a division returns both the
* quotient and the remainder, so both should be equally fast. Furthermore, if
* the divisor is a power of two, the compiler will optimize it, anyway.
*
* The operationsare performed with the types given by the caller. It is the
* caller's responsibility to convert the arguments to suitable types if
* necessary.
*
* Return: The quotient is returned.
*/
#define c_div_round_up(_x, _y) C_CC_MACRO2(C_DIV_ROUND_UP, (_x), (_y))
#define C_DIV_ROUND_UP(_x, _y) ((_x) / (_y) + !!((_x) % (_y)))
/**
* c_align_to() - align value to a multiple
* @_val: value to align
* @_to: align to multiple of this
*
* This aligns @_val to a multiple of @_to. If @_val is already a multiple of
* @_to, @_val is returned unchanged. This function operates within the
* boundaries of the type of @_val and @_to. Make sure to cast them if needed.
*
* The arguments of this macro are evaluated exactly once. If both arguments
* are a constant expression, this also yields a constant return value.
*
* Note that @_to must be a power of 2, otherwise the behavior will not match
* expectations.
*
* Return: @_val aligned to a multiple of @_to
*/
#define c_align_to(_val, _to) C_CC_MACRO2(C_ALIGN_TO, (_val), (_to))
#define C_ALIGN_TO(_val, _to) (((_val) + (_to) - 1) & ~((_to) - 1))
/**
* c_assert() - runtime assertions
* @expr_result: result of an expression
*
* This function behaves like the standard `assert(3)` macro. That is, if
* `NDEBUG` is defined, it is a no-op. In all other cases it will assert that
* the result of the passed expression is true.
*
* Unlike the standard `assert(3)` macro, this function always evaluates its
* argument. This means side-effects will always be evaluated! However, if the
* macro is used with constant expressions, the compiler will be able to
* optimize it away.
*/
#define c_assert(_x) ({ \
const _c_unused_ bool c_assert_result = (_x); \
assert(c_assert_result && #_x); \
})
/**
* c_errno() - return valid errno
*
* This helper should be used to shut up gcc if you know 'errno' is valid (ie.,
* errno is > 0). Instead of "return -errno;", use
* "return -c_errno();" It will suppress bogus gcc warnings in case it assumes
* 'errno' might be 0 (or <0) and thus the caller's error-handling might not be
* triggered.
*
* This helper should be avoided whenever possible. However, occasionally we
* really want to shut up gcc (especially with static/inline functions). In
* those cases, gcc usually cannot deduce that some error paths are guaranteed
* to be taken. Hence, making the return value explicit allows gcc to better
* optimize the code.
*
* Note that you really should never use this helper to work around broken libc
* calls or syscalls, not setting 'errno' correctly.
*
* Return: Positive error code is returned.
*/
static inline int c_errno(void) {
return _c_likely_(errno > 0) ? errno : ENOTRECOVERABLE;
}
/*
* Common Destructors
*
* Followingly, there're a bunch of common 'static inline' destructors, which
* simply call the function that they're named after, but return "INVALID"
* instead of "void". This allows direct assignment to any member-field and/or
* variable they're defined in, like:
*
* foo = c_free(foo);
*
* or
*
* foo->bar = c_close(foo->bar);
*
* Furthermore, all those destructors can be safely called with the "INVALID"
* value as argument, and they will be a no-op.
*/
static inline void *c_free(void *p) {
free(p);
return NULL;
}
static inline int c_close(int fd) {
if (fd >= 0)
close(fd);
return -1;
}
static inline FILE *c_fclose(FILE *f) {
if (f)
fclose(f);
return NULL;
}
static inline DIR *c_closedir(DIR *d) {
if (d)
closedir(d);
return NULL;
}
/*
* Common Cleanup Helpers
*
* A bunch of _c_cleanup_(foobarp) helpers that are used all over the place.
* Note that all of those have the "if (IS_INVALID(foobar))" check inline, so
* compilers can optimize most of the cleanup-paths in a function. However, if
* the function they call already does this _inline_, then it might be skipped.
*/
#define C_DEFINE_CLEANUP(_type, _func) \
static inline void _func ## p(_type *p) { \
if (*p) \
_func(*p); \
} struct c_internal_trailing_semicolon
#define C_DEFINE_DIRECT_CLEANUP(_type, _func) \
static inline void _func ## p(_type *p) { \
_func(*p); \
} struct c_internal_trailing_semicolon
static inline void c_freep(void *p) {
/*
* `foobar **` does not coerce to `void **`, so we need `void *` as
* argument type, and then we dereference manually.
*/
c_free(*(void **)p);
}
C_DEFINE_DIRECT_CLEANUP(int, c_close);
C_DEFINE_CLEANUP(FILE *, c_fclose);
C_DEFINE_CLEANUP(DIR *, c_closedir);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,31 @@
#
# target: libcstdaux.so
# (No .so is built so far, since we are header-only. This might change in the
# future, if we add more complex helpers.)
#
libcstdaux_dep = declare_dependency(
include_directories: include_directories('.'),
version: meson.project_version(),
)
if not meson.is_subproject()
install_headers('c-stdaux.h')
mod_pkgconfig.generate(
version: meson.project_version(),
name: 'libcstdaux',
filebase: 'libcstdaux',
description: project_description,
)
endif
#
# target: test-*
#
test_api = executable('test-api', ['test-api.c'], dependencies: libcstdaux_dep)
test('API Symbol Visibility', test_api)
test_basic = executable('test-basic', ['test-basic.c'], dependencies: libcstdaux_dep)
test('Basic API Behavior', test_basic)

View file

@ -0,0 +1,209 @@
/*
* API Visibility Tests
* This verifies the visibility and availability of the exported API.
*/
#undef NDEBUG
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "c-stdaux.h"
static _c_const_ int const_fn(void) { return 0; }
static _c_deprecated_ _c_unused_ int deprecated_fn(void) { return 0; }
_c_hidden_ int c_internal_hidden_fn(void) { return 0; }
static _c_printf_(1, 2) int printf_fn(const char *f, ...) { return 0; }
_c_public_ int c_internal_public_fn(void) { return 0; }
static _c_pure_ int pure_fn(void) { return 0; }
static _c_sentinel_ int sentinel_fn(const char *f, ...) { return 0; }
static _c_unused_ int unused_fn(void) { return 0; }
static void cleanup_fn(int p) {}
static void direct_cleanup_fn(int p) {}
C_DEFINE_CLEANUP(int, cleanup_fn);
C_DEFINE_DIRECT_CLEANUP(int, direct_cleanup_fn);
static void test_api_macros(void) {
/* _c_cleanup_ */
{
_c_cleanup_(c_freep) void *foo = NULL;
c_assert(!foo);
}
/* _c_const_ */
{
c_assert(!const_fn());
}
/* _c_deprecated_ */
{
/* see deprecated_fn() */
}
/* _c_hidden_ */
{
c_assert(!c_internal_hidden_fn());
}
/* _c_likely_ */
{
c_assert(_c_likely_(true));
}
/* _c_packed_ */
{
struct _c_packed_ FooBar {
int member;
} foobar = {};
c_assert(!foobar.member);
}
/* _c_printf_ */
{
c_assert(!printf_fn("%d", 1));
}
/* _c_public_ */
{
c_assert(!c_internal_public_fn());
}
/* _c_pure_ */
{
c_assert(!pure_fn());
}
/* _c_sentinel_ */
{
c_assert(!sentinel_fn("", NULL));
}
/* _c_unlikely_ */
{
c_assert(!_c_unlikely_(false));
}
/* _c_unused_ */
{
c_assert(!unused_fn());
}
/* C_EXPR_ASSERT */
{
int v = C_EXPR_ASSERT(0, true, "");
c_assert(!v);
}
/* C_STRINGIFY */
{
const char v[] = C_STRINGIFY(foobar);
c_assert(!strcmp(v, "foobar"));
}
/* C_CONCATENATE */
{
int C_CONCATENATE(a, b) = 0;
c_assert(!ab);
}
/* C_EXPAND */
{
int x[] = { C_EXPAND((0, 1)) };
c_assert(sizeof(x) / sizeof(*x) == 2);
}
/* C_VAR */
{
int C_VAR = 0; c_assert(!C_VAR); /* must be on the same line */
}
/* C_CC_MACRO1, C_CC_MACRO2, C_CC_MACRO3 */
{
#define MACRO_REAL(_x1, _x2, _x3) ((_x1 + _x2 + _x3) * 0)
#define MACRO1(_x1) C_CC_MACRO1(MACRO_REAL, _x1, 0, 0)
#define MACRO2(_x1, _x2) C_CC_MACRO2(MACRO_REAL, _x1, _x2, 0)
#define MACRO3(_x1, _x2, _x3) C_CC_MACRO3(MACRO_REAL, _x1, _x2, _x3)
c_assert(!MACRO1(1));
c_assert(!MACRO2(1, 1));
c_assert(!MACRO3(1, 1, 1));
#undef MACRO3
#undef MACRO2
#undef MACRO1
}
/* C_ARRAY_SIZE */
{
int v[] = { 0, 1, 2 };
c_assert(C_ARRAY_SIZE(v) == 3);
}
/* C_DECIMAL_MAX */
{
c_assert(C_DECIMAL_MAX(uint8_t) == 4);
}
/* c_container_of */
{
struct FooBarContainer {
int member;
} v = {};
c_assert(c_container_of(&v.member, struct FooBarContainer, member) == &v);
}
/* c_max, c_min, c_less_by, c_clamp, c_div_round_up */
{
c_assert(c_max(0, 0) == 0);
c_assert(c_min(0, 0) == 0);
c_assert(c_less_by(0, 0) == 0);
c_assert(c_clamp(0, 0, 0) == 0);
c_assert(c_div_round_up(1, 1) == 1);
}
/* c_align_to */
{
c_assert(c_align_to(0, 0) == 0);
}
/* c_assert */
{
c_assert(true);
}
/* C_DEFINE_CLEANUP / C_DEFINE_DIRECT_CLEANUP */
{
int v = 0;
cleanup_fnp(&v);
direct_cleanup_fnp(&v);
}
}
static void test_api_functions(void) {
void *fns[] = {
(void *)c_errno,
(void *)c_free,
(void *)c_close,
(void *)c_fclose,
(void *)c_closedir,
(void *)c_freep,
(void *)c_closep,
(void *)c_fclosep,
(void *)c_closedirp,
};
size_t i;
for (i = 0; i < sizeof(fns) / sizeof(*fns); ++i)
c_assert(!!fns[i]);
}
int main(int argc, char **argv) {
test_api_macros();
test_api_functions();
return 0;
}

View file

@ -0,0 +1,432 @@
/*
* Tests for Basic Functionality
*
* This runs same basic verification that each feature does what we expect it
* to do. More elaborate tests and/or stress-tests are not included here.
*/
#undef NDEBUG
#include <stdlib.h>
#include <sys/eventfd.h>
#include "c-stdaux.h"
/*
* Tests for all remaining helpers
*/
static void test_misc(int non_constant_expr) {
int foo;
/*
* Test the C_EXPR_ASSERT() macro to work in static and non-static
* environments, and evaluate exactly to its passed expression.
*/
{
static int v = C_EXPR_ASSERT(1, true, "");
c_assert(v == 1);
}
/*
* Test stringify/concatenation helpers. Also make sure to test that
* the passed arguments are evaluated first, before they're stringified
* and/or concatenated.
*/
{
#define TEST_TOKEN foobar
c_assert(!strcmp("foobar", C_STRINGIFY(foobar)));
c_assert(!strcmp("foobar", C_STRINGIFY(TEST_TOKEN)));
c_assert(!strcmp("foobar", C_STRINGIFY(C_CONCATENATE(foo, bar))));
c_assert(!strcmp("foobarfoobar", C_STRINGIFY(C_CONCATENATE(TEST_TOKEN, foobar))));
c_assert(!strcmp("foobarfoobar", C_STRINGIFY(C_CONCATENATE(foobar, TEST_TOKEN))));
#undef TEST_TOKEN
}
/*
* Test tuple expansion. This is used to strip tuple-wrappers in the
* pre-processor.
* We make sure that it works with {0,1,2}-tuples, as well as only
* strips a single layer.
*/
{
/*
* strcmp() might be a macro, so make sure we get a proper C
* expression below. Otherwise, C_EXPAND() cannot be used that
* way (since it would evaluate to a single macro argument).
*/
int (*f) (const char *, const char *) = strcmp;
c_assert(!f(C_EXPAND(()) "foobar", "foo" "bar"));
c_assert(!f(C_EXPAND(("foobar")), "foo" "bar"));
c_assert(!f(C_EXPAND(("foobar", "foo" "bar"))));
c_assert(!f C_EXPAND((("foobar", "foo" "bar"))));
}
/*
* Test C_VAR() macro. It's sole purpose is to create a valid C
* identifier given a single argument (which itself must be a valid
* identifier).
* Just test that we can declare variables with it and use it in
* expressions.
*/
{
{
int C_VAR(sub, UNIQUE) = 5;
/* make sure the variable name does not clash */
int sub = 12, subUNIQUE = 12, UNIQUEsub = 12;
c_assert(7 + C_VAR(sub, UNIQUE) == sub);
c_assert(sub == subUNIQUE);
c_assert(sub == UNIQUEsub);
}
{
/*
* Make sure both produce different names, even though they're
* exactly the same expression.
*/
_c_unused_ int C_VAR(sub, __COUNTER__), C_VAR(sub, __COUNTER__);
}
{
/* verify C_VAR() with single argument works line-based */
int C_VAR(sub); C_VAR(sub) = 5; c_assert(C_VAR(sub) == 5);
}
{
/* verify C_VAR() with no argument works line-based */
int C_VAR(); C_VAR() = 5; c_assert(C_VAR() == 5);
}
}
/*
* Test array-size helper. This simply computes the number of elements
* of an array, instead of the binary size.
*/
{
int bar[8];
static_assert(C_ARRAY_SIZE(bar) == 8, "");
c_assert(__builtin_constant_p(C_ARRAY_SIZE(bar)));
}
/*
* Test decimal-representation calculator. Make sure it is
* type-independent and just uses the size of the type to calculate how
* many bytes are needed to print that integer in decimal form. Also
* verify that it is a constant expression.
*/
{
static_assert(C_DECIMAL_MAX(char) == 4, "");
static_assert(C_DECIMAL_MAX(signed char) == 4, "");
static_assert(C_DECIMAL_MAX(unsigned char) == 4, "");
static_assert(C_DECIMAL_MAX(unsigned long) == (sizeof(long) == 8 ? 21 : 11), "");
static_assert(C_DECIMAL_MAX(unsigned long long) == 21, "");
static_assert(C_DECIMAL_MAX(int32_t) == 11, "");
static_assert(C_DECIMAL_MAX(uint32_t) == 11, "");
static_assert(C_DECIMAL_MAX(uint64_t) == 21, "");
}
/*
* Test c_container_of(). We cannot test for type-safety, nor for
* other invalid uses, as they'd require negative compile-testing.
* However, we can test that the macro yields the correct values under
* normal use.
*/
{
struct foobar {
int a;
char b;
} sub = {};
c_assert(&sub == c_container_of(&sub.a, struct foobar, a));
c_assert(&sub == c_container_of(&sub.b, struct foobar, b));
c_assert(&sub == c_container_of((const char *)&sub.b, struct foobar, b));
}
/*
* Test min/max macros. Especially check that macro arguments are never
* evaluated multiple times, and if both arguments are constant, the
* return value is constant as well.
*/
{
foo = 0;
c_assert(c_max(1, 5) == 5);
c_assert(c_max(-1, 5) == 5);
c_assert(c_max(-1, -5) == -1);
c_assert(c_max(foo++, -1) == 0);
c_assert(foo == 1);
c_assert(c_max(foo++, foo++) > 0);
c_assert(foo == 3);
c_assert(__builtin_constant_p(c_max(1, 5)));
c_assert(!__builtin_constant_p(c_max(1, non_constant_expr)));
foo = 0;
c_assert(c_min(1, 5) == 1);
c_assert(c_min(-1, 5) == -1);
c_assert(c_min(-1, -5) == -5);
c_assert(c_min(foo++, 1) == 0);
c_assert(foo == 1);
c_assert(c_min(foo++, foo++) > 0);
c_assert(foo == 3);
c_assert(__builtin_constant_p(c_min(1, 5)));
c_assert(!__builtin_constant_p(c_min(1, non_constant_expr)));
}
/*
* Test c_less_by(), c_clamp(). Make sure they
* evaluate arguments exactly once, and yield a constant expression,
* if all arguments are constant.
*/
{
foo = 8;
c_assert(c_less_by(1, 5) == 0);
c_assert(c_less_by(5, 1) == 4);
c_assert(c_less_by(foo++, 1) == 7);
c_assert(foo == 9);
c_assert(c_less_by(foo++, foo++) >= 0);
c_assert(foo == 11);
c_assert(__builtin_constant_p(c_less_by(1, 5)));
c_assert(!__builtin_constant_p(c_less_by(1, non_constant_expr)));
foo = 8;
c_assert(c_clamp(foo, 1, 5) == 5);
c_assert(c_clamp(foo, 9, 20) == 9);
c_assert(c_clamp(foo++, 1, 5) == 5);
c_assert(foo == 9);
c_assert(c_clamp(foo++, foo++, foo++) >= 0);
c_assert(foo == 12);
c_assert(__builtin_constant_p(c_clamp(0, 1, 5)));
c_assert(!__builtin_constant_p(c_clamp(1, 0, non_constant_expr)));
}
/*
* Div Round Up: Normal division, but round up to next integer, instead
* of clipping. Also verify that it does not suffer from the integer
* overflow in the prevalant, alternative implementation:
* [(x + y - 1) / y].
*/
{
int i, j;
#define TEST_ALT_DIV(_x, _y) (((_x) + (_y) - 1) / (_y))
foo = 8;
c_assert(c_div_round_up(0, 5) == 0);
c_assert(c_div_round_up(1, 5) == 1);
c_assert(c_div_round_up(5, 5) == 1);
c_assert(c_div_round_up(6, 5) == 2);
c_assert(c_div_round_up(foo++, 1) == 8);
c_assert(foo == 9);
c_assert(c_div_round_up(foo++, foo++) >= 0);
c_assert(foo == 11);
c_assert(__builtin_constant_p(c_div_round_up(1, 5)));
c_assert(!__builtin_constant_p(c_div_round_up(1, non_constant_expr)));
/* alternative calculation is [(x + y - 1) / y], but it may overflow */
for (i = 0; i <= 0xffff; ++i) {
for (j = 1; j <= 0xff; ++j)
c_assert(c_div_round_up(i, j) == TEST_ALT_DIV(i, j));
for (j = 0xff00; j <= 0xffff; ++j)
c_assert(c_div_round_up(i, j) == TEST_ALT_DIV(i, j));
}
/* make sure it doesn't suffer from high overflow */
c_assert(UINT32_C(0xfffffffa) % 10 == 0);
c_assert(UINT32_C(0xfffffffa) / 10 == UINT32_C(429496729));
c_assert(c_div_round_up(UINT32_C(0xfffffffa), 10) == UINT32_C(429496729));
c_assert(TEST_ALT_DIV(UINT32_C(0xfffffffa), 10) == 0); /* overflow */
c_assert(UINT32_C(0xfffffffd) % 10 == 3);
c_assert(UINT32_C(0xfffffffd) / 10 == UINT32_C(429496729));
c_assert(c_div_round_up(UINT32_C(0xfffffffd), 10) == UINT32_C(429496730));
c_assert(TEST_ALT_DIV(UINT32_C(0xfffffffd), 10) == 0);
#undef TEST_ALT_DIV
}
/*
* Align to multiple of: Test the alignment macro. Check that it does
* not suffer from incorrect integer overflows, neither should it
* exceed the boundaries of the input type.
*/
{
c_assert(c_align_to(UINT32_C(0), 1) == 0);
c_assert(c_align_to(UINT32_C(0), 2) == 0);
c_assert(c_align_to(UINT32_C(0), 4) == 0);
c_assert(c_align_to(UINT32_C(0), 8) == 0);
c_assert(c_align_to(UINT32_C(1), 8) == 8);
c_assert(c_align_to(UINT32_C(0xffffffff), 8) == 0);
c_assert(c_align_to(UINT32_C(0xfffffff1), 8) == 0xfffffff8);
c_assert(c_align_to(UINT32_C(0xfffffff1), 8) == 0xfffffff8);
c_assert(__builtin_constant_p(c_align_to(16, 8)));
c_assert(!__builtin_constant_p(c_align_to(non_constant_expr, 8)));
c_assert(!__builtin_constant_p(c_align_to(16, non_constant_expr)));
c_assert(!__builtin_constant_p(c_align_to(16, non_constant_expr ? 8 : 16)));
c_assert(__builtin_constant_p(c_align_to(16, 7 + 1)));
c_assert(c_align_to(15, non_constant_expr ? 8 : 16) == 16);
}
/*
* Test c_assert(). Make sure side-effects are always evaluated, and
* variables are marked as used regardless of NDEBUG.
*/
{
int v1 = 0, v2 = 0;
#define NDEBUG 1
c_assert(!v1);
if (v1)
abort();
c_assert(++v1);
if (v1 != 1)
abort();
#undef NDEBUG
c_assert(!v2);
if (v2)
abort();
c_assert(++v2);
if (v2 != 1)
abort();
}
/*
* Test c_errno(). Simply verify that the correct value is returned. It
* must always be >0 and equivalent to `errno' if set.
*/
{
c_assert(c_errno() > 0);
close(-1);
c_assert(c_errno() == errno);
errno = 0;
c_assert(c_errno() != errno);
}
}
/*
* Tests for:
* - c_free*()
* - c_close*()
* - c_fclose*()
* - c_closedir*()
*/
static void test_destructors(void) {
int i;
/*
* Verify that c_free*() works as expected. Since we want to support
* running under valgrind, there is no easy way to verify the
* correctness of free(). Hence, we simply rely on valgrind to catch
* the leaks.
*/
{
for (i = 0; i < 16; ++i) {
_c_cleanup_(c_freep) void *foo;
_c_cleanup_(c_freep) int **bar; /* supports any type */
size_t sz = 128 * 1024;
foo = malloc(sz);
c_assert(foo);
bar = malloc(sz);
c_assert(bar);
bar = c_free(bar);
c_assert(!bar);
}
c_assert(c_free(NULL) == NULL);
}
/*
* Test c_close*(), rely on sparse FD allocation. Make sure all the
* helpers actually close the fd, and cope fine with negative numbers.
*/
{
int fd;
fd = eventfd(0, EFD_CLOEXEC);
c_assert(fd >= 0);
/* verify c_close() returns -1 */
c_assert(c_close(fd) == -1);
/* verify c_close() deals fine with negative fds */
c_assert(c_close(-1) == -1);
c_assert(c_close(-16) == -1);
/* make sure c_closep() deals fine with negative FDs */
{
_c_cleanup_(c_closep) int t = 0;
t = -1;
}
/*
* Make sure the c_close() earlier worked, by allocating the
* FD again and relying on the same FD number to be reused. Do
* this twice, to verify that the c_closep() in the cleanup
* path works as well.
*/
for (i = 0; i < 2; ++i) {
_c_cleanup_(c_closep) int t = -1;
t = eventfd(0, EFD_CLOEXEC);
c_assert(t >= 0);
c_assert(t == fd);
}
}
/*
* Test c_fclose() and c_fclosep(). This uses the same logic as the
* tests for c_close() (i.e., sparse FD allocation).
*/
{
FILE *f;
int fd;
fd = eventfd(0, EFD_CLOEXEC);
c_assert(fd >= 0);
f = fdopen(fd, "r");
c_assert(f);
/* verify c_fclose() returns NULL */
f = c_fclose(f);
c_assert(!f);
/* verify c_fclose() deals fine with NULL */
c_assert(!c_fclose(NULL));
/* make sure c_flosep() deals fine with NULL */
{
_c_cleanup_(c_fclosep) FILE *t = (void *)0xdeadbeef;
t = NULL;
}
/*
* Make sure the c_fclose() earlier worked, by allocating the
* FD again and relying on the same FD number to be reused. Do
* this twice, to verify that the c_fclosep() in the cleanup
* path works as well.
*/
for (i = 0; i < 2; ++i) {
_c_cleanup_(c_fclosep) FILE *t = NULL;
int tfd;
tfd = eventfd(0, EFD_CLOEXEC);
c_assert(tfd >= 0);
c_assert(tfd == fd); /* the same as before */
t = fdopen(tfd, "r");
c_assert(t);
}
}
}
int main(int argc, char **argv) {
test_misc(argc);
test_destructors();
return 0;
}