diff options
Diffstat (limited to 'src/bfs.h')
-rw-r--r-- | src/bfs.h | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/src/bfs.h b/src/bfs.h new file mode 100644 index 0000000..bb83df2 --- /dev/null +++ b/src/bfs.h @@ -0,0 +1,268 @@ +// Copyright © Tavian Barnes <tavianator@tavianator.com> +// SPDX-License-Identifier: 0BSD + +/** + * Configuration and fundamental utilities. + */ + +#ifndef BFS_H +#define BFS_H + +#include <assert.h> // For __GLIBC__ +#include <stddef.h> // For offsetof + +// Standard versions + +/** Possible __STDC_VERSION__ values. */ +#define C95 199409L +#define C99 199901L +#define C11 201112L +#define C17 201710L +#define C23 202311L + +/** Possible _POSIX_C_SOURCE and _POSIX_<OPTION> values. */ +#define POSIX_1990 1 +#define POSIX_1992 2 +#define POSIX_1993 199309L +#define POSIX_1995 199506L +#define POSIX_2001 200112L +#define POSIX_2008 200809L +#define POSIX_2024 202405L + +// Build configuration + +#include "config.h" + +#ifndef BFS_COMMAND +# define BFS_COMMAND "bfs" +#endif + +#ifndef BFS_HOMEPAGE +# define BFS_HOMEPAGE "https://tavianator.com/projects/bfs.html" +#endif + +#ifndef BFS_LINT +# define BFS_LINT false +#endif + +// This is a symbol instead of a literal so we don't have to rebuild everything +// when the version number changes +extern const char bfs_version[]; + +extern const char bfs_confflags[]; +extern const char bfs_cc[]; +extern const char bfs_cppflags[]; +extern const char bfs_cflags[]; +extern const char bfs_ldflags[]; +extern const char bfs_ldlibs[]; + +// Fundamental utilities + +/** + * Given `ptr = &t->member`, return `t`. + */ +#define container_of(ptr, type, member) \ + (container_of_typecheck(ptr, type, member), \ + (type *)((char *)ptr - offsetof(type, member))) + +#define container_of_typecheck(ptr, type, field) \ + (void)sizeof(ptr - &((type *)NULL)->field) + +/** + * A preprocessor conditional. + * + * BFS_VA_IF(A)(B)(C) => B + * BFS_VA_IF( )(B)(C) => C + */ +#define BFS_VA_IF(...) BFS_VA_IF_AB ## __VA_OPT__(C) +// BFS_VA_IF(A)(B)(C) => BFS_VA_IF_ABC(B)(C) +// BFS_VA_IF( )(B)(C) => BFS_VA_IF_AB(B)(C) + +#define BFS_VA_IF_ABC(...) __VA_ARGS__ BFS_VA_IGNORE +// BFS_VA_IF_ABC(B)(C) => B BFS_VA_IGNORE(C) + +#define BFS_VA_IF_AB(...) BFS_VA_REPEAT +// BFS_VA_IF_AB(B)(C) => BFS_VA_REPEAT(C) + +#define BFS_VA_IGNORE(...) +#define BFS_VA_REPEAT(...) __VA_ARGS__ + +/** + * False sharing/destructive interference/largest cache line size. + */ +#ifdef __GCC_DESTRUCTIVE_SIZE +# define FALSE_SHARING_SIZE __GCC_DESTRUCTIVE_SIZE +#else +# define FALSE_SHARING_SIZE 64 +#endif + +/** + * True sharing/constructive interference/smallest cache line size. + */ +#ifdef __GCC_CONSTRUCTIVE_SIZE +# define TRUE_SHARING_SIZE __GCC_CONSTRUCTIVE_SIZE +#else +# define TRUE_SHARING_SIZE 64 +#endif + +/** + * Alignment specifier that avoids false sharing. + */ +#define cache_align alignas(FALSE_SHARING_SIZE) + +// Wrappers for attributes + +/** + * Silence warnings about unused declarations. + */ +#if __has_c_attribute(maybe_unused) +# define _maybe_unused maybe_unused +#elif __has_c_attribute(gnu::unused) +# define _maybe_unused gnu::unused +#else +# define _maybe_unused +#endif + +/** + * Warn if a value is unused. + */ +#if __has_c_attribute(nodiscard) +# define _nodiscard nodiscard +#elif __has_c_attribute(gnu::warn_unused_result) +# define _nodiscard gnu::warn_unused_result +#else +# define _nodiscard +#endif + +/** + * Hint to avoid inlining a function. + */ +#if __has_c_attribute(gnu::noinline) +# define _noinline gnu::noinline +#else +# define _noinline +#endif + +/** + * Hint that a function is unlikely to be called. + */ +#if __has_c_attribute(gnu::cold) +# define _cold _noinline, gnu::cold +#else +# define _cold _noinline +#endif + +/** + * Marks a non-returning function. + */ +#if __has_c_attribute(noreturn) +# define _noreturn noreturn +#elif __has_c_attribute(gnu::noreturn) +# define _noreturn gnu::noreturn +#else +# define _noreturn +#endif + + +/** + * Adds compiler warnings for bad printf()-style function calls, if supported. + */ +#if __has_c_attribute(gnu::format) +# define _printf(fmt, args) gnu::format(printf, fmt, args) +#else +# define _printf(fmt, args) +#endif + +/** + * Annotates functions that potentially modify and return format strings. + */ +#if __has_c_attribute(gnu::format_arg) +# define _format_arg(arg) gnu::format_arg(arg) +#else +# define _format_arg(arg) +#endif + +/** + * Annotates allocator-like functions. + */ +#if __has_c_attribute(gnu::malloc) +# if __GNUC__ >= 11 && !__OPTIMIZE__ // malloc(deallocator) disables inlining on GCC +# define _malloc(...) _nodiscard, gnu::malloc(__VA_ARGS__) +# else +# define _malloc(...) _nodiscard, gnu::malloc +# endif +#else +# define _malloc(...) _nodiscard +#endif + +/** + * Specifies that a function returns allocations with a given alignment. + */ +#if __has_c_attribute(gnu::alloc_align) +# define _alloc_align(param) gnu::alloc_align(param) +#else +# define _alloc_align(param) +#endif + +/** + * Specifies that a function returns allocations with a given size. + */ +#if __has_c_attribute(gnu::alloc_size) +# define _alloc_size(...) gnu::alloc_size(__VA_ARGS__) +#else +# define _alloc_size(...) +#endif + +/** + * Shorthand for _alloc_align() and _alloc_size(). + */ +#define _aligned_alloc(align, ...) _alloc_align(align), _alloc_size(__VA_ARGS__) + +/** + * Check if function multiversioning via GNU indirect functions (ifunc) is supported. + * + * Disabled on TSan due to https://github.com/google/sanitizers/issues/342. + */ +#ifndef BFS_USE_TARGET_CLONES +# if __has_c_attribute(gnu::target_clones) \ + && (__GLIBC__ || __FreeBSD__) \ + && !__SANITIZE_THREAD__ \ + && !__SANITIZE_TYPE__ +# define BFS_USE_TARGET_CLONES true +# else +# define BFS_USE_TARGET_CLONES false +# endif +#endif + +/** + * Apply the target_clones attribute, if available. + */ +#if BFS_USE_TARGET_CLONES +# define _target_clones(...) gnu::target_clones(__VA_ARGS__) +#else +# define _target_clones(...) +#endif + +/** + * Mark the size of a flexible array member. + */ +#if __has_c_attribute(clang::counted_by) +# define _counted_by(...) clang::counted_by(__VA_ARGS__) +#elif __has_c_attribute(gnu::counted_by) +# define _counted_by(...) gnu::counted_by(__VA_ARGS__) +#else +# define _counted_by(...) +#endif + +/** + * Optimization hint to not unroll a loop. + */ +#if BFS_HAS_PRAGMA_NOUNROLL +# define _nounroll _Pragma("nounroll") +#elif __GNUC__ && !__clang__ +# define _nounroll _Pragma("GCC unroll 0") +#else +# define _nounroll +#endif + +#endif // BFS_H |