inline functions that require the full definition of a struct into the
implementation file so that only a forward declaration of the struct is
required and not the full definition.
+ - `src/basic/forward.h` contains forward declarations for common types. If
+ possible, only include `forward.h` in header files which makes circular
+ header dependencies a non-issue.
Bad:
the implementation (.c) file over implementing them in the corresponding
header file. Inline functions in the header are allowed if they are just a few
lines and don't require including any extra header files that would otherwise
- not have to be included. Similarly, prefer forward declarations of structs
- over including the corresponding header file. Keeping header files as lean as
- possible speeds up incremental builds when header files are changed (either by
- yourself when working on a pull request or as part of rebasing onto the main
- branch) as each file that (transitively) includes a header that was changed
- needs to be recompiled. By keeping the number of header files included by
- other header files low, we reduce the impact of modifying header files on
+ not have to be included. Keeping header files as lean as possible speeds up
+ incremental builds when header files are changed (either by yourself when
+ working on a pull request or as part of rebasing onto the main branch) as each
+ file that (transitively) includes a header that was changed needs to be
+ recompiled. By keeping the number of header files included by other header
+ files low, we reduce the impact of modifying header files on
incremental builds as much as possible.
+ To avoid having to include other headers in header files, always include
+ `forward.h` in each header file and then add other required includes as
+ needed. `forward.h` already includes generic headers and contains forward
+ declarations for common types which should be sufficient for most header
+ files. For each extra include you add on top of `forward.h`, check if it can
+ be replaced by adding another forward declaration to `forward.h`. Depending on
+ the daemon, there might be a specific forward header to include (e.g.
+ `resolved-forward.h` for systemd-resolved header files).
+
+ Header files that extend other header files can include the original header
+ file. For example, `iovec-util.h` includes `iovec-fundamental.h` and
+ `sys/uio.h`. To identify headers that are exported from other headers, add a
+ `IWYU pragma: export` comment to the includes so that these exports are
+ recognized by clang static analysis tooling.
+
Bad:
```c
// source.h
+ #include <stddef.h>
+
#include "log.h"
- static inline void my_function_that_logs(void) {
- log_error("oops");
+ static inline void my_function_that_logs(size_t sz) {
+ log_error("oops: %zu", sz);
}
```
```c
// source.h
- void my_function_that_logs(void);
+ #include "forward.h"
+
+ void my_function_that_logs(size_t sz);
// source.c
- #include "header.h"
+ #include "source.h"
#include "log.h"
- void my_function_that_logs(void) {
- log_error("oops");
+ void my_function_that_logs(size_t sz) {
+ log_error("oops: %zu", sz);
}
```
#include <string.h>
#include "assert-util.h"
+#include "cleanup-util.h"
#include "macro.h"
#include "memory-util.h"
# include <sanitizer/msan_interface.h>
#endif
-typedef void (*free_func_t)(void *p);
-typedef void* (*mfree_func_t)(void *p);
-
/* If for some reason more than 4M are allocated on the stack, let's abort immediately. It's better than
* proceeding and smashing the stack limits. Note that by default RLIMIT_STACK is 8M on Linux. */
#define ALLOCA_MAX (4U*1024U*1024U)
#define malloc0(n) (calloc(1, (n) ?: 1))
-#define free_and_replace_full(a, b, free_func) \
- ({ \
- typeof(a)* _a = &(a); \
- typeof(b)* _b = &(b); \
- free_func(*_a); \
- *_a = *_b; \
- *_b = NULL; \
- 0; \
- })
-
#define free_and_replace(a, b) \
free_and_replace_full(a, b, free)
-/* This is similar to free_and_replace_full(), but NULL is not assigned to 'b', and its reference counter is
- * increased. */
-#define unref_and_replace_full(a, b, ref_func, unref_func) \
- ({ \
- typeof(a)* _a = &(a); \
- typeof(b) _b = ref_func(b); \
- unref_func(*_a); \
- *_a = _b; \
- 0; \
- })
-
void* memdup(const void *p, size_t l) _alloc_(2);
void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, since we return a buffer one byte larger than the specified size */
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "cleanup-fundamental.h" /* IWYU pragma: export */
+
+typedef void (*free_func_t)(void *p);
+typedef void* (*mfree_func_t)(void *p);
+
+#define free_and_replace_full(a, b, free_func) \
+ ({ \
+ typeof(a)* _a = &(a); \
+ typeof(b)* _b = &(b); \
+ free_func(*_a); \
+ *_a = *_b; \
+ *_b = NULL; \
+ 0; \
+ })
+
+/* This is similar to free_and_replace_full(), but NULL is not assigned to 'b', and its reference counter is
+ * increased. */
+#define unref_and_replace_full(a, b, ref_func, unref_func) \
+ ({ \
+ typeof(a)* _a = &(a); \
+ typeof(b) _b = ref_func(b); \
+ unref_func(*_a); \
+ *_a = _b; \
+ 0; \
+ })
+
+#define _DEFINE_TRIVIAL_REF_FUNC(type, name, scope) \
+ scope type *name##_ref(type *p) { \
+ if (!p) \
+ return NULL; \
+ \
+ /* For type check. */ \
+ unsigned *q = &p->n_ref; \
+ assert(*q > 0); \
+ assert_se(*q < UINT_MAX); \
+ \
+ (*q)++; \
+ return p; \
+ }
+
+#define _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, scope) \
+ scope type *name##_unref(type *p) { \
+ if (!p) \
+ return NULL; \
+ \
+ assert(p->n_ref > 0); \
+ p->n_ref--; \
+ if (p->n_ref > 0) \
+ return NULL; \
+ \
+ return free_func(p); \
+ }
+
+#define DEFINE_TRIVIAL_REF_FUNC(type, name) \
+ _DEFINE_TRIVIAL_REF_FUNC(type, name,)
+#define DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name) \
+ _DEFINE_TRIVIAL_REF_FUNC(type, name, static)
+#define DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name) \
+ _DEFINE_TRIVIAL_REF_FUNC(type, name, _public_)
+
+#define DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func) \
+ _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func,)
+#define DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func) \
+ _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, static)
+#define DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func) \
+ _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, _public_)
+
+#define DEFINE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \
+ DEFINE_TRIVIAL_REF_FUNC(type, name); \
+ DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func);
+
+#define DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \
+ DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name); \
+ DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func);
+
+#define DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \
+ DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name); \
+ DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <errno.h> /* IWYU pragma: export */
+#include <inttypes.h> /* IWYU pragma: export */
+#include <limits.h> /* IWYU pragma: export */
+#include <stdarg.h> /* IWYU pragma: export */
+#include <stdbool.h> /* IWYU pragma: export */
+#include <stddef.h> /* IWYU pragma: export */
+#include <stdint.h> /* IWYU pragma: export */
+#include <sys/types.h> /* IWYU pragma: export */
+#include <uchar.h> /* IWYU pragma: export */
+
+#include "assert-util.h" /* IWYU pragma: export */
+#include "cleanup-util.h" /* IWYU pragma: export */
+#include "macro.h" /* IWYU pragma: export */
+
+/* Generic types */
+
+typedef uint64_t usec_t;
+typedef uint64_t nsec_t;
+
+/* Libc forward declarations */
+
+struct dirent;
+struct ether_addr;
+struct file_handle;
+struct glob_t;
+struct group;
+struct icmp6_hdr;
+struct in_addr;
+struct in6_addr;
+struct inotify_event;
+struct iovec;
+struct msghdr;
+struct passwd;
+struct pollfd;
+struct rlimit;
+struct sgrp;
+struct shadow;
+struct signalfd_siginfo;
+struct siphash;
+struct sockaddr;
+struct spwd;
+struct stat;
+struct statfs;
+struct statx_timestamp;
+struct statx;
+struct termios;
+struct tm;
+struct ucred;
+
+/* To forward declare FILE and DIR, we have to declare the internal struct names for them. Since these are
+ * used for C++ symbol name mangling, they're effectively part of the ABI and won't actually change. */
+typedef struct _IO_FILE FILE;
+typedef struct __dirstream DIR;
+typedef __socklen_t socklen_t;
+
+/* 3rd-party library forward declarations */
+
+struct fdisk_context;
+struct fdisk_table;
+struct crypt_device;
+
+/* basic/ forward declarations */
+
+typedef void (*hash_func_t)(const void *p, struct siphash *state);
+typedef int (*compare_func_t)(const void *a, const void *b);
+typedef compare_func_t comparison_fn_t;
+typedef int (*comparison_userdata_fn_t)(const void *, const void *, void *);
+
+struct hash_ops;
+struct hw_addr_data;
+struct in_addr_data;
+struct iovec_wrapper;
+union in_addr_union;
+union sockaddr_union;
+
+typedef enum JobMode JobMode;
+typedef enum RuntimeScope RuntimeScope;
+typedef enum TimestampStyle TimestampStyle;
+typedef enum UnitActiveState UnitActiveState;
+typedef enum UnitDependency UnitDependency;
+
+typedef struct Hashmap Hashmap;
+typedef struct HashmapBase HashmapBase;
+typedef struct IteratedCache IteratedCache;
+typedef struct Iterator Iterator;
+typedef struct OrderedHashmap OrderedHashmap;
+typedef struct OrderedSet OrderedSet;
+typedef struct Set Set;
+
+typedef struct dual_timestamp dual_timestamp;
+typedef struct triple_timestamp triple_timestamp;
+typedef struct PidRef PidRef;
+typedef struct Prioq Prioq;
+typedef struct RateLimit RateLimit;
+typedef struct SocketAddress SocketAddress;
+
+/* libsystemd/ and libsystemd-network/ forward declarations */
+
+typedef void (*_sd_destroy_t)(void *userdata);
+
+typedef union sd_id128 sd_id128_t;
+
+typedef struct sd_event sd_event;
+typedef struct sd_event_source sd_event_source;
+
+typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata);
+typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata);
+typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata);
+typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata);
+typedef int (*sd_event_inotify_handler_t)(sd_event_source *s, const struct inotify_event *event, void *userdata);
+typedef _sd_destroy_t sd_event_destroy_t;
+
+enum ENUM_TYPE_S64(sd_json_format_flags_t);
+enum ENUM_TYPE_S64(sd_json_dispatch_flags_t);
+enum ENUM_TYPE_S64(sd_json_variant_type_t);
+enum ENUM_TYPE_S64(sd_json_parse_flags_t);
+
+typedef enum sd_json_format_flags_t sd_json_format_flags_t;
+typedef enum sd_json_dispatch_flags_t sd_json_dispatch_flags_t;
+typedef enum sd_json_variant_type_t sd_json_variant_type_t;
+typedef enum sd_json_parse_flags_t sd_json_parse_flags_t;
+
+typedef struct sd_json_variant sd_json_variant;
+
+typedef struct sd_bus sd_bus;
+typedef struct sd_bus_error sd_bus_error;
+typedef struct sd_bus_error_map sd_bus_error_map;
+typedef struct sd_bus_message sd_bus_message;
+typedef struct sd_bus_slot sd_bus_slot;
+typedef struct sd_bus_creds sd_bus_creds;
+typedef struct sd_bus_track sd_bus_track;
+typedef struct sd_bus_vtable sd_bus_vtable;
+
+typedef int (*sd_bus_message_handler_t)(sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
+typedef int (*sd_bus_property_get_t)(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error);
+typedef int (*sd_bus_property_set_t)(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *ret_error);
+typedef int (*sd_bus_object_find_t)(sd_bus *bus, const char *path, const char *interface, void *userdata, void **ret_found, sd_bus_error *ret_error);
+typedef int (*sd_bus_node_enumerator_t)(sd_bus *bus, const char *prefix, void *userdata, char ***ret_nodes, sd_bus_error *ret_error);
+typedef int (*sd_bus_track_handler_t)(sd_bus_track *track, void *userdata);
+typedef _sd_destroy_t sd_bus_destroy_t;
+
+enum ENUM_TYPE_S64(sd_device_action_t);
+
+typedef enum sd_device_action_t sd_device_action_t;
+
+typedef struct sd_device sd_device;
+typedef struct sd_device_enumerator sd_device_enumerator;
+typedef struct sd_device_monitor sd_device_monitor;
+
+typedef struct sd_netlink sd_netlink;
+typedef struct sd_netlink_message sd_netlink_message;
+typedef struct sd_netlink_slot sd_netlink_slot;
+
+typedef int (*sd_netlink_message_handler_t)(sd_netlink *nl, sd_netlink_message *m, void *userdata);
+typedef _sd_destroy_t sd_netlink_destroy_t;
+
+typedef struct sd_network_monitor sd_network_monitor;
+
+enum ENUM_TYPE_S64(sd_dhcp_lease_server_type_t);
+enum ENUM_TYPE_S64(sd_lldp_rx_event_t);
+enum ENUM_TYPE_S64(sd_lldp_multicast_mode_t);
+enum ENUM_TYPE_S64(sd_ndisc_event_t);
+
+typedef enum sd_dhcp_lease_server_type_t sd_dhcp_lease_server_type_t;
+typedef enum sd_lldp_rx_event_t sd_lldp_rx_event_t;
+typedef enum sd_lldp_multicast_mode_t sd_lldp_multicast_mode_t;
+typedef enum sd_ndisc_event_t sd_ndisc_event_t;
+
+typedef struct sd_ipv4ll sd_ipv4ll;
+typedef struct sd_dhcp_client sd_dhcp_client;
+typedef struct sd_dhcp_lease sd_dhcp_lease;
+typedef struct sd_dhcp_route sd_dhcp_route;
+typedef struct sd_dns_resolver sd_dns_resolver;
+typedef struct sd_dhcp_server sd_dhcp_server;
+typedef struct sd_ndisc sd_ndisc;
+typedef struct sd_radv sd_radv;
+typedef struct sd_dhcp6_client sd_dhcp6_client;
+typedef struct sd_dhcp6_lease sd_dhcp6_lease;
+typedef struct sd_lldp_tx sd_lldp_tx;
+typedef struct sd_lldp_rx sd_lldp_rx;
+typedef struct sd_lldp_neighbor sd_lldp_neighbor;
+
+typedef struct ICMP6Packet ICMP6Packet;
+
+enum ENUM_TYPE_S64(sd_varlink_method_flags_t);
+enum ENUM_TYPE_S64(sd_varlink_interface_flags_t);
+enum ENUM_TYPE_S64(sd_varlink_symbol_type_t);
+enum ENUM_TYPE_S64(sd_varlink_field_type_t);
+enum ENUM_TYPE_S64(sd_varlink_field_direction_t);
+enum ENUM_TYPE_S64(sd_varlink_field_flags_t);
+enum ENUM_TYPE_S64(sd_varlink_idl_format_flags_t);
+enum ENUM_TYPE_S64(sd_varlink_reply_flags_t);
+enum ENUM_TYPE_S64(sd_varlink_server_flags_t);
+enum ENUM_TYPE_S64(sd_varlink_invocation_flags_t);
+
+typedef enum sd_varlink_method_flags_t sd_varlink_method_flags_t;
+typedef enum sd_varlink_interface_flags_t sd_varlink_interface_flags_t;
+typedef enum sd_varlink_symbol_type_t sd_varlink_symbol_type_t;
+typedef enum sd_varlink_field_type_t sd_varlink_field_type_t;
+typedef enum sd_varlink_field_direction_t sd_varlink_field_direction_t;
+typedef enum sd_varlink_field_flags_t sd_varlink_field_flags_t;
+typedef enum sd_varlink_idl_format_flags_t sd_varlink_idl_format_flags_t;
+typedef enum sd_varlink_reply_flags_t sd_varlink_reply_flags_t;
+typedef enum sd_varlink_server_flags_t sd_varlink_server_flags_t;
+typedef enum sd_varlink_invocation_flags_t sd_varlink_invocation_flags_t;
+
+typedef struct sd_varlink sd_varlink;
+typedef struct sd_varlink_server sd_varlink_server;
+typedef struct sd_varlink_field sd_varlink_field;
+typedef struct sd_varlink_symbol sd_varlink_symbol;
+typedef struct sd_varlink_interface sd_varlink_interface;
+
+typedef struct sd_journal sd_journal;
+
+typedef struct sd_resolve sd_resolve;
+typedef struct sd_resolve_query sd_resolve_query;
+
+typedef struct sd_hwdb sd_hwdb;
+
+/* shared/ forward declarations */
+
+struct local_address;
+struct in_addr_prefix;
+
+typedef enum AskPasswordFlags AskPasswordFlags;
+typedef enum BootEntryTokenType BootEntryTokenType;
+typedef enum BusPrintPropertyFlags BusPrintPropertyFlags;
+typedef enum BusTransport BusTransport;
+typedef enum CatFlags CatFlags;
+typedef enum CertificateSourceType CertificateSourceType;
+typedef enum DnsCacheMode DnsCacheMode;
+typedef enum DnsOverTlsMode DnsOverTlsMode;
+typedef enum DnssecMode DnssecMode;
+typedef enum Fido2EnrollFlags Fido2EnrollFlags;
+typedef enum KeySourceType KeySourceType;
+typedef enum MountInNamespaceFlags MountInNamespaceFlags;
+typedef enum NamePolicy NamePolicy;
+typedef enum OutputMode OutputMode;
+typedef enum PagerFlags PagerFlags;
+typedef enum PatternCompileCase PatternCompileCase;
+typedef enum ResolveSupport ResolveSupport;
+typedef enum TPM2Flags TPM2Flags;
+typedef enum UnitFileFlags UnitFileFlags;
+typedef enum UnitFilePresetMode UnitFilePresetMode;
+typedef enum UnitFileState UnitFileState;
+typedef enum UserRecordLoadFlags UserRecordLoadFlags;
+typedef enum UserStorage UserStorage;
+
+typedef struct Bitmap Bitmap;
+typedef struct BPFProgram BPFProgram;
+typedef struct CalendarSpec CalendarSpec;
+typedef struct Condition Condition;
+typedef struct ConfigSection ConfigSection;
+typedef struct ConfigTableItem ConfigTableItem;
+typedef struct CPUSet CPUSet;
+typedef struct FDSet FDSet;
+typedef struct Fido2HmacSalt Fido2HmacSalt;
+typedef struct FirewallContext FirewallContext;
+typedef struct GroupRecord GroupRecord;
+typedef struct Image Image;
+typedef struct ImagePolicy ImagePolicy;
+typedef struct LookupPaths LookupPaths;
+typedef struct LoopDevice LoopDevice;
+typedef struct MountOptions MountOptions;
+typedef struct OpenFile OpenFile;
+typedef struct Pkcs11EncryptedKey Pkcs11EncryptedKey;
+typedef struct Table Table;
+typedef struct Tpm2PCRValue Tpm2PCRValue;
+typedef struct UnitInfo UnitInfo;
+typedef struct UserRecord UserRecord;
+typedef struct VeritySettings VeritySettings;
+
+/* Constants */
+
+/* We duplicate various commonly used constants here so we can keep most static inline functions without
+ * having to include the full header that provides these constants. */
+
+#define AT_FDCWD -100
+#define AT_EMPTY_PATH 0x1000
+#define AT_SYMLINK_FOLLOW 0x400
+#define AT_SYMLINK_NOFOLLOW 0x100
+
+#define MODE_INVALID ((mode_t) -1)
+
+#define UID_INVALID ((uid_t) -1)
+#define GID_INVALID ((gid_t) -1)
+
+#define USEC_INFINITY ((usec_t) UINT64_MAX)
+#define NSEC_INFINITY ((nsec_t) UINT64_MAX)
+
+/* MAX_ERRNO is defined as 4095 in linux/err.h. We use the same value here. */
+#define ERRNO_MAX 4095
#include <string.h>
#include <sys/types.h>
+#include "cleanup-util.h"
#include "macro.h"
#include "memory-util-fundamental.h"
/* Makes a copy of the buffer with reversed order of bytes */
void* memdup_reverse(const void *mem, size_t size);
-
-#define _DEFINE_TRIVIAL_REF_FUNC(type, name, scope) \
- scope type *name##_ref(type *p) { \
- if (!p) \
- return NULL; \
- \
- /* For type check. */ \
- unsigned *q = &p->n_ref; \
- assert(*q > 0); \
- assert_se(*q < UINT_MAX); \
- \
- (*q)++; \
- return p; \
- }
-
-#define _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, scope) \
- scope type *name##_unref(type *p) { \
- if (!p) \
- return NULL; \
- \
- assert(p->n_ref > 0); \
- p->n_ref--; \
- if (p->n_ref > 0) \
- return NULL; \
- \
- return free_func(p); \
- }
-
-#define DEFINE_TRIVIAL_REF_FUNC(type, name) \
- _DEFINE_TRIVIAL_REF_FUNC(type, name,)
-#define DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name) \
- _DEFINE_TRIVIAL_REF_FUNC(type, name, static)
-#define DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name) \
- _DEFINE_TRIVIAL_REF_FUNC(type, name, _public_)
-
-#define DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func) \
- _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func,)
-#define DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func) \
- _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, static)
-#define DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func) \
- _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, _public_)
-
-#define DEFINE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \
- DEFINE_TRIVIAL_REF_FUNC(type, name); \
- DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func);
-
-#define DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \
- DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name); \
- DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func);
-
-#define DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \
- DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name); \
- DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "assert-fundamental.h"
+
+/* A wrapper for 'func' to return void.
+ * Only useful when a void-returning function is required by some API. */
+#define DEFINE_TRIVIAL_DESTRUCTOR(name, type, func) \
+ static inline void name(type *p) { \
+ func(p); \
+ }
+
+/* When func() returns the void value (NULL, -1, …) of the appropriate type */
+#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
+ static inline void func##p(type *p) { \
+ if (*p) \
+ *p = func(*p); \
+ }
+
+/* When func() doesn't return the appropriate type, set variable to empty afterwards.
+ * The func() may be provided by a dynamically loaded shared library, hence add an assertion. */
+#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(type, func, empty) \
+ static inline void func##p(type *p) { \
+ if (*p != (empty)) { \
+ DISABLE_WARNING_ADDRESS; \
+ assert(func); \
+ REENABLE_WARNING; \
+ func(*p); \
+ *p = (empty); \
+ } \
+ }
+
+/* When func() doesn't return the appropriate type, and is also a macro, set variable to empty afterwards. */
+#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_MACRO(type, func, empty) \
+ static inline void func##p(type *p) { \
+ if (*p != (empty)) { \
+ func(*p); \
+ *p = (empty); \
+ } \
+ }
+
+typedef void (*free_array_func_t)(void *p, size_t n);
+
+/* An automatic _cleanup_-like logic for destroy arrays (i.e. pointers + size) when leaving scope */
+typedef struct ArrayCleanup {
+ void **parray;
+ size_t *pn;
+ free_array_func_t pfunc;
+} ArrayCleanup;
+
+static inline void array_cleanup(const ArrayCleanup *c) {
+ assert(c);
+ assert(!c->parray == !c->pn);
+
+ if (!c->parray)
+ return;
+
+ if (*c->parray) {
+ assert(c->pfunc);
+ c->pfunc(*c->parray, *c->pn);
+ *c->parray = NULL;
+ }
+
+ *c->pn = 0;
+}
+
+#define CLEANUP_ARRAY(array, n, func) \
+ _cleanup_(array_cleanup) _unused_ const ArrayCleanup CONCATENATE(_cleanup_array_, UNIQ) = { \
+ .parray = (void**) &(array), \
+ .pn = &(n), \
+ .pfunc = (free_array_func_t) ({ \
+ void (*_f)(typeof(array[0]) *a, size_t b) = func; \
+ _f; \
+ }), \
+ }
assert_cc(STRLEN(__FILE__) > STRLEN(RELATIVE_SOURCE_PATH) + 1);
#define PROJECT_FILE (&__FILE__[STRLEN(RELATIVE_SOURCE_PATH) + 1])
+
+/* In GCC 14 (C23) we can force enums to have the right types, and not solely rely on language extensions anymore */
+#if __GNUC__ >= 14 || __STDC_VERSION__ >= 202311L
+# define ENUM_TYPE_S64(id) id : int64_t
+#else
+# define ENUM_TYPE_S64(id) id
+#endif
#endif
#include "assert-fundamental.h"
+#include "cleanup-fundamental.h"
#include "macro-fundamental.h"
#define memzero(x, l) \
.size = (sz), \
}
-typedef void (*free_array_func_t)(void *p, size_t n);
-
-/* An automatic _cleanup_-like logic for destroy arrays (i.e. pointers + size) when leaving scope */
-typedef struct ArrayCleanup {
- void **parray;
- size_t *pn;
- free_array_func_t pfunc;
-} ArrayCleanup;
-
-static inline void array_cleanup(const ArrayCleanup *c) {
- assert(c);
-
- assert(!c->parray == !c->pn);
-
- if (!c->parray)
- return;
-
- if (*c->parray) {
- assert(c->pfunc);
- c->pfunc(*c->parray, *c->pn);
- *c->parray = NULL;
- }
-
- *c->pn = 0;
-}
-
-#define CLEANUP_ARRAY(array, n, func) \
- _cleanup_(array_cleanup) _unused_ const ArrayCleanup CONCATENATE(_cleanup_array_, UNIQ) = { \
- .parray = (void**) &(array), \
- .pn = &(n), \
- .pfunc = (free_array_func_t) ({ \
- void (*_f)(typeof(array[0]) *a, size_t b) = func; \
- _f; \
- }), \
- }
-
-/* A wrapper for 'func' to return void.
- * Only useful when a void-returning function is required by some API. */
-#define DEFINE_TRIVIAL_DESTRUCTOR(name, type, func) \
- static inline void name(type *p) { \
- func(p); \
- }
-
-/* When func() returns the void value (NULL, -1, …) of the appropriate type */
-#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
- static inline void func##p(type *p) { \
- if (*p) \
- *p = func(*p); \
- }
-
-/* When func() doesn't return the appropriate type, set variable to empty afterwards.
- * The func() may be provided by a dynamically loaded shared library, hence add an assertion. */
-#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(type, func, empty) \
- static inline void func##p(type *p) { \
- if (*p != (empty)) { \
- DISABLE_WARNING_ADDRESS; \
- assert(func); \
- REENABLE_WARNING; \
- func(*p); \
- *p = (empty); \
- } \
- }
-
-/* When func() doesn't return the appropriate type, and is also a macro, set variable to empty afterwards. */
-#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_MACRO(type, func, empty) \
- static inline void func##p(type *p) { \
- if (*p != (empty)) { \
- func(*p); \
- *p = (empty); \
- } \
- }
-
static inline size_t ALIGN_TO(size_t l, size_t ali) {
assert(ISPOWEROF2(ali));