From e74c568b07b50b97873fb4ee1d776dedefbd54d6 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Fri, 1 Oct 2021 23:05:04 +0200 Subject: New upstream version 1.32.12 --- src/libnm-std-aux/c-list-util.c | 184 ++++ src/libnm-std-aux/c-list-util.h | 56 ++ src/libnm-std-aux/meson.build | 13 + src/libnm-std-aux/nm-dbus-compat.h | 25 + src/libnm-std-aux/nm-default-std.h | 102 +++ src/libnm-std-aux/nm-linux-compat.h | 25 + src/libnm-std-aux/nm-networkmanager-compilation.h | 54 ++ src/libnm-std-aux/nm-std-aux.h | 978 ++++++++++++++++++++++ src/libnm-std-aux/nm-std-utils.c | 90 ++ src/libnm-std-aux/nm-std-utils.h | 37 + src/libnm-std-aux/unaligned.h | 99 +++ 11 files changed, 1663 insertions(+) create mode 100644 src/libnm-std-aux/c-list-util.c create mode 100644 src/libnm-std-aux/c-list-util.h create mode 100644 src/libnm-std-aux/meson.build create mode 100644 src/libnm-std-aux/nm-dbus-compat.h create mode 100644 src/libnm-std-aux/nm-default-std.h create mode 100644 src/libnm-std-aux/nm-linux-compat.h create mode 100644 src/libnm-std-aux/nm-networkmanager-compilation.h create mode 100644 src/libnm-std-aux/nm-std-aux.h create mode 100644 src/libnm-std-aux/nm-std-utils.c create mode 100644 src/libnm-std-aux/nm-std-utils.h create mode 100644 src/libnm-std-aux/unaligned.h (limited to 'src/libnm-std-aux') diff --git a/src/libnm-std-aux/c-list-util.c b/src/libnm-std-aux/c-list-util.c new file mode 100644 index 00000000..d16bd6b7 --- /dev/null +++ b/src/libnm-std-aux/c-list-util.c @@ -0,0 +1,184 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2017 Red Hat, Inc. + */ + +#include "c-list-util.h" + +/*****************************************************************************/ + +/** + * c_list_relink: + * @lst: the head list entry + * + * Takes an invalid list, that has undefined prev pointers. + * Only the next pointers are valid, and the tail's next + * pointer points to %NULL instead of the head. + * + * c_list_relink() fixes the list by updating all prev pointers + * and close the circular linking by pointing the tails' next + * pointer to @lst. + * + * The use of this function is to do a bulk update, that lets the + * list degenerate by not updating the prev pointers. At the end, + * the list can be fixed by c_list_relink(). + */ +void +c_list_relink(CList *lst) +{ + CList *ls, *ls_prev; + + ls_prev = lst; + ls = lst->next; + do { + ls->prev = ls_prev; + ls_prev = ls; + ls = ls->next; + } while (ls); + ls_prev->next = lst; + lst->prev = ls_prev; +} + +/*****************************************************************************/ + +static CList * +_c_list_srt_split(CList *ls) +{ + CList *ls2; + + ls2 = ls; + ls = ls->next; + if (!ls) + return NULL; + do { + ls = ls->next; + if (!ls) + break; + ls = ls->next; + ls2 = ls2->next; + } while (ls); + ls = ls2->next; + ls2->next = NULL; + return ls; +} + +static CList * +_c_list_srt_merge(CList *ls1, CList *ls2, CListSortCmp cmp, const void *user_data) +{ + CList *ls; + CList head; + + ls = &head; + for (;;) { + /* while invoking the @cmp function, the list + * elements are not properly linked. Don't try to access + * their next/prev pointers. */ + if (cmp(ls1, ls2, user_data) <= 0) { + ls->next = ls1; + ls = ls1; + ls1 = ls1->next; + if (!ls1) + break; + } else { + ls->next = ls2; + ls = ls2; + ls2 = ls2->next; + if (!ls2) + break; + } + } + ls->next = ls1 ?: ls2; + + return head.next; +} + +typedef struct { + CList *ls1; + CList *ls2; + char ls1_sorted; +} SortStack; + +static CList * +_c_list_sort(CList *ls, CListSortCmp cmp, const void *user_data) +{ + /* reserve a huge stack-size. We need roughly log2(n) entries, hence this + * is much more we will ever need. We don't guard for stack-overflow either. */ + SortStack stack_arr[70]; + SortStack *stack_head = stack_arr; + + stack_arr[0].ls1 = ls; + + /* A simple top-down, non-recursive, stable merge-sort. + * + * Maybe natural merge-sort would be better, to do better for + * partially sorted lists. Doing that would be much more complicated, + * so it's not done. */ +_split: + stack_head[0].ls2 = _c_list_srt_split(stack_head[0].ls1); + if (stack_head[0].ls2) { + stack_head[0].ls1_sorted = 0; + stack_head[1].ls1 = stack_head[0].ls1; + stack_head++; + goto _split; + } + +_backtrack: + if (stack_head == stack_arr) + return stack_arr[0].ls1; + + stack_head--; + if (!stack_head[0].ls1_sorted) { + stack_head[0].ls1 = stack_head[1].ls1; + stack_head[0].ls1_sorted = 1; + stack_head[1].ls1 = stack_head[0].ls2; + stack_head++; + goto _split; + } + + stack_head[0].ls1 = _c_list_srt_merge(stack_head[0].ls1, stack_head[1].ls1, cmp, user_data); + goto _backtrack; +} + +/** + * c_list_sort_headless: + * @lst: the list. + * @cmp: compare function for sorting. While comparing two + * CList elements, their next/prev pointers are in undefined + * state. + * @user_data: user data for @cmp. + * + * Sorts the list @lst according to @cmp. Contrary to + * c_list_sort(), @lst is not the list head but a + * valid entry as well. This function returns the new + * list head. + */ +CList * +c_list_sort_headless(CList *lst, CListSortCmp cmp, const void *user_data) +{ + if (!c_list_is_empty(lst)) { + lst->prev->next = NULL; + lst = _c_list_sort(lst, cmp, user_data); + c_list_relink(lst); + } + return lst; +} + +/** + * c_list_sort: + * @head: the list head. + * @cmp: compare function for sorting. While comparing two + * CList elements, their next/prev pointers are in undefined + * state. + * @user_data: user data for @cmp. + * + * Sorts the list @head according to @cmp. + */ +void +c_list_sort(CList *head, CListSortCmp cmp, const void *user_data) +{ + if (!c_list_is_empty(head) && head->next->next != head) { + head->prev->next = NULL; + head->next = _c_list_sort(head->next, cmp, user_data); + c_list_relink(head); + } +} diff --git a/src/libnm-std-aux/c-list-util.h b/src/libnm-std-aux/c-list-util.h new file mode 100644 index 00000000..9d86d663 --- /dev/null +++ b/src/libnm-std-aux/c-list-util.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2017 Red Hat, Inc. + */ + +#ifndef __C_LIST_UTIL_H__ +#define __C_LIST_UTIL_H__ + +#include "c-list/src/c-list.h" + +/*****************************************************************************/ + +void c_list_relink(CList *lst); + +typedef int (*CListSortCmp)(const CList *a, const CList *b, const void *user_data); + +CList *c_list_sort_headless(CList *lst, CListSortCmp cmp, const void *user_data); + +void c_list_sort(CList *head, CListSortCmp cmp, const void *user_data); + +/* c_list_length_is: + * @list: the #CList list head + * @check_len: the length to compare + * + * Returns: basically the same as (c_list_length (@list) == @check_len), + * but does not require to iterate the entire list first. There is only + * one real use: to find out whether there is exactly one element in the + * list, by passing @check_len as 1. + */ +static inline int +c_list_length_is(const CList *list, unsigned long check_len) +{ + unsigned long n = 0; + const CList * iter; + + c_list_for_each (iter, list) { + ++n; + if (n > check_len) + return 0; + } + + return n == check_len; +} + +#define c_list_for_each_prev(_iter, _list) \ + for (_iter = (_list)->prev; (_iter) != (_list); _iter = (_iter)->prev) + +#define c_list_for_each_prev_safe(_iter, _safe, _list) \ + for (_iter = (_list)->prev, _safe = (_iter)->prev; (_iter) != (_list); \ + _iter = (_safe), _safe = (_safe)->prev) + +#define c_list_for_each_entry_prev(_iter, _list, _m) \ + for (_iter = c_list_entry((_list)->prev, __typeof__(*_iter), _m); &(_iter)->_m != (_list); \ + _iter = c_list_entry((_iter)->_m.prev, __typeof__(*_iter), _m)) + +#endif /* __C_LIST_UTIL_H__ */ diff --git a/src/libnm-std-aux/meson.build b/src/libnm-std-aux/meson.build new file mode 100644 index 00000000..d7b24528 --- /dev/null +++ b/src/libnm-std-aux/meson.build @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +libnm_std_aux = static_library( + 'nm-std-aux', + sources: [ + 'c-list-util.c', + 'nm-std-utils.c', + ], + include_directories: [ + src_inc, + top_inc, + ], +) diff --git a/src/libnm-std-aux/nm-dbus-compat.h b/src/libnm-std-aux/nm-dbus-compat.h new file mode 100644 index 00000000..c1076200 --- /dev/null +++ b/src/libnm-std-aux/nm-dbus-compat.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#ifndef __NM_DBUS_COMPAT_H__ +#define __NM_DBUS_COMPAT_H__ + +#define DBUS_SERVICE_DBUS "org.freedesktop.DBus" + +#define DBUS_PATH_DBUS "/org/freedesktop/DBus" + +#define DBUS_INTERFACE_DBUS "org.freedesktop.DBus" +#define DBUS_INTERFACE_INTROSPECTABLE "org.freedesktop.DBus.Introspectable" +#define DBUS_INTERFACE_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager" +#define DBUS_INTERFACE_PEER "org.freedesktop.DBus.Peer" +#define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties" + +#define DBUS_NAME_FLAG_ALLOW_REPLACEMENT 0x1 +#define DBUS_NAME_FLAG_REPLACE_EXISTING 0x2 +#define DBUS_NAME_FLAG_DO_NOT_QUEUE 0x4 + +#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 +#define DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2 +#define DBUS_REQUEST_NAME_REPLY_EXISTS 3 +#define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4 + +#endif /* __NM_DBUS_COMPAT_H__ */ diff --git a/src/libnm-std-aux/nm-default-std.h b/src/libnm-std-aux/nm-default-std.h new file mode 100644 index 00000000..5f4af3a5 --- /dev/null +++ b/src/libnm-std-aux/nm-default-std.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2015 Red Hat, Inc. + */ + +#ifndef __NM_DEFAULT_STD_H__ +#define __NM_DEFAULT_STD_H__ + +#include "nm-networkmanager-compilation.h" + +#ifdef NETWORKMANAGER_COMPILATION + #error Dont define NETWORKMANAGER_COMPILATION +#endif + +#ifndef G_LOG_DOMAIN + #define G_LOG_DOMAIN "nm" +#endif + +/*****************************************************************************/ + +#define NETWORKMANAGER_COMPILATION 0 + +/*****************************************************************************/ + +/* always include these headers for our internal source files. */ + +#ifndef ___CONFIG_H__ + #define ___CONFIG_H__ + #include +#endif + +#include "config-extra.h" + +/* for internal compilation we don't want the deprecation macros + * to be in effect. Define the widest range of versions to effectively + * disable deprecation checks */ +#define NM_VERSION_MIN_REQUIRED NM_VERSION_0_9_8 + +#ifndef NM_MORE_ASSERTS + #define NM_MORE_ASSERTS 0 +#endif + +#if NM_MORE_ASSERTS == 0 + /* The cast macros like NM_TYPE() are implemented via G_TYPE_CHECK_INSTANCE_CAST() + * and _G_TYPE_CIC(). The latter, by default performs runtime checks of the type + * by calling g_type_check_instance_cast(). + * This check has a certain overhead without being helpful. + * + * Example 1: + * static void foo (NMType *obj) + * { + * access_obj_without_check (obj); + * } + * foo ((NMType *) obj); + * // There is no runtime check and passing an invalid pointer + * // leads to a crash. + * + * Example 2: + * static void foo (NMType *obj) + * { + * access_obj_without_check (obj); + * } + * foo (NM_TYPE (obj)); + * // There is a runtime check which prints a g_warning(), but that doesn't + * // avoid the crash as NM_TYPE() cannot do anything then passing on the + * // invalid pointer. + * + * Example 3: + * static void foo (NMType *obj) + * { + * g_return_if_fail (NM_IS_TYPE (obj)); + * access_obj_without_check (obj); + * } + * foo ((NMType *) obj); + * // There is a runtime check which prints a g_critical() which also avoids + * // the crash. That is actually helpful to catch bugs and avoid crashes. + * + * Example 4: + * static void foo (NMType *obj) + * { + * g_return_if_fail (NM_IS_TYPE (obj)); + * access_obj_without_check (obj); + * } + * foo (NM_TYPE (obj)); + * // The runtime check is performed twice, with printing a g_warning() and + * // a g_critical() and avoiding the crash. + * + * Example 3 is how it should be done. Type checks in NM_TYPE() are pointless. + * Disable them for our production builds. + */ + #ifndef G_DISABLE_CAST_CHECKS + #define G_DISABLE_CAST_CHECKS + #endif +#endif + +/*****************************************************************************/ + +#include + +/*****************************************************************************/ + +#endif /* __NM_DEFAULT_STD_H__ */ diff --git a/src/libnm-std-aux/nm-linux-compat.h b/src/libnm-std-aux/nm-linux-compat.h new file mode 100644 index 00000000..7492d527 --- /dev/null +++ b/src/libnm-std-aux/nm-linux-compat.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#ifndef __NM_LINUX_COMPAT_H__ +#define __NM_LINUX_COMPAT_H__ + +/* We have copies of linux UAPI headers in `src/linux-headers` which + * should be preferred over the headers on the system. However, these + * newer headers might be incompatible with the installed UAPI headers. + * + * This nm-linux-compat.h header tries to solve that and apply the necessary + * workarounds. + * + * Unlike most NetworkManager headers, this header needs to be included + * *before* most system headers. */ + +#include + +#ifndef __KERNEL_DIV_ROUND_UP + #define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) -1) / (d)) +#endif + +#include "linux-headers/ethtool.h" +#include "linux-headers/nl802154.h" + +#endif /* __NM_LINUX_COMPAT_H__ */ diff --git a/src/libnm-std-aux/nm-networkmanager-compilation.h b/src/libnm-std-aux/nm-networkmanager-compilation.h new file mode 100644 index 00000000..025a158d --- /dev/null +++ b/src/libnm-std-aux/nm-networkmanager-compilation.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2015 Red Hat, Inc. + */ + +#ifndef __NM_NETWORKMANAGER_COMPILATION_H__ +#define __NM_NETWORKMANAGER_COMPILATION_H__ + +#define NM_NETWORKMANAGER_COMPILATION_WITH_GLIB (1 << 0) +#define NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB (1 << 1) +#define NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG (1 << 2) +#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM (1 << 3) +#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE (1 << 4) +#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE (1 << 5) +#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL (1 << 6) +#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_PRIVATE (1 << 7) +#define NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON (1 << 10) +#define NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD (1 << 11) + +#define NM_NETWORKMANAGER_COMPILATION_LIBNM_CORE \ + (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB \ + | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_PRIVATE \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL) + +#define NM_NETWORKMANAGER_COMPILATION_LIBNM \ + (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB \ + | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL) + +#define NM_NETWORKMANAGER_COMPILATION_CLIENT \ + (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB \ + | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE) + +#define NM_NETWORKMANAGER_COMPILATION_DAEMON \ + (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB \ + | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL \ + | NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON) + +#define NM_NETWORKMANAGER_COMPILATION_SYSTEMD_SHARED \ + (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB | NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD) + +#define NM_NETWORKMANAGER_COMPILATION_SYSTEMD \ + (0 | NM_NETWORKMANAGER_COMPILATION_DAEMON | NM_NETWORKMANAGER_COMPILATION_SYSTEMD_SHARED) + +#define NM_NETWORKMANAGER_COMPILATION_GLIB (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB) + +#endif /* __NM_NETWORKMANAGER_COMPILATION_H__ */ diff --git a/src/libnm-std-aux/nm-std-aux.h b/src/libnm-std-aux/nm-std-aux.h new file mode 100644 index 00000000..17b26881 --- /dev/null +++ b/src/libnm-std-aux/nm-std-aux.h @@ -0,0 +1,978 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#ifndef __NM_STD_AUX_H__ +#define __NM_STD_AUX_H__ + +#include +#include +#include +#include +#include +#include +#include + +/*****************************************************************************/ + +#define _nm_packed __attribute__((__packed__)) +#define _nm_unused __attribute__((__unused__)) +#define _nm_used __attribute__((__used__)) +#define _nm_pure __attribute__((__pure__)) +#define _nm_const __attribute__((__const__)) +#define _nm_printf(a, b) __attribute__((__format__(__printf__, a, b))) +#define _nm_align(s) __attribute__((__aligned__(s))) +#define _nm_section(s) __attribute__((__section__(s))) +#define _nm_alignof(type) __alignof(type) +#define _nm_alignas(type) _nm_align(_nm_alignof(type)) +#define nm_auto(fcn) __attribute__((__cleanup__(fcn))) + +/* This is required to make LTO working. + * + * See https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/76#note_112694 + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48200#c28 + */ +#ifndef __clang__ + #define _nm_externally_visible __attribute__((__externally_visible__)) +#else + #define _nm_externally_visible +#endif + +#if __GNUC__ >= 7 + #define _nm_fallthrough __attribute__((__fallthrough__)) +#else + #define _nm_fallthrough +#endif + +/*****************************************************************************/ + +#ifdef __CHECKER__ + #define _nm_bitwise __attribute__((__bitwise__)) + #define _nm_force __attribute__((__force__)) +#else + #define _nm_bitwise + #define _nm_force +#endif + +typedef uint16_t _nm_bitwise nm_le16_t; +typedef uint16_t _nm_bitwise nm_be16_t; +typedef uint32_t _nm_bitwise nm_le32_t; +typedef uint32_t _nm_bitwise nm_be32_t; +typedef uint64_t _nm_bitwise nm_le64_t; +typedef uint64_t _nm_bitwise nm_be64_t; + +/*****************************************************************************/ + +#ifdef thread_local + #define _nm_thread_local thread_local +/* + * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__ + * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 + */ +#elif __STDC_VERSION__ >= 201112L \ + && !(defined(__STDC_NO_THREADS__) \ + || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16)) + #define _nm_thread_local _Thread_local +#else + #define _nm_thread_local __thread +#endif + +/*****************************************************************************/ + +#define _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON struct _nm_dummy_struct_for_trailing_semicolon + +/*****************************************************************************/ + +#define NM_PASTE_ARGS(identifier1, identifier2) identifier1##identifier2 +#define NM_PASTE(identifier1, identifier2) NM_PASTE_ARGS(identifier1, identifier2) + +/* Taken from systemd's UNIQ_T and UNIQ macros. */ + +#define NM_UNIQ_T(x, uniq) NM_PASTE(__unique_prefix_, NM_PASTE(x, uniq)) +#define NM_UNIQ __COUNTER__ + +/*****************************************************************************/ + +#define _NM_BOOLEAN_EXPR_IMPL(v, expr) \ + ({ \ + int NM_UNIQ_T(V, v); \ + \ + if (expr) \ + NM_UNIQ_T(V, v) = 1; \ + else \ + NM_UNIQ_T(V, v) = 0; \ + NM_UNIQ_T(V, v); \ + }) +#define NM_BOOLEAN_EXPR(expr) _NM_BOOLEAN_EXPR_IMPL(NM_UNIQ, expr) + +#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) + #define NM_LIKELY(expr) (__builtin_expect(NM_BOOLEAN_EXPR(expr), 1)) + #define NM_UNLIKELY(expr) (__builtin_expect(NM_BOOLEAN_EXPR(expr), 0)) +#else + #define NM_LIKELY(expr) NM_BOOLEAN_EXPR(expr) + #define NM_UNLIKELY(expr) NM_BOOLEAN_EXPR(expr) +#endif + +/*****************************************************************************/ + +/* glib/C provides the following kind of assertions: + * - assert() -- disable with NDEBUG + * - g_return_if_fail() -- disable with G_DISABLE_CHECKS + * - g_assert() -- disable with G_DISABLE_ASSERT + * but they are all enabled by default and usually even production builds have + * these kind of assertions enabled. It also means, that disabling assertions + * is an untested configuration, and might have bugs. + * + * Add our own assertion macro nm_assert(), which is disabled by default and must + * be explicitly enabled. They are useful for more expensive checks or checks that + * depend less on runtime conditions (that is, are generally expected to be true). */ + +#ifndef NM_MORE_ASSERTS + #define NM_MORE_ASSERTS 0 +#endif + +#ifndef _nm_assert_call + #define _nm_assert_call(cond) assert(cond) + #define _nm_assert_call_not_reached() assert(0) +#endif + +#if NM_MORE_ASSERTS + #define nm_assert(cond) \ + do { \ + _nm_assert_call(cond); \ + } while (0) + #define nm_assert_se(cond) \ + do { \ + if (NM_LIKELY(cond)) { \ + ; \ + } else { \ + _nm_assert_call(0 && (cond)); \ + } \ + } while (0) + #define nm_assert_not_reached() \ + do { \ + _nm_assert_call_not_reached(); \ + } while (0) +#else + #define nm_assert(cond) \ + do { \ + if (0) { \ + if (cond) {} \ + } \ + } while (0) + #define nm_assert_se(cond) \ + do { \ + if (NM_LIKELY(cond)) { \ + ; \ + } \ + } while (0) + #define nm_assert_not_reached() \ + do { \ + ; \ + } while (0) +#endif + +#define nm_assert_unreachable_val(val) \ + ({ \ + nm_assert_not_reached(); \ + (val); \ + }) + +#define NM_STATIC_ASSERT(cond) static_assert(cond, "") +#define NM_STATIC_ASSERT_EXPR(cond) \ + ({ \ + NM_STATIC_ASSERT(cond); \ + 1; \ + }) + +/*****************************************************************************/ + +#define NM_N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0])) + +/*****************************************************************************/ + +static inline uint32_t +nm_add_clamped_u32(uint32_t a, uint32_t b) +{ + uint32_t c; + + /* returns a+b, or UINT32_MAX if the result would overflow. */ + + c = a + b; + if (c < a) + return UINT32_MAX; + return c; +} + +static inline unsigned +nm_mult_clamped_u(unsigned a, unsigned b) +{ + unsigned c; + + /* returns a*b, or UINT_MAX if the result would overflow. */ + + if (b == 0) + return 0; + + c = a * b; + + if (c / b != a) + return (unsigned) -1; + + return c; +} + +/* glib's MIN()/MAX() macros don't have function-like behavior, in that they evaluate + * the argument possibly twice. + * + * Taken from systemd's MIN()/MAX() macros. */ + +#define NM_MIN(a, b) __NM_MIN(NM_UNIQ, a, NM_UNIQ, b) +#define __NM_MIN(aq, a, bq, b) \ + ({ \ + typeof(a) NM_UNIQ_T(A, aq) = (a); \ + typeof(b) NM_UNIQ_T(B, bq) = (b); \ + ((NM_UNIQ_T(A, aq) < NM_UNIQ_T(B, bq)) ? NM_UNIQ_T(A, aq) : NM_UNIQ_T(B, bq)); \ + }) + +#define NM_MAX(a, b) __NM_MAX(NM_UNIQ, a, NM_UNIQ, b) +#define __NM_MAX(aq, a, bq, b) \ + ({ \ + typeof(a) NM_UNIQ_T(A, aq) = (a); \ + typeof(b) NM_UNIQ_T(B, bq) = (b); \ + ((NM_UNIQ_T(A, aq) > NM_UNIQ_T(B, bq)) ? NM_UNIQ_T(A, aq) : NM_UNIQ_T(B, bq)); \ + }) + +#define NM_CLAMP(x, low, high) __NM_CLAMP(NM_UNIQ, x, NM_UNIQ, low, NM_UNIQ, high) +#define __NM_CLAMP(xq, x, lowq, low, highq, high) \ + ({ \ + typeof(x) NM_UNIQ_T(X, xq) = (x); \ + typeof(low) NM_UNIQ_T(LOW, lowq) = (low); \ + typeof(high) NM_UNIQ_T(HIGH, highq) = (high); \ + \ + ((NM_UNIQ_T(X, xq) > NM_UNIQ_T(HIGH, highq)) ? NM_UNIQ_T(HIGH, highq) \ + : (NM_UNIQ_T(X, xq) < NM_UNIQ_T(LOW, lowq)) ? NM_UNIQ_T(LOW, lowq) \ + : NM_UNIQ_T(X, xq)); \ + }) + +#define NM_MAX_WITH_CMP(cmp, a, b) \ + ({ \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + \ + (((cmp(_a, _b)) >= 0) ? _a : _b); \ + }) + +/* evaluates to (void) if _A or _B are not constant or of different types */ +#define NM_CONST_MAX(_A, _B) \ + (__builtin_choose_expr((__builtin_constant_p(_A) && __builtin_constant_p(_B) \ + && __builtin_types_compatible_p(typeof(_A), typeof(_B))), \ + ((_A) > (_B)) ? (_A) : (_B), \ + ((void) 0))) + +/* Determine whether @x is a power of two (@x being an integer type). + * Basically, this returns TRUE, if @x has exactly one bit set. + * For negative values and zero, this always returns FALSE. */ +#define nm_utils_is_power_of_two(x) \ + ({ \ + typeof(x) _x2 = (x); \ + const typeof(_x2) _X_0 = ((typeof(_x2)) 0); \ + const typeof(_x2) _X_1 = ((typeof(_x2)) 1); \ + \ + ((_x2 > _X_0) && ((_x2 & (_x2 - _X_1)) == _X_0)); \ + }) + +#define nm_utils_is_power_of_two_or_zero(x) \ + ({ \ + typeof(x) _x1 = (x); \ + \ + ((_x1 == 0) || nm_utils_is_power_of_two(_x1)); \ + }) + +/*****************************************************************************/ + +#define NM_SWAP(p_a, p_b) \ + do { \ + typeof(*(p_a)) *const _p_a = (p_a); \ + typeof(*(p_a)) *const _p_b = (p_b); \ + typeof(*(p_a)) _tmp; \ + \ + _tmp = *_p_a; \ + *_p_a = *_p_b; \ + *_p_b = _tmp; \ + } while (0) + +/*****************************************************************************/ + +/* macro to return strlen() of a compile time string. */ +#define NM_STRLEN(str) (sizeof("" str "") - 1u) + +/* returns the length of a NULL terminated array of pointers, + * like g_strv_length() does. The difference is: + * - it operates on arrays of pointers (of any kind, requiring no cast). + * - it accepts NULL to return zero. */ +#define NM_PTRARRAY_LEN(array) \ + ({ \ + typeof(*(array)) *const _array = (array); \ + size_t _n = 0; \ + \ + if (_array) { \ + _nm_unused const void *_type_check_is_pointer = _array[0]; \ + \ + while (_array[_n]) \ + _n++; \ + } \ + _n; \ + }) + +/*****************************************************************************/ + +static inline int +nm_strcmp0(const char *s1, const char *s2) +{ + int c; + + /* like g_strcmp0(), but this is inlinable. + * + * Also, it is guaranteed to return either -1, 0, or 1. */ + if (s1 == s2) + return 0; + if (!s1) + return -1; + if (!s2) + return 1; + c = strcmp(s1, s2); + if (c < 0) + return -1; + if (c > 0) + return 1; + return 0; +} + +static inline int +nm_streq(const char *s1, const char *s2) +{ + return strcmp(s1, s2) == 0; +} + +static inline int +nm_streq0(const char *s1, const char *s2) +{ + return (s1 == s2) || (s1 && s2 && strcmp(s1, s2) == 0); +} + +#define NM_STR_HAS_PREFIX(str, prefix) \ + ({ \ + const char *const _str_has_prefix = (str); \ + \ + nm_assert(strlen(prefix) == NM_STRLEN(prefix)); \ + \ + _str_has_prefix && (strncmp(_str_has_prefix, "" prefix "", NM_STRLEN(prefix)) == 0); \ + }) + +#define NM_STR_HAS_SUFFIX(str, suffix) \ + ({ \ + const char *const _str_has_suffix = (str); \ + size_t _l; \ + \ + nm_assert(strlen(suffix) == NM_STRLEN(suffix)); \ + \ + (_str_has_suffix && ((_l = strlen(_str_has_suffix)) >= NM_STRLEN(suffix)) \ + && (memcmp(&_str_has_suffix[_l - NM_STRLEN(suffix)], "" suffix "", NM_STRLEN(suffix)) \ + == 0)); \ + }) + +/* whether @str starts with the string literal @prefix and is followed by + * some other text. It is like NM_STR_HAS_PREFIX() && !nm_streq() together. */ +#define NM_STR_HAS_PREFIX_WITH_MORE(str, prefix) \ + ({ \ + const char *const _str_has_prefix_with_more = (str); \ + \ + NM_STR_HAS_PREFIX(_str_has_prefix_with_more, "" prefix "") \ + &&_str_has_prefix_with_more[NM_STRLEN(prefix)] != '\0'; \ + }) + +#define NM_STR_HAS_SUFFIX_WITH_MORE(str, suffix) \ + ({ \ + const char *const _str_has_suffix = (str); \ + size_t _l; \ + \ + nm_assert(strlen(suffix) == NM_STRLEN(suffix)); \ + \ + (_str_has_suffix && ((_l = strlen(_str_has_suffix)) > NM_STRLEN(suffix)) \ + && (memcmp(&_str_has_suffix[_l - NM_STRLEN(suffix)], "" suffix "", NM_STRLEN(suffix)) \ + == 0)); \ + }) + +/*****************************************************************************/ + +#define _NM_IN_SET_EVAL_1(op, _x, y) (_x == (y)) +#define _NM_IN_SET_EVAL_2(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_1(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_3(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_2(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_4(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_3(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_5(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_4(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_6(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_5(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_7(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_6(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_8(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_7(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_9(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_8(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_10(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_9(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_11(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_10(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_12(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_11(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_13(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_12(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_14(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_13(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_15(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_14(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_16(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_15(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_17(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_16(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_18(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_17(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_19(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_18(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_20(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_19(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_21(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_20(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_22(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_21(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_23(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_22(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_24(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_23(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_25(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_24(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_26(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_25(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_27(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_26(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_28(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_27(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_29(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_28(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_30(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_29(op, _x, __VA_ARGS__) + +#define _NM_IN_SET_EVAL_N2(op, _x, n, ...) (_NM_IN_SET_EVAL_##n(op, _x, __VA_ARGS__)) +#define _NM_IN_SET_EVAL_N(op, type, x, n, ...) \ + ({ \ + type _x = (x); \ + \ + /* trigger a -Wenum-compare warning */ \ + nm_assert(true || _x == (x)); \ + \ + !!_NM_IN_SET_EVAL_N2(op, _x, n, __VA_ARGS__); \ + }) + +#define _NM_IN_SET(op, type, x, ...) \ + _NM_IN_SET_EVAL_N(op, type, x, NM_NARG(__VA_ARGS__), __VA_ARGS__) + +/* Beware that this does short-circuit evaluation (use "||" instead of "|") + * which has a possibly unexpected non-function-like behavior. + * Use NM_IN_SET_SE if you need all arguments to be evaluated. */ +#define NM_IN_SET(x, ...) _NM_IN_SET(||, typeof(x), x, __VA_ARGS__) + +/* "SE" stands for "side-effect". Contrary to NM_IN_SET(), this does not do + * short-circuit evaluation, which can make a difference if the arguments have + * side-effects. */ +#define NM_IN_SET_SE(x, ...) _NM_IN_SET(|, typeof(x), x, __VA_ARGS__) + +/* the *_TYPED forms allow to explicitly select the type of "x". This is useful + * if "x" doesn't support typeof (bitfields) or you want to gracefully convert + * a type using automatic type conversion rules (but not forcing the conversion + * with a cast). */ +#define NM_IN_SET_TYPED(type, x, ...) _NM_IN_SET(||, type, x, __VA_ARGS__) +#define NM_IN_SET_SE_TYPED(type, x, ...) _NM_IN_SET(|, type, x, __VA_ARGS__) + +/*****************************************************************************/ + +#define _NM_IN_SETOP_EVAL_1(op, op_eq, _x, y) (op_eq(_x, y)) +#define _NM_IN_SETOP_EVAL_2(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_1(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_3(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_2(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_4(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_3(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_5(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_4(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_6(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_5(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_7(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_6(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_8(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_7(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_9(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_8(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_10(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_9(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_11(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_10(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_12(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_11(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_13(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_12(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_14(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_13(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_15(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_14(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_16(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_15(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_17(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_16(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_18(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_17(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_19(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_18(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_20(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_19(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_21(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_20(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_22(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_21(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_23(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_22(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_24(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_23(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_25(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_24(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_26(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_25(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_27(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_26(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_28(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_27(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_29(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_28(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_30(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_29(op, op_eq, _x, __VA_ARGS__) + +/*****************************************************************************/ + +#define _NM_IN_STRSET_EVAL_N2(op, op_ed, _x, n, ...) \ + (_NM_IN_SETOP_EVAL_##n(op, op_ed, _x, __VA_ARGS__)) +#define _NM_IN_STRSET_EVAL_N(op, op_ed, x, n, ...) \ + ({ \ + const char *_x = (x); \ + (((_x == NULL) && _NM_IN_SET_EVAL_N2(op, ((const char *) NULL), n, __VA_ARGS__)) \ + || ((_x != NULL) && _NM_IN_STRSET_EVAL_N2(op, op_ed, _x, n, __VA_ARGS__))); \ + }) + +/*****************************************************************************/ + +static inline int +_NM_IN_STRSET_op_streq(const char *x, const char *s) +{ + return s && strcmp(x, s) == 0; +} + +/* Beware that this does short-circuit evaluation (use "||" instead of "|") + * which has a possibly unexpected non-function-like behavior. + * Use NM_IN_STRSET_SE if you need all arguments to be evaluated. */ +#define NM_IN_STRSET(x, ...) \ + _NM_IN_STRSET_EVAL_N(||, _NM_IN_STRSET_op_streq, x, NM_NARG(__VA_ARGS__), __VA_ARGS__) + +/* "SE" stands for "side-effect". Contrary to NM_IN_STRSET(), this does not do + * short-circuit evaluation, which can make a difference if the arguments have + * side-effects. */ +#define NM_IN_STRSET_SE(x, ...) \ + _NM_IN_STRSET_EVAL_N(|, _NM_IN_STRSET_op_streq, x, NM_NARG(__VA_ARGS__), __VA_ARGS__) + +/*****************************************************************************/ + +#define NM_STRCHAR_ALL(str, ch_iter, predicate) \ + ({ \ + int _val = true; \ + const char *_str = (str); \ + \ + if (_str) { \ + for (;;) { \ + const char ch_iter = _str[0]; \ + \ + if (ch_iter != '\0') { \ + if (predicate) { \ + _str++; \ + continue; \ + } \ + _val = false; \ + } \ + break; \ + } \ + } \ + _val; \ + }) + +#define NM_STRCHAR_ANY(str, ch_iter, predicate) \ + ({ \ + int _val = false; \ + const char *_str = (str); \ + \ + if (_str) { \ + for (;;) { \ + const char ch_iter = _str[0]; \ + \ + if (ch_iter != '\0') { \ + if (predicate) { \ + ; \ + } else { \ + _str++; \ + continue; \ + } \ + _val = true; \ + } \ + break; \ + } \ + } \ + _val; \ + }) + +/*****************************************************************************/ + +/** + * nm_close: + * + * Like close() but throws an assertion if the input fd is + * invalid. Closing an invalid fd is a programming error, so + * it's better to catch it early. + */ +static inline int +nm_close(int fd) +{ + int r; + + r = close(fd); + nm_assert(r != -1 || fd < 0 || errno != EBADF); + return r; +} + +/*****************************************************************************/ + +/* Note: @value is only evaluated when *out_val is present. + * Thus, + * NM_SET_OUT (out_str, g_strdup ("hallo")); + * does the right thing. + */ +#define NM_SET_OUT(out_val, value) \ + ({ \ + typeof(*(out_val)) *_out_val = (out_val); \ + \ + if (_out_val) { \ + *_out_val = (value); \ + } \ + \ + (!!_out_val); \ + }) + +/*****************************************************************************/ + +#define NM_AUTO_DEFINE_FCN_VOID(CastType, name, func) \ + static inline void name(void *v) \ + { \ + func(*((CastType *) v)); \ + } \ + _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON + +#define NM_AUTO_DEFINE_FCN_VOID0(CastType, name, func) \ + static inline void name(void *v) \ + { \ + if (*((CastType *) v)) \ + func(*((CastType *) v)); \ + } \ + _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON + +#define NM_AUTO_DEFINE_FCN(Type, name, func) \ + static inline void name(Type *v) \ + { \ + func(*v); \ + } \ + _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON + +#define NM_AUTO_DEFINE_FCN0(Type, name, func) \ + static inline void name(Type *v) \ + { \ + if (*v) \ + func(*v); \ + } \ + _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON + +/*****************************************************************************/ + +/** + * nm_auto_free: + * + * Call free() on a variable location when it goes out of scope. + * This is for pointers that are allocated with malloc() instead of + * g_malloc(). + * + * In practice, since glib 2.45, g_malloc()/g_free() always wraps malloc()/free(). + * See bgo#751592. In that case, it would be safe to free pointers allocated with + * malloc() with gs_free or g_free(). + * + * However, let's never mix them. To free malloc'ed memory, always use + * free() or nm_auto_free. + */ +NM_AUTO_DEFINE_FCN_VOID0(void *, _nm_auto_free_impl, free); +#define nm_auto_free nm_auto(_nm_auto_free_impl) + +static inline void +_nm_auto_protect_errno(const int *p_saved_errno) +{ + errno = *p_saved_errno; +} +#define NM_AUTO_PROTECT_ERRNO(errsv_saved) \ + nm_auto(_nm_auto_protect_errno) _nm_unused const int errsv_saved = (errno) + +/*****************************************************************************/ + +static inline void +_nm_auto_close(int *pfd) +{ + if (*pfd >= 0) { + NM_AUTO_PROTECT_ERRNO(errsv); + (void) nm_close(*pfd); + } +} +#define nm_auto_close nm_auto(_nm_auto_close) + +static inline void +_nm_auto_fclose(FILE **pfd) +{ + if (*pfd) { + NM_AUTO_PROTECT_ERRNO(errsv); + (void) fclose(*pfd); + } +} +#define nm_auto_fclose nm_auto(_nm_auto_fclose) + +/*****************************************************************************/ + +#define nm_clear_pointer(pp, destroy) \ + ({ \ + typeof(*(pp)) *_pp = (pp); \ + typeof(*_pp) _p; \ + int _changed = false; \ + \ + if (_pp && (_p = *_pp)) { \ + _nm_unused const void *_p_check_is_pointer = _p; \ + \ + *_pp = NULL; \ + \ + /* g_clear_pointer() assigns @destroy first to a local variable, so that + * you can call "g_clear_pointer (pp, (GDestroyNotify) destroy);" without + * gcc emitting a warning. We don't do that, hence, you cannot cast + * "destroy" first. + * + * On the upside: you are not supposed to cast fcn, because the pointer + * types are preserved. If you really need a cast, you should cast @pp. + * But that is hardly ever necessary. */ \ + (destroy)(_p); \ + \ + _changed = true; \ + } \ + _changed; \ + }) + +#define nm_clear_free(pp) nm_clear_pointer(pp, free) + +/*****************************************************************************/ + +#define nm_steal_pointer(pp) \ + ({ \ + typeof(*(pp)) *const _pp = (pp); \ + typeof(*_pp) _p = *_pp; \ + _nm_unused const void *const _p_type_check = _p; \ + \ + *_pp = NULL; \ + _p; \ + }) + +/** + * nm_steal_int: + * @p_val: pointer to an int type. + * + * Returns: *p_val and sets *p_val to zero the same time. + * Accepts %NULL, in which case also numeric 0 will be returned. + */ +#define nm_steal_int(p_val) \ + ({ \ + typeof(p_val) const _p_val = (p_val); \ + typeof(*_p_val) _val = 0; \ + \ + if (_p_val && (_val = *_p_val)) { \ + *_p_val = 0; \ + } \ + _val; \ + }) + +static inline int +nm_steal_fd(int *p_fd) +{ + int fd; + + if (p_fd && ((fd = *p_fd) >= 0)) { + *p_fd = -1; + return fd; + } + return -1; +} + +/*****************************************************************************/ + +static inline uintptr_t +nm_ptr_to_uintptr(const void *p) +{ + /* in C, pointers can only be compared (with less-than or greater-than) under certain + * circumstances. Since uintptr_t is supposed to be able to represent the pointer + * as a plain integer and also support to convert the integer back to the pointer, + * it should be safer to compare the pointers directly. + * + * Of course, this function isn't very useful beyond that its use makes it clear + * that we want to compare pointers by value, which otherwise may not be valid. */ + return (uintptr_t) p; +} + +/*****************************************************************************/ + +#define NM_CMP_RETURN(c) \ + do { \ + const int _cc = (c); \ + if (_cc) \ + return _cc < 0 ? -1 : 1; \ + } while (0) + +#define NM_CMP_RETURN_DIRECT(c) \ + do { \ + const int _cc = (c); \ + if (_cc) \ + return _cc; \ + } while (0) + +#define NM_CMP_SELF(a, b) \ + do { \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + \ + if (_a == _b) \ + return 0; \ + if (!_a) \ + return -1; \ + if (!_b) \ + return 1; \ + } while (0) + +#define NM_CMP_DIRECT(a, b) \ + do { \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + \ + if (_a != _b) \ + return (_a < _b) ? -1 : 1; \ + } while (0) + +#define NM_CMP_DIRECT_UNSAFE(a, b) \ + do { \ + if ((a) != (b)) \ + return ((a) < (b)) ? -1 : 1; \ + } while (0) + +/* In the general case, direct pointer comparison is undefined behavior in C. + * Avoid that by casting pointers to void* and then to uintptr_t. This comparison + * is not really meaningful, except that it provides some kind of stable sort order + * between pointers (that can otherwise not be compared). */ +#define NM_CMP_DIRECT_PTR(a, b) NM_CMP_DIRECT(nm_ptr_to_uintptr(a), nm_ptr_to_uintptr(b)) + +#define NM_CMP_DIRECT_MEMCMP(a, b, size) NM_CMP_RETURN(memcmp((a), (b), (size))) + +#define NM_CMP_DIRECT_STRCMP(a, b) NM_CMP_RETURN_DIRECT(strcmp((a), (b))) + +#define NM_CMP_DIRECT_STRCMP0(a, b) NM_CMP_RETURN_DIRECT(nm_strcmp0((a), (b))) + +#define NM_CMP_DIRECT_IN6ADDR(a, b) \ + do { \ + const struct in6_addr *const _a = (a); \ + const struct in6_addr *const _b = (b); \ + NM_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \ + } while (0) + +#define NM_CMP_FIELD(a, b, field) NM_CMP_DIRECT(((a)->field), ((b)->field)) + +#define NM_CMP_FIELD_UNSAFE(a, b, field) \ + do { \ + /* it's unsafe, because it evaluates the arguments more then once. + * This is necessary for bitfields, for which typeof() doesn't work. */ \ + if (((a)->field) != ((b)->field)) \ + return ((a)->field < ((b)->field)) ? -1 : 1; \ + } while (0) + +#define NM_CMP_FIELD_BOOL(a, b, field) NM_CMP_DIRECT(!!((a)->field), !!((b)->field)) + +#define NM_CMP_FIELD_STR(a, b, field) NM_CMP_RETURN(strcmp(((a)->field), ((b)->field))) + +#define NM_CMP_FIELD_STR_INTERNED(a, b, field) \ + do { \ + const char *_a = ((a)->field); \ + const char *_b = ((b)->field); \ + \ + if (_a != _b) { \ + NM_CMP_RETURN_DIRECT(nm_strcmp0(_a, _b)); \ + } \ + } while (0) + +#define NM_CMP_FIELD_STR0(a, b, field) NM_CMP_RETURN_DIRECT(nm_strcmp0(((a)->field), ((b)->field))) + +#define NM_CMP_FIELD_MEMCMP_LEN(a, b, field, len) \ + NM_CMP_RETURN(memcmp(&((a)->field), &((b)->field), NM_MIN(len, sizeof((a)->field)))) + +#define NM_CMP_FIELD_MEMCMP(a, b, field) \ + NM_CMP_RETURN(memcmp(&((a)->field), &((b)->field), sizeof((a)->field))) + +#define NM_CMP_FIELD_IN6ADDR(a, b, field) \ + do { \ + const struct in6_addr *const _a = &((a)->field); \ + const struct in6_addr *const _b = &((b)->field); \ + NM_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \ + } while (0) + +/*****************************************************************************/ + +#define NM_AF_UNSPEC 0 /* AF_UNSPEC */ +#define NM_AF_INET 2 /* AF_INET */ +#define NM_AF_INET6 10 /* AF_INET6 */ + +#define NM_AF_INET_SIZE 4 /* sizeof (in_addr_t) */ +#define NM_AF_INET6_SIZE 16 /* sizeof (stuct in6_addr) */ + +static inline char +nm_utils_addr_family_to_char(int addr_family) +{ + switch (addr_family) { + case NM_AF_UNSPEC: + return 'X'; + case NM_AF_INET: + return '4'; + case NM_AF_INET6: + return '6'; + } + nm_assert_not_reached(); + return '?'; +} + +static inline size_t +nm_utils_addr_family_to_size(int addr_family) +{ + switch (addr_family) { + case NM_AF_INET: + return NM_AF_INET_SIZE; + case NM_AF_INET6: + return NM_AF_INET6_SIZE; + } + nm_assert_not_reached(); + return 0; +} + +static inline int +nm_utils_addr_family_from_size(size_t len) +{ + switch (len) { + case NM_AF_INET_SIZE: + return NM_AF_INET; + case NM_AF_INET6_SIZE: + return NM_AF_INET6; + } + return NM_AF_UNSPEC; +} + +#define nm_assert_addr_family(addr_family) \ + nm_assert(NM_IN_SET((addr_family), NM_AF_INET, NM_AF_INET6)) + +#define NM_IS_IPv4(addr_family) \ + ({ \ + const int _addr_family = (addr_family); \ + \ + nm_assert_addr_family(_addr_family); \ + \ + (_addr_family == NM_AF_INET); \ + }) + +#endif /* __NM_STD_AUX_H__ */ diff --git a/src/libnm-std-aux/nm-std-utils.c b/src/libnm-std-aux/nm-std-utils.c new file mode 100644 index 00000000..18692b19 --- /dev/null +++ b/src/libnm-std-aux/nm-std-utils.c @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "nm-default-std.h" + +#include "nm-std-utils.h" + +#include +#include +#include + +/*****************************************************************************/ + +size_t +nm_utils_get_next_realloc_size(bool true_realloc, size_t requested) +{ + size_t n, x; + + /* https://doc.qt.io/qt-5/containers.html#growth-strategies */ + + if (requested <= 40) { + /* small allocations. Increase in small steps of 8 bytes. + * + * We get thus sizes of 8, 16, 32, 40. */ + if (requested <= 8) + return 8; + if (requested <= 16) + return 16; + if (requested <= 32) + return 32; + + /* The return values for < 104 are essentially hard-coded, and the choice here is + * made without very strong reasons. + * + * We want to stay 24 bytes below the power-of-two border 64. Hence, return 40 here. + * However, the next step then is already 104 (128 - 24). It's a larger gap than in + * the steps before. + * + * It's not clear whether some of the steps should be adjusted (or how exactly). */ + return 40; + } + + if (requested <= 0x2000u - 24u || NM_UNLIKELY(!true_realloc)) { + /* mid sized allocations. Return next power of two, minus 24 bytes extra space + * at the beginning. + * That means, we double the size as we grow. + * + * With !true_realloc, it means that the caller does not intend to call + * realloc() but instead clone the buffer. This is for example the case, when we + * want to nm_explicit_bzero() the old buffer. In that case we really want to grow + * the buffer exponentially every time and not increment in page sizes of 4K (below). + * + * We get thus sizes of 104, 232, 488, 1000, 2024, 4072, 8168... */ + + if (NM_UNLIKELY(requested > SIZE_MAX / 2u - 24u)) + goto out_huge; + + x = requested + 24u; + n = 128u; + while (n < x) { + n <<= 1; + nm_assert(n > 128u); + } + + nm_assert(n > 24u && n - 24u >= requested); + return n - 24u; + } + + if (NM_UNLIKELY(requested > SIZE_MAX - 0x1000u - 24u)) { + /* overflow happened. */ + goto out_huge; + } + + /* For large allocations (with !true_realloc) we allocate memory in chunks of + * 4K (- 24 bytes extra), assuming that the memory gets mmapped and thus + * realloc() is efficient by just reordering pages. */ + n = ((requested + (0x0FFFu + 24u)) & ~((size_t) 0x0FFFu)) - 24u; + nm_assert(n >= requested); + return n; + +out_huge: + if (sizeof(size_t) > 4u) { + /* on s390x (64 bit), gcc with LTO can complain that the size argument to + * malloc must not be larger than 9223372036854775807. + * + * Work around that by returning SSIZE_MAX. It should be plenty still! */ + assert(requested <= (size_t) SSIZE_MAX); + return (size_t) SSIZE_MAX; + } + return SIZE_MAX; +} diff --git a/src/libnm-std-aux/nm-std-utils.h b/src/libnm-std-aux/nm-std-utils.h new file mode 100644 index 00000000..76d49d2f --- /dev/null +++ b/src/libnm-std-aux/nm-std-utils.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#ifndef __NM_STD_UTILS_H__ +#define __NM_STD_UTILS_H__ + +#include + +#include "nm-std-aux.h" + +/*****************************************************************************/ + +/* nm_utils_get_next_realloc_size() is used to grow buffers exponentially, when + * the final size is unknown. As such, it has borders for which it allocates + * certain buffer sizes. + * + * The use of these defines is to get favorable allocation sequences. + * For example, nm_str_buf_init() asks for an initial allocation size. Note that + * it reserves the exactly requested amount, under the assumption that the + * user may know how many bytes will be required. However, often the caller + * doesn't know in advance, and NMStrBuf grows exponentially by calling + * nm_utils_get_next_realloc_size(). + * Imagine you call nm_str_buf_init() with an initial buffer size 100, and you + * add one character at a time. Then the first reallocation will increase the + * buffer size only from 100 to 104. + * If you however start with an initial buffer size of 104, then the next reallocation + * via nm_utils_get_next_realloc_size() gives you 232, and so on. By using + * these sizes, it results in one less allocation, if you anyway don't know the + * exact size in advance. */ +#define NM_UTILS_GET_NEXT_REALLOC_SIZE_32 ((size_t) 32) +#define NM_UTILS_GET_NEXT_REALLOC_SIZE_40 ((size_t) 40) +#define NM_UTILS_GET_NEXT_REALLOC_SIZE_104 ((size_t) 104) +#define NM_UTILS_GET_NEXT_REALLOC_SIZE_232 ((size_t) 232) +#define NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 ((size_t) 1000) + +size_t nm_utils_get_next_realloc_size(bool true_realloc, size_t requested); + +#endif /* __NM_STD_UTILS_H__ */ diff --git a/src/libnm-std-aux/unaligned.h b/src/libnm-std-aux/unaligned.h new file mode 100644 index 00000000..4100be08 --- /dev/null +++ b/src/libnm-std-aux/unaligned.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include +#include + +/* BE */ + +static inline uint16_t unaligned_read_be16(const void *_u) { + const struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u; + + return be16toh(u->x); +} + +static inline uint32_t unaligned_read_be32(const void *_u) { + const struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u; + + return be32toh(u->x); +} + +static inline uint64_t unaligned_read_be64(const void *_u) { + const struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u; + + return be64toh(u->x); +} + +static inline void unaligned_write_be16(void *_u, uint16_t a) { + struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u; + + u->x = be16toh(a); +} + +static inline void unaligned_write_be32(void *_u, uint32_t a) { + struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u; + + u->x = be32toh(a); +} + +static inline void unaligned_write_be64(void *_u, uint64_t a) { + struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u; + + u->x = be64toh(a); +} + +/* LE */ + +static inline uint16_t unaligned_read_le16(const void *_u) { + const struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u; + + return le16toh(u->x); +} + +static inline uint32_t unaligned_read_le32(const void *_u) { + const struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u; + + return le32toh(u->x); +} + +static inline uint64_t unaligned_read_le64(const void *_u) { + const struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u; + + return le64toh(u->x); +} + +static inline void unaligned_write_le16(void *_u, uint16_t a) { + struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u; + + u->x = le16toh(a); +} + +static inline void unaligned_write_le32(void *_u, uint32_t a) { + struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u; + + u->x = le32toh(a); +} + +static inline void unaligned_write_le64(void *_u, uint64_t a) { + struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u; + + u->x = le64toh(a); +} + +#if __BYTE_ORDER == __BIG_ENDIAN +#define unaligned_read_ne16 unaligned_read_be16 +#define unaligned_read_ne32 unaligned_read_be32 +#define unaligned_read_ne64 unaligned_read_be64 + +#define unaligned_write_ne16 unaligned_write_be16 +#define unaligned_write_ne32 unaligned_write_be32 +#define unaligned_write_ne64 unaligned_write_be64 +#else +#define unaligned_read_ne16 unaligned_read_le16 +#define unaligned_read_ne32 unaligned_read_le32 +#define unaligned_read_ne64 unaligned_read_le64 + +#define unaligned_write_ne16 unaligned_write_le16 +#define unaligned_write_ne32 unaligned_write_le32 +#define unaligned_write_ne64 unaligned_write_le64 +#endif -- cgit 1.3.0-6-gf8a5 From 88c227d90a6b7b388c5c85d72802a0ca8f05ed5c Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Thu, 13 Jan 2022 22:30:39 +0100 Subject: New upstream version 1.34.0 --- src/libnm-std-aux/nm-default-std.h | 18 +- src/libnm-std-aux/nm-linux-compat.h | 2 +- src/libnm-std-aux/nm-std-aux.h | 746 +++++++++++++++++++++++++----------- 3 files changed, 524 insertions(+), 242 deletions(-) (limited to 'src/libnm-std-aux') diff --git a/src/libnm-std-aux/nm-default-std.h b/src/libnm-std-aux/nm-default-std.h index 5f4af3a5..23f5fc60 100644 --- a/src/libnm-std-aux/nm-default-std.h +++ b/src/libnm-std-aux/nm-default-std.h @@ -9,11 +9,11 @@ #include "nm-networkmanager-compilation.h" #ifdef NETWORKMANAGER_COMPILATION - #error Dont define NETWORKMANAGER_COMPILATION +#error Dont define NETWORKMANAGER_COMPILATION #endif #ifndef G_LOG_DOMAIN - #define G_LOG_DOMAIN "nm" +#define G_LOG_DOMAIN "nm" #endif /*****************************************************************************/ @@ -25,8 +25,8 @@ /* always include these headers for our internal source files. */ #ifndef ___CONFIG_H__ - #define ___CONFIG_H__ - #include +#define ___CONFIG_H__ +#include #endif #include "config-extra.h" @@ -37,11 +37,11 @@ #define NM_VERSION_MIN_REQUIRED NM_VERSION_0_9_8 #ifndef NM_MORE_ASSERTS - #define NM_MORE_ASSERTS 0 +#define NM_MORE_ASSERTS 0 #endif #if NM_MORE_ASSERTS == 0 - /* The cast macros like NM_TYPE() are implemented via G_TYPE_CHECK_INSTANCE_CAST() +/* The cast macros like NM_TYPE() are implemented via G_TYPE_CHECK_INSTANCE_CAST() * and _G_TYPE_CIC(). The latter, by default performs runtime checks of the type * by calling g_type_check_instance_cast(). * This check has a certain overhead without being helpful. @@ -88,9 +88,9 @@ * Example 3 is how it should be done. Type checks in NM_TYPE() are pointless. * Disable them for our production builds. */ - #ifndef G_DISABLE_CAST_CHECKS - #define G_DISABLE_CAST_CHECKS - #endif +#ifndef G_DISABLE_CAST_CHECKS +#define G_DISABLE_CAST_CHECKS +#endif #endif /*****************************************************************************/ diff --git a/src/libnm-std-aux/nm-linux-compat.h b/src/libnm-std-aux/nm-linux-compat.h index 7492d527..7ca7ec78 100644 --- a/src/libnm-std-aux/nm-linux-compat.h +++ b/src/libnm-std-aux/nm-linux-compat.h @@ -16,7 +16,7 @@ #include #ifndef __KERNEL_DIV_ROUND_UP - #define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) -1) / (d)) +#define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) -1) / (d)) #endif #include "linux-headers/ethtool.h" diff --git a/src/libnm-std-aux/nm-std-aux.h b/src/libnm-std-aux/nm-std-aux.h index 17b26881..b79b1c65 100644 --- a/src/libnm-std-aux/nm-std-aux.h +++ b/src/libnm-std-aux/nm-std-aux.h @@ -10,20 +10,49 @@ #include #include #include +#include /*****************************************************************************/ -#define _nm_packed __attribute__((__packed__)) -#define _nm_unused __attribute__((__unused__)) -#define _nm_used __attribute__((__used__)) -#define _nm_pure __attribute__((__pure__)) -#define _nm_const __attribute__((__const__)) -#define _nm_printf(a, b) __attribute__((__format__(__printf__, a, b))) -#define _nm_align(s) __attribute__((__aligned__(s))) -#define _nm_section(s) __attribute__((__section__(s))) -#define _nm_alignof(type) __alignof(type) -#define _nm_alignas(type) _nm_align(_nm_alignof(type)) -#define nm_auto(fcn) __attribute__((__cleanup__(fcn))) +#define _nm_packed __attribute__((__packed__)) +#define _nm_unused __attribute__((__unused__)) +#define _nm_used __attribute__((__used__)) +#define _nm_pure __attribute__((__pure__)) +#define _nm_const __attribute__((__const__)) +#define _nm_warn_unused_result __attribute__((__warn_unused_result__)) +#define _nm_printf(a, b) __attribute__((__format__(__printf__, a, b))) +#define _nm_align(s) __attribute__((__aligned__(s))) +#define _nm_section(s) __attribute__((__section__(s))) +#define _nm_alignof(type) __alignof(type) +#define _nm_alignas(type) _nm_align(_nm_alignof(type)) +#define _nm_deprecated(msg) __attribute__((__deprecated__(msg))) +#define _nm_retain + +#if defined(__clang__) && defined(__has_attribute) +#if __has_attribute(__retain__) +/* __attribute__((__retain__)) is supported in clang 13+, but is warned about + * as an unknown attribute in older versions. We assume older versions are used + * together with linkers that do not require the attribute. + * + * Ideally __has_attribute(__retain__) would be checked in other compilers as + * well, but it is broken in GCC (bug 99587). Limit it to clang for now, as it + * is only known to be needed for linking lld. */ +#undef _nm_retain +#define _nm_retain __attribute__((__retain__)) +#endif +#endif + +#if defined(__clang__) && __clang_major__ == 13 +/* Clang 13 can emit -Wunused-but-set-variable warning for cleanup variables + * that are only assigned (never used otherwise). Hack around */ +#define _nm_auto_extra _nm_unused +#else +#define _nm_auto_extra +#endif + +#define nm_auto(fcn) _nm_auto_extra __attribute__((__cleanup__(fcn))) + +#define _nm_nil /* This is required to make LTO working. * @@ -31,25 +60,55 @@ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48200#c28 */ #ifndef __clang__ - #define _nm_externally_visible __attribute__((__externally_visible__)) +#define _nm_externally_visible __attribute__((__externally_visible__)) #else - #define _nm_externally_visible +#define _nm_externally_visible #endif #if __GNUC__ >= 7 - #define _nm_fallthrough __attribute__((__fallthrough__)) +#define _nm_fallthrough __attribute__((__fallthrough__)) +#else +#define _nm_fallthrough +#endif + +/*****************************************************************************/ + +#ifndef _NM_CC_SUPPORT_AUTO_TYPE +#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9))) +#define _NM_CC_SUPPORT_AUTO_TYPE 1 +#else +#define _NM_CC_SUPPORT_AUTO_TYPE 0 +#endif +#endif + +#if _NM_CC_SUPPORT_AUTO_TYPE +#define _nm_auto_type __auto_type +#endif + +#ifndef _NM_CC_SUPPORT_GENERIC +/* In the meantime, NetworkManager requires C11 and _Generic() should always be available. + * However, shared/nm-utils may also be used in VPN/applet, which possibly did not yet + * bump the C standard requirement. Leave this for the moment, but eventually we can + * drop it. + * + * Technically, gcc 4.9 already has some support for _Generic(). But there seems + * to be issues with propagating "const char *[5]" to "const char **". Only assume + * we have _Generic() since gcc 5. */ +#if (defined(__GNUC__) && __GNUC__ >= 5) || (defined(__clang__)) +#define _NM_CC_SUPPORT_GENERIC 1 #else - #define _nm_fallthrough +#define _NM_CC_SUPPORT_GENERIC 0 +#endif #endif /*****************************************************************************/ #ifdef __CHECKER__ - #define _nm_bitwise __attribute__((__bitwise__)) - #define _nm_force __attribute__((__force__)) +#define _nm_bitwise __attribute__((__bitwise__)) +#define _nm_force __attribute__((__force__)) #else - #define _nm_bitwise - #define _nm_force +#define _nm_bitwise +#define _nm_force #endif typedef uint16_t _nm_bitwise nm_le16_t; @@ -62,7 +121,7 @@ typedef uint64_t _nm_bitwise nm_be64_t; /*****************************************************************************/ #ifdef thread_local - #define _nm_thread_local thread_local +#define _nm_thread_local thread_local /* * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__ * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 @@ -70,9 +129,9 @@ typedef uint64_t _nm_bitwise nm_be64_t; #elif __STDC_VERSION__ >= 201112L \ && !(defined(__STDC_NO_THREADS__) \ || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16)) - #define _nm_thread_local _Thread_local +#define _nm_thread_local _Thread_local #else - #define _nm_thread_local __thread +#define _nm_thread_local __thread #endif /*****************************************************************************/ @@ -81,6 +140,10 @@ typedef uint64_t _nm_bitwise nm_be64_t; /*****************************************************************************/ +#define NM_BIT(n) (1ull << (n)) + +/*****************************************************************************/ + #define NM_PASTE_ARGS(identifier1, identifier2) identifier1##identifier2 #define NM_PASTE(identifier1, identifier2) NM_PASTE_ARGS(identifier1, identifier2) @@ -104,11 +167,11 @@ typedef uint64_t _nm_bitwise nm_be64_t; #define NM_BOOLEAN_EXPR(expr) _NM_BOOLEAN_EXPR_IMPL(NM_UNIQ, expr) #if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) - #define NM_LIKELY(expr) (__builtin_expect(NM_BOOLEAN_EXPR(expr), 1)) - #define NM_UNLIKELY(expr) (__builtin_expect(NM_BOOLEAN_EXPR(expr), 0)) +#define NM_LIKELY(expr) (__builtin_expect(NM_BOOLEAN_EXPR(expr), 1)) +#define NM_UNLIKELY(expr) (__builtin_expect(NM_BOOLEAN_EXPR(expr), 0)) #else - #define NM_LIKELY(expr) NM_BOOLEAN_EXPR(expr) - #define NM_UNLIKELY(expr) NM_BOOLEAN_EXPR(expr) +#define NM_LIKELY(expr) NM_BOOLEAN_EXPR(expr) +#define NM_UNLIKELY(expr) NM_BOOLEAN_EXPR(expr) #endif /*****************************************************************************/ @@ -126,50 +189,59 @@ typedef uint64_t _nm_bitwise nm_be64_t; * depend less on runtime conditions (that is, are generally expected to be true). */ #ifndef NM_MORE_ASSERTS - #define NM_MORE_ASSERTS 0 +#define NM_MORE_ASSERTS 0 #endif #ifndef _nm_assert_call - #define _nm_assert_call(cond) assert(cond) - #define _nm_assert_call_not_reached() assert(0) +#define _nm_assert_call(cond) assert(cond) +#define _nm_assert_call_not_reached() assert(0) #endif #if NM_MORE_ASSERTS - #define nm_assert(cond) \ - do { \ - _nm_assert_call(cond); \ - } while (0) - #define nm_assert_se(cond) \ - do { \ - if (NM_LIKELY(cond)) { \ - ; \ - } else { \ - _nm_assert_call(0 && (cond)); \ - } \ - } while (0) - #define nm_assert_not_reached() \ - do { \ - _nm_assert_call_not_reached(); \ - } while (0) +#define nm_assert(cond) \ + ({ \ + _nm_assert_call(cond); \ + 1; \ + }) +#define nm_assert_se(cond) \ + ({ \ + if (NM_LIKELY(cond)) { \ + ; \ + } else { \ + _nm_assert_call(0 && (cond)); \ + } \ + 1; \ + }) +#define nm_assert_not_reached() \ + ({ \ + _nm_assert_call_not_reached(); \ + 1; \ + }) #else - #define nm_assert(cond) \ - do { \ - if (0) { \ - if (cond) {} \ - } \ - } while (0) - #define nm_assert_se(cond) \ - do { \ - if (NM_LIKELY(cond)) { \ - ; \ - } \ - } while (0) - #define nm_assert_not_reached() \ - do { \ - ; \ - } while (0) +#define nm_assert(cond) \ + ({ \ + if (0) { \ + if (cond) {} \ + } \ + 1; \ + }) +#define nm_assert_se(cond) \ + ({ \ + if (NM_LIKELY(cond)) { \ + ; \ + } \ + 1; \ + }) +#define nm_assert_not_reached() ({ 1; }) #endif +/* This is similar nm_assert_not_reached(), but it's supposed to be used only during + * development. Like _XXX_ comments, they can be used as a marker that something still + * needs to be done. */ +#define XXX(msg) \ + nm_assert(!"X" \ + "XX error: " msg "") + #define nm_assert_unreachable_val(val) \ ({ \ nm_assert_not_reached(); \ @@ -177,11 +249,10 @@ typedef uint64_t _nm_bitwise nm_be64_t; }) #define NM_STATIC_ASSERT(cond) static_assert(cond, "") -#define NM_STATIC_ASSERT_EXPR(cond) \ - ({ \ - NM_STATIC_ASSERT(cond); \ - 1; \ - }) +#define NM_STATIC_ASSERT_EXPR_1(cond) \ + (sizeof(struct { char __static_assert_expr_1[(cond) ? 1 : -1]; }) == 1) +#define NM_STATIC_ASSERT_EXPR_VOID(cond) \ + ((void) (sizeof(struct { char __static_assert_expr_void[(cond) ? 1 : -1]; }) == 1)) /*****************************************************************************/ @@ -189,6 +260,59 @@ typedef uint64_t _nm_bitwise nm_be64_t; /*****************************************************************************/ +#define nm_offsetof(t, m) offsetof(t, m) + +#define nm_offsetofend(t, m) (nm_offsetof(t, m) + sizeof(((t *) NULL)->m)) + +/*****************************************************************************/ + +/* This does a compile time check that "type" is a suitable C type. It either + * returns a compile time constant of 1 or it fails compilation. The point + * is only in macros to check that a macro parameter (what we might pass to + * sizeof() is really a type, and not a variable. */ +#define NM_ENSURE_IS_TYPE(type) (sizeof(void (*)(type[])) == sizeof(void (*)(void *))) + +/*****************************************************************************/ + +#if _NM_CC_SUPPORT_GENERIC +/* returns @value, if the type of @value matches @type. + * This requires support for C11 _Generic(). If no support is + * present, this returns @value directly. + * + * It's useful to check the let the compiler ensure that @value is + * of a certain type. */ +#define _NM_ENSURE_TYPE(type, value) (_Generic((value), type : (value))) +#define _NM_ENSURE_TYPE_CONST(type, value) \ + (_Generic((value), const type \ + : ((const type)(value)), const type const \ + : ((const type)(value)), type \ + : ((const type)(value)), type const \ + : ((const type)(value)))) +#else +#define _NM_ENSURE_TYPE(type, value) (value) +#define _NM_ENSURE_TYPE_CONST(type, value) ((const type)(value)) +#endif + +/* returns void, but does a compile time check that the argument is a pointer + * (that is, can be converted to (const void *)). It does not actually evaluate + * (value). That means, it's also safe to call _NM_ENSURE_POINTER(array[0]) if + * array might be NULL. It's also safe to call on a macro argument that is + * supposed to be evaluate at most once (this macro will not "execute" the + * argument). */ +#define _NM_ENSURE_POINTER(value) \ + do { \ + _nm_unused const void *const _unused_for_type_check = 0 ? (value) : NULL; \ + } while (0) + +#if _NM_CC_SUPPORT_GENERIC && (!defined(__clang__) || __clang_major__ > 3) +#define NM_STRUCT_OFFSET_ENSURE_TYPE(type, container, field) \ + (_Generic((&(((container *) NULL)->field))[0], type : nm_offsetof(container, field))) +#else +#define NM_STRUCT_OFFSET_ENSURE_TYPE(type, container, field) nm_offsetof(container, field) +#endif + +/*****************************************************************************/ + static inline uint32_t nm_add_clamped_u32(uint32_t a, uint32_t b) { @@ -305,22 +429,26 @@ nm_mult_clamped_u(unsigned a, unsigned b) /* macro to return strlen() of a compile time string. */ #define NM_STRLEN(str) (sizeof("" str "") - 1u) +static inline size_t +_nm_ptrarray_len_impl(const void *const *array) +{ + size_t n = 0; + + if (array) { + while (array[n]) + n++; + } + return n; +} + /* returns the length of a NULL terminated array of pointers, * like g_strv_length() does. The difference is: * - it operates on arrays of pointers (of any kind, requiring no cast). * - it accepts NULL to return zero. */ -#define NM_PTRARRAY_LEN(array) \ - ({ \ - typeof(*(array)) *const _array = (array); \ - size_t _n = 0; \ - \ - if (_array) { \ - _nm_unused const void *_type_check_is_pointer = _array[0]; \ - \ - while (_array[_n]) \ - _n++; \ - } \ - _n; \ +#define NM_PTRARRAY_LEN(array) \ + ({ \ + _NM_ENSURE_POINTER((array)[0]); \ + _nm_ptrarray_len_impl((const void *const *) (array)); \ }) /*****************************************************************************/ @@ -404,50 +532,230 @@ nm_streq0(const char *s1, const char *s2) /*****************************************************************************/ -#define _NM_IN_SET_EVAL_1(op, _x, y) (_x == (y)) -#define _NM_IN_SET_EVAL_2(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_1(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_3(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_2(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_4(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_3(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_5(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_4(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_6(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_5(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_7(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_6(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_8(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_7(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_9(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_8(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_10(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_9(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_11(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_10(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_12(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_11(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_13(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_12(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_14(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_13(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_15(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_14(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_16(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_15(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_17(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_16(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_18(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_17(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_19(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_18(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_20(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_19(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_21(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_20(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_22(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_21(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_23(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_22(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_24(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_23(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_25(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_24(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_26(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_25(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_27(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_26(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_28(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_27(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_29(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_28(op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_30(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_29(op, _x, __VA_ARGS__) - -#define _NM_IN_SET_EVAL_N2(op, _x, n, ...) (_NM_IN_SET_EVAL_##n(op, _x, __VA_ARGS__)) -#define _NM_IN_SET_EVAL_N(op, type, x, n, ...) \ - ({ \ - type _x = (x); \ - \ - /* trigger a -Wenum-compare warning */ \ - nm_assert(true || _x == (x)); \ - \ - !!_NM_IN_SET_EVAL_N2(op, _x, n, __VA_ARGS__); \ - }) +/* clang-format off */ +#define _NM_MACRO_SELECT_ARG_120(_empty, \ + _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ + _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ + _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ + _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ + _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \ + _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, \ + _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, \ + _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, \ + _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, \ + _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, \ + _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, \ + N, \ + ...) \ + N + +#define NM_NARG(...) \ + _NM_MACRO_SELECT_ARG_120(, ##__VA_ARGS__, \ + 120, \ + 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, \ + 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, \ + 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, \ + 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, \ + 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, \ + 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, \ + 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \ + 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \ + 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \ + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \ + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \ + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#define NM_NARG_MAX1(...) \ + _NM_MACRO_SELECT_ARG_120(, ##__VA_ARGS__, \ + 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 110 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 100 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 70 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) +#define NM_NARG_MAX2(...) \ + _NM_MACRO_SELECT_ARG_120(, ##__VA_ARGS__, \ + 2, \ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 110 */ \ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 100 */ \ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 90 */ \ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 80 */ \ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 70 */ \ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 60 */ \ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 50 */ \ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 40 */ \ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 30 */ \ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 20 */ \ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 10 */ \ + 2, 2, 2, 2, 2, 2, 2, 2, 1, 0) +/* clang-format on */ + +/*****************************************************************************/ + +#define _NM_MACRO_IDENTITY(...) __VA_ARGS__ + +#define _NM_MACRO_SELECT_FIRST(...) _NM_MACRO_SELECT_FIRST_IMPL(__VA_ARGS__, throwaway) +#define _NM_MACRO_SELECT_FIRST_IMPL(first, ...) first + +#define _NM_MACRO_CALL(macro, ...) macro(__VA_ARGS__) +#define _NM_MACRO_CALL2(macro, ...) macro(__VA_ARGS__) + +/*****************************************************************************/ -#define _NM_IN_SET(op, type, x, ...) \ - _NM_IN_SET_EVAL_N(op, type, x, NM_NARG(__VA_ARGS__), __VA_ARGS__) +/* clang-format off */ +#define _NM_VA_ARGS_FOREACH_0(prefix, postfix, sep, op) +#define _NM_VA_ARGS_FOREACH_1(prefix, postfix, sep, op, x) prefix _NM_MACRO_CALL2(op, x, 0 ) postfix +#define _NM_VA_ARGS_FOREACH_2(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 1 ) postfix sep _NM_VA_ARGS_FOREACH_1(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_3(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 2 ) postfix sep _NM_VA_ARGS_FOREACH_2(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_4(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 3 ) postfix sep _NM_VA_ARGS_FOREACH_3(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_5(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 4 ) postfix sep _NM_VA_ARGS_FOREACH_4(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_6(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 5 ) postfix sep _NM_VA_ARGS_FOREACH_5(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_7(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 6 ) postfix sep _NM_VA_ARGS_FOREACH_6(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_8(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 7 ) postfix sep _NM_VA_ARGS_FOREACH_7(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_9(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 8 ) postfix sep _NM_VA_ARGS_FOREACH_8(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_10(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 9 ) postfix sep _NM_VA_ARGS_FOREACH_9(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_11(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 10 ) postfix sep _NM_VA_ARGS_FOREACH_10(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_12(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 11 ) postfix sep _NM_VA_ARGS_FOREACH_11(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_13(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 12 ) postfix sep _NM_VA_ARGS_FOREACH_12(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_14(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 13 ) postfix sep _NM_VA_ARGS_FOREACH_13(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_15(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 14 ) postfix sep _NM_VA_ARGS_FOREACH_14(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_16(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 15 ) postfix sep _NM_VA_ARGS_FOREACH_15(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_17(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 16 ) postfix sep _NM_VA_ARGS_FOREACH_16(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_18(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 17 ) postfix sep _NM_VA_ARGS_FOREACH_17(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_19(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 18 ) postfix sep _NM_VA_ARGS_FOREACH_18(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_20(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 19 ) postfix sep _NM_VA_ARGS_FOREACH_19(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_21(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 20 ) postfix sep _NM_VA_ARGS_FOREACH_20(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_22(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 21 ) postfix sep _NM_VA_ARGS_FOREACH_21(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_23(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 22 ) postfix sep _NM_VA_ARGS_FOREACH_22(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_24(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 23 ) postfix sep _NM_VA_ARGS_FOREACH_23(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_25(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 24 ) postfix sep _NM_VA_ARGS_FOREACH_24(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_26(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 25 ) postfix sep _NM_VA_ARGS_FOREACH_25(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_27(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 26 ) postfix sep _NM_VA_ARGS_FOREACH_26(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_28(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 27 ) postfix sep _NM_VA_ARGS_FOREACH_27(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_29(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 28 ) postfix sep _NM_VA_ARGS_FOREACH_28(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_30(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 29 ) postfix sep _NM_VA_ARGS_FOREACH_29(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_31(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 30 ) postfix sep _NM_VA_ARGS_FOREACH_30(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_32(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 31 ) postfix sep _NM_VA_ARGS_FOREACH_31(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_33(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 32 ) postfix sep _NM_VA_ARGS_FOREACH_32(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_34(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 33 ) postfix sep _NM_VA_ARGS_FOREACH_33(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_35(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 34 ) postfix sep _NM_VA_ARGS_FOREACH_34(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_36(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 35 ) postfix sep _NM_VA_ARGS_FOREACH_35(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_37(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 36 ) postfix sep _NM_VA_ARGS_FOREACH_36(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_38(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 37 ) postfix sep _NM_VA_ARGS_FOREACH_37(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_39(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 38 ) postfix sep _NM_VA_ARGS_FOREACH_38(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_40(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 39 ) postfix sep _NM_VA_ARGS_FOREACH_39(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_41(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 40 ) postfix sep _NM_VA_ARGS_FOREACH_40(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_42(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 41 ) postfix sep _NM_VA_ARGS_FOREACH_41(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_43(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 42 ) postfix sep _NM_VA_ARGS_FOREACH_42(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_44(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 43 ) postfix sep _NM_VA_ARGS_FOREACH_43(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_45(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 44 ) postfix sep _NM_VA_ARGS_FOREACH_44(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_46(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 45 ) postfix sep _NM_VA_ARGS_FOREACH_45(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_47(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 46 ) postfix sep _NM_VA_ARGS_FOREACH_46(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_48(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 47 ) postfix sep _NM_VA_ARGS_FOREACH_47(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_49(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 48 ) postfix sep _NM_VA_ARGS_FOREACH_48(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_50(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 49 ) postfix sep _NM_VA_ARGS_FOREACH_49(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_51(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 50 ) postfix sep _NM_VA_ARGS_FOREACH_50(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_52(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 51 ) postfix sep _NM_VA_ARGS_FOREACH_51(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_53(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 52 ) postfix sep _NM_VA_ARGS_FOREACH_52(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_54(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 53 ) postfix sep _NM_VA_ARGS_FOREACH_53(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_55(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 54 ) postfix sep _NM_VA_ARGS_FOREACH_54(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_56(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 55 ) postfix sep _NM_VA_ARGS_FOREACH_55(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_57(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 56 ) postfix sep _NM_VA_ARGS_FOREACH_56(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_58(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 57 ) postfix sep _NM_VA_ARGS_FOREACH_57(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_59(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 58 ) postfix sep _NM_VA_ARGS_FOREACH_58(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_60(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 59 ) postfix sep _NM_VA_ARGS_FOREACH_59(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_61(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 10 ) postfix sep _NM_VA_ARGS_FOREACH_60(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_62(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 61 ) postfix sep _NM_VA_ARGS_FOREACH_61(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_63(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 62 ) postfix sep _NM_VA_ARGS_FOREACH_62(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_64(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 63 ) postfix sep _NM_VA_ARGS_FOREACH_63(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_65(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 64 ) postfix sep _NM_VA_ARGS_FOREACH_64(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_66(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 65 ) postfix sep _NM_VA_ARGS_FOREACH_65(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_67(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 66 ) postfix sep _NM_VA_ARGS_FOREACH_66(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_68(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 67 ) postfix sep _NM_VA_ARGS_FOREACH_67(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_69(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 68 ) postfix sep _NM_VA_ARGS_FOREACH_68(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_70(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 69 ) postfix sep _NM_VA_ARGS_FOREACH_69(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_71(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 70 ) postfix sep _NM_VA_ARGS_FOREACH_70(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_72(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 71 ) postfix sep _NM_VA_ARGS_FOREACH_71(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_73(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 72 ) postfix sep _NM_VA_ARGS_FOREACH_72(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_74(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 73 ) postfix sep _NM_VA_ARGS_FOREACH_73(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_75(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 74 ) postfix sep _NM_VA_ARGS_FOREACH_74(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_76(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 75 ) postfix sep _NM_VA_ARGS_FOREACH_75(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_77(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 76 ) postfix sep _NM_VA_ARGS_FOREACH_76(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_78(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 77 ) postfix sep _NM_VA_ARGS_FOREACH_77(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_79(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 78 ) postfix sep _NM_VA_ARGS_FOREACH_78(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_80(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 79 ) postfix sep _NM_VA_ARGS_FOREACH_79(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_81(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 80 ) postfix sep _NM_VA_ARGS_FOREACH_80(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_82(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 81 ) postfix sep _NM_VA_ARGS_FOREACH_81(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_83(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 82 ) postfix sep _NM_VA_ARGS_FOREACH_82(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_84(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 83 ) postfix sep _NM_VA_ARGS_FOREACH_83(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_85(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 84 ) postfix sep _NM_VA_ARGS_FOREACH_84(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_86(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 85 ) postfix sep _NM_VA_ARGS_FOREACH_85(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_87(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 86 ) postfix sep _NM_VA_ARGS_FOREACH_86(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_88(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 87 ) postfix sep _NM_VA_ARGS_FOREACH_87(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_89(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 88 ) postfix sep _NM_VA_ARGS_FOREACH_88(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_90(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 89 ) postfix sep _NM_VA_ARGS_FOREACH_89(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_91(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 90 ) postfix sep _NM_VA_ARGS_FOREACH_90(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_92(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 91 ) postfix sep _NM_VA_ARGS_FOREACH_91(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_93(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 92 ) postfix sep _NM_VA_ARGS_FOREACH_92(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_94(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 93 ) postfix sep _NM_VA_ARGS_FOREACH_93(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_95(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 94 ) postfix sep _NM_VA_ARGS_FOREACH_94(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_96(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 95 ) postfix sep _NM_VA_ARGS_FOREACH_95(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_97(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 96 ) postfix sep _NM_VA_ARGS_FOREACH_96(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_98(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 97 ) postfix sep _NM_VA_ARGS_FOREACH_97(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_99(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 98 ) postfix sep _NM_VA_ARGS_FOREACH_98(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_100(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 99 ) postfix sep _NM_VA_ARGS_FOREACH_99(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_101(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 100) postfix sep _NM_VA_ARGS_FOREACH_100(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_102(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 101) postfix sep _NM_VA_ARGS_FOREACH_101(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_103(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 102) postfix sep _NM_VA_ARGS_FOREACH_102(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_104(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 103) postfix sep _NM_VA_ARGS_FOREACH_103(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_105(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 104) postfix sep _NM_VA_ARGS_FOREACH_104(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_106(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 105) postfix sep _NM_VA_ARGS_FOREACH_105(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_107(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 106) postfix sep _NM_VA_ARGS_FOREACH_106(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_108(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 107) postfix sep _NM_VA_ARGS_FOREACH_107(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_109(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 108) postfix sep _NM_VA_ARGS_FOREACH_108(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_110(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 109) postfix sep _NM_VA_ARGS_FOREACH_109(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_111(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 100) postfix sep _NM_VA_ARGS_FOREACH_110(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_112(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 111) postfix sep _NM_VA_ARGS_FOREACH_111(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_113(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 112) postfix sep _NM_VA_ARGS_FOREACH_112(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_114(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 113) postfix sep _NM_VA_ARGS_FOREACH_113(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_115(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 114) postfix sep _NM_VA_ARGS_FOREACH_114(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_116(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 115) postfix sep _NM_VA_ARGS_FOREACH_115(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_117(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 116) postfix sep _NM_VA_ARGS_FOREACH_116(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_118(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 117) postfix sep _NM_VA_ARGS_FOREACH_117(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_119(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 118) postfix sep _NM_VA_ARGS_FOREACH_118(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_120(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 119) postfix sep _NM_VA_ARGS_FOREACH_119(prefix, postfix, sep, op, __VA_ARGS__) +/* clang-format on */ +#define NM_VA_ARGS_FOREACH(prefix, postfix, sep, op, ...) \ + _NM_MACRO_CALL(NM_PASTE(_NM_VA_ARGS_FOREACH_, NM_NARG(__VA_ARGS__)), \ + prefix, \ + postfix, \ + sep, \ + op, \ + ##__VA_ARGS__) + +/*****************************************************************************/ + +#define NM_VA_ARGS_JOIN(sep, ...) NM_VA_ARGS_FOREACH(, , sep, _NM_MACRO_SELECT_FIRST, __VA_ARGS__) + +/*****************************************************************************/ + +#define _NM_IN_SET_OP(x, idx) (_x == (x)) +#define _NM_IN_SET(op, type, x, ...) \ + ({ \ + type _x = (x); \ + \ + /* trigger a -Wenum-compare warning */ \ + nm_assert(true || _x == (x)); \ + \ + !!(NM_VA_ARGS_FOREACH(, , op, _NM_IN_SET_OP, __VA_ARGS__)); \ + }) /* Beware that this does short-circuit evaluation (use "||" instead of "|") * which has a possibly unexpected non-function-like behavior. @@ -468,96 +776,31 @@ nm_streq0(const char *s1, const char *s2) /*****************************************************************************/ -#define _NM_IN_SETOP_EVAL_1(op, op_eq, _x, y) (op_eq(_x, y)) -#define _NM_IN_SETOP_EVAL_2(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_1(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_3(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_2(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_4(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_3(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_5(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_4(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_6(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_5(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_7(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_6(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_8(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_7(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_9(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_8(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_10(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_9(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_11(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_10(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_12(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_11(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_13(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_12(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_14(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_13(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_15(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_14(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_16(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_15(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_17(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_16(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_18(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_17(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_19(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_18(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_20(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_19(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_21(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_20(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_22(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_21(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_23(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_22(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_24(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_23(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_25(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_24(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_26(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_25(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_27(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_26(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_28(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_27(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_29(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_28(op, op_eq, _x, __VA_ARGS__) -#define _NM_IN_SETOP_EVAL_30(op, op_eq, _x, y, ...) \ - (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_29(op, op_eq, _x, __VA_ARGS__) - -/*****************************************************************************/ - -#define _NM_IN_STRSET_EVAL_N2(op, op_ed, _x, n, ...) \ - (_NM_IN_SETOP_EVAL_##n(op, op_ed, _x, __VA_ARGS__)) -#define _NM_IN_STRSET_EVAL_N(op, op_ed, x, n, ...) \ - ({ \ - const char *_x = (x); \ - (((_x == NULL) && _NM_IN_SET_EVAL_N2(op, ((const char *) NULL), n, __VA_ARGS__)) \ - || ((_x != NULL) && _NM_IN_STRSET_EVAL_N2(op, op_ed, _x, n, __VA_ARGS__))); \ - }) - -/*****************************************************************************/ - static inline int -_NM_IN_STRSET_op_streq(const char *x, const char *s) +_NM_IN_STRSET_EVAL_op_streq(const char *x1, const char *x) { - return s && strcmp(x, s) == 0; + return x && nm_streq(x1, x); } +#define _NM_IN_STRSET_EVAL_OP_NULL(x, idx) (((const char *) NULL) == (x)) +#define _NM_IN_STRSET_EVAL_OP_STREQ(x, idx) _NM_IN_STRSET_EVAL_op_streq(_x1, x) +#define _NM_IN_STRSET_EVAL(op, eval_op, x1, ...) \ + ({ \ + const char *const _x1 = (x1); \ + \ + !!(_x1 ? (NM_VA_ARGS_FOREACH(, , op, eval_op, __VA_ARGS__)) \ + : (NM_VA_ARGS_FOREACH(, , op, _NM_IN_STRSET_EVAL_OP_NULL, __VA_ARGS__))); \ + }) + /* Beware that this does short-circuit evaluation (use "||" instead of "|") * which has a possibly unexpected non-function-like behavior. * Use NM_IN_STRSET_SE if you need all arguments to be evaluated. */ -#define NM_IN_STRSET(x, ...) \ - _NM_IN_STRSET_EVAL_N(||, _NM_IN_STRSET_op_streq, x, NM_NARG(__VA_ARGS__), __VA_ARGS__) +#define NM_IN_STRSET(x1, ...) _NM_IN_STRSET_EVAL(||, _NM_IN_STRSET_EVAL_OP_STREQ, x1, __VA_ARGS__) /* "SE" stands for "side-effect". Contrary to NM_IN_STRSET(), this does not do * short-circuit evaluation, which can make a difference if the arguments have * side-effects. */ -#define NM_IN_STRSET_SE(x, ...) \ - _NM_IN_STRSET_EVAL_N(|, _NM_IN_STRSET_op_streq, x, NM_NARG(__VA_ARGS__), __VA_ARGS__) +#define NM_IN_STRSET_SE(x1, ...) _NM_IN_STRSET_EVAL(|, _NM_IN_STRSET_EVAL_OP_STREQ, x1, __VA_ARGS__) /*****************************************************************************/ @@ -626,6 +869,19 @@ nm_close(int fd) return r; } +static inline bool +nm_clear_fd(int *p_fd) +{ + int fd; + + if (!p_fd || (fd = *p_fd) < 0) + return false; + + *p_fd = -1; + nm_close(fd); + return true; +} + /*****************************************************************************/ /* Note: @value is only evaluated when *out_val is present. @@ -734,7 +990,7 @@ _nm_auto_fclose(FILE **pfd) int _changed = false; \ \ if (_pp && (_p = *_pp)) { \ - _nm_unused const void *_p_check_is_pointer = _p; \ + _NM_ENSURE_POINTER(_p); \ \ *_pp = NULL; \ \ @@ -757,14 +1013,15 @@ _nm_auto_fclose(FILE **pfd) /*****************************************************************************/ -#define nm_steal_pointer(pp) \ - ({ \ - typeof(*(pp)) *const _pp = (pp); \ - typeof(*_pp) _p = *_pp; \ - _nm_unused const void *const _p_type_check = _p; \ - \ - *_pp = NULL; \ - _p; \ +#define nm_steal_pointer(pp) \ + ({ \ + typeof(*(pp)) *const _pp = (pp); \ + typeof(*_pp) _p = *_pp; \ + \ + _NM_ENSURE_POINTER(_p); \ + \ + *_pp = NULL; \ + _p; \ }) /** @@ -774,15 +1031,15 @@ _nm_auto_fclose(FILE **pfd) * Returns: *p_val and sets *p_val to zero the same time. * Accepts %NULL, in which case also numeric 0 will be returned. */ -#define nm_steal_int(p_val) \ - ({ \ - typeof(p_val) const _p_val = (p_val); \ - typeof(*_p_val) _val = 0; \ - \ - if (_p_val && (_val = *_p_val)) { \ - *_p_val = 0; \ - } \ - _val; \ +#define nm_steal_int(p_val) \ + ({ \ + typeof(p_val) const _p_val = (p_val); \ + typeof(*_p_val) _val = 0; \ + \ + if (_p_val && ((_val = *_p_val) != 0)) { \ + *_p_val = 0; \ + } \ + _val; \ }) static inline int @@ -923,6 +1180,21 @@ nm_ptr_to_uintptr(const void *p) #define NM_AF_INET_SIZE 4 /* sizeof (in_addr_t) */ #define NM_AF_INET6_SIZE 16 /* sizeof (stuct in6_addr) */ +static inline const char * +nm_utils_addr_family_to_str(int addr_family) +{ + switch (addr_family) { + case NM_AF_UNSPEC: + return ""; + case NM_AF_INET: + return "4"; + case NM_AF_INET6: + return "6"; + } + nm_assert_not_reached(); + return "?"; +} + static inline char nm_utils_addr_family_to_char(int addr_family) { @@ -938,6 +1210,29 @@ nm_utils_addr_family_to_char(int addr_family) return '?'; } +#define nm_assert_addr_family(addr_family) \ + nm_assert(NM_IN_SET((addr_family), NM_AF_INET, NM_AF_INET6)) + +#define nm_assert_addr_family_or_unspec(addr_family) \ + nm_assert(NM_IN_SET((addr_family), NM_AF_UNSPEC, NM_AF_INET, NM_AF_INET6)) + +#define _NM_IS_IPv4(uniq, addr_family) \ + ({ \ + const int NM_UNIQ_T(_addr_family, uniq) = (addr_family); \ + \ + nm_assert_addr_family(NM_UNIQ_T(_addr_family, uniq)); \ + \ + (NM_UNIQ_T(_addr_family, uniq) == NM_AF_INET); \ + }) + +#define NM_IS_IPv4(addr_family) _NM_IS_IPv4(NM_UNIQ, addr_family) + +static inline int +nm_utils_addr_family_other(int addr_family) +{ + return NM_IS_IPv4(addr_family) ? NM_AF_INET6 : NM_AF_INET; +} + static inline size_t nm_utils_addr_family_to_size(int addr_family) { @@ -947,8 +1242,7 @@ nm_utils_addr_family_to_size(int addr_family) case NM_AF_INET6: return NM_AF_INET6_SIZE; } - nm_assert_not_reached(); - return 0; + return nm_assert_unreachable_val(0); } static inline int @@ -963,16 +1257,4 @@ nm_utils_addr_family_from_size(size_t len) return NM_AF_UNSPEC; } -#define nm_assert_addr_family(addr_family) \ - nm_assert(NM_IN_SET((addr_family), NM_AF_INET, NM_AF_INET6)) - -#define NM_IS_IPv4(addr_family) \ - ({ \ - const int _addr_family = (addr_family); \ - \ - nm_assert_addr_family(_addr_family); \ - \ - (_addr_family == NM_AF_INET); \ - }) - #endif /* __NM_STD_AUX_H__ */ -- cgit 1.3.0-6-gf8a5