summaryrefslogtreecommitdiffstats
path: root/src/bfs.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/bfs.h')
-rw-r--r--src/bfs.h268
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