summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAlejandro Colomar <alx@nginx.com>2023-08-19 12:43:39 +0200
committerAlejandro Colomar <alx@kernel.org>2023-10-25 13:37:31 +0200
commita084e2bc8066ce2fed852bf04e5168e289bf834b (patch)
tree72cc4a025ae508b2461b20f8371a186c380600ac
parentfb33ec86a3b6ca6a844dfa6980bb9e083094abec (diff)
downloadunit-a084e2bc8066ce2fed852bf04e5168e289bf834b.tar.gz
unit-a084e2bc8066ce2fed852bf04e5168e289bf834b.tar.bz2
Libunit: added macros that enhance type safety.
nxt_min() nxt_max() Return the minimum/maximum of two values. nxt_swap() Swap the values of two variables passed by their addresses. nxt_sizeof_array() Return the size (in bytes) of an array. nxt_nitems() Return the number of elements in an array. nxt_memberof() Expand to a member of a structure. It uses a compound literal for the object. nxt_sizeof_incomplete() Calculate the size of an incomplete type, as if sizeof() could be applied to it. nxt_sizeof_fam0() Calculate the size of each element of a FAM of a structure. nxt_sizeof_fam() Calculate the size of a FAM of a structure. nxt_offsetof_fam() Calculate the offset of the nth element of the FAM from the start of the containing structure. nxt_sizeof_struct() Calculate the total size of a structure containing a FAM. This value is the one that should be used for allocating the structure. Suggested-by: Andrew Clayton <a.clayton@nginx.com> nxt_is_near_end() Evaluate to true if the member is near the end of a structure. This is only designed to be used with FAMs, to make sure that the FAM is near the end of the structure (a zero-length array near the end of the structure would still pass this test, but it's a reasonable assertion to do. Suggested-by: David Laight <David.Laight@ACULAB.COM> nxt_is_zero_sizeof() Evaluate to true if the size of 'x' is 0. nxt_is_same_type() Evaluate to true if the both arguments are compatible types. nxt_is_same_typeof() Evaluate to true if the types of both arguments are compatible. nxt_is_array() Evaluate to true if the argument is an array. nxt_must_be() It's like static_assert(3), but implemented as an expression. It's necessary for writing the must_be_array() macro. It's always evaluates to (int) 0. nxt_must_be_array() Statically assert that the argument is an array. It is an expression that always evaluates to (int) 0. nxt_must_be_zero_sizeof() Statically assert that the argument has a size of 0. nxt_must_be_near_end() Statically assert that a member of a structure is near the end of it. Suggested-by: David Laight <David.Laight@ACULAB.COM> nxt_must_be_fam() Statically assert that the argument is a flexible array member (FAM). It's an expression that always evaluates to (int) 0. Link: <https://gustedt.wordpress.com/2011/03/14/flexible-array-member/> Link: <https://lore.kernel.org/lkml/202308161913.91369D4A@keescook/T/> Link: <https://inbox.sourceware.org/gcc/dac8afb7-5026-c702-85d2-c3ad977d9a48@kernel.org/T/> Link: <https://stackoverflow.com/a/57537491> Link: <https://github.com/shadow-maint/shadow/pull/762> Cc: Andrew Clayton <a.clayton@nginx.com> Cc: Zhidao Hong <z.hong@f5.com> Signed-off-by: Alejandro Colomar <alx@nginx.com> Signed-off-by: Alejandro Colomar <alx@kernel.org>
-rw-r--r--auto/make2
-rw-r--r--src/nxt_clang.h17
-rw-r--r--src/nxt_unit.h1
-rw-r--r--src/nxt_unit_cdefs.h87
4 files changed, 94 insertions, 13 deletions
diff --git a/auto/make b/auto/make
index abfd41ad..88c4fb2b 100644
--- a/auto/make
+++ b/auto/make
@@ -406,6 +406,7 @@ libunit-install: $NXT_BUILD_DIR/lib/$NXT_LIB_UNIT_STATIC
test -d \$(DESTDIR)$NXT_INCLUDEDIR \
|| install -d \$(DESTDIR)$NXT_INCLUDEDIR
install -p -m u=rw,go=r src/nxt_unit.h \
+ src/nxt_unit_cdefs.h \
src/nxt_unit_field.h \
src/nxt_unit_request.h \
src/nxt_unit_response.h \
@@ -423,6 +424,7 @@ libunit-uninstall:
rm -f \$(DESTDIR)$NXT_PKGCONFIGDIR/unit.pc
@rmdir -p \$(DESTDIR)$NXT_PKGCONFIGDIR 2>/dev/null || true
rm -f \$(DESTDIR)$NXT_INCLUDEDIR/nxt_unit.h \
+ \$(DESTDIR)$NXT_INCLUDEDIR/nxt_unit_cdefs.h \
\$(DESTDIR)$NXT_INCLUDEDIR/nxt_unit_field.h \
\$(DESTDIR)$NXT_INCLUDEDIR/nxt_unit_request.h \
\$(DESTDIR)$NXT_INCLUDEDIR/nxt_unit_response.h \
diff --git a/src/nxt_clang.h b/src/nxt_clang.h
index 94638346..10ed6687 100644
--- a/src/nxt_clang.h
+++ b/src/nxt_clang.h
@@ -8,6 +8,9 @@
#define _NXT_CLANG_H_INCLUDED_
+#include <nxt_unit_cdefs.h>
+
+
#define nxt_inline static inline __attribute__((always_inline))
#define nxt_noinline __attribute__((noinline))
#define nxt_cdecl
@@ -210,24 +213,12 @@ nxt_popcount(unsigned int x)
*(type *) ((u_char *) p + offset)
-#define nxt_nitems(x) \
- (sizeof(x) / sizeof((x)[0]))
-
-
/* GCC and Clang use __builtin_abs() instead of libc abs(). */
#define nxt_abs(val) \
abs(val)
-#define nxt_max(val1, val2) \
- ((val1 < val2) ? (val2) : (val1))
-
-
-#define nxt_min(val1, val2) \
- ((val1 > val2) ? (val2) : (val1))
-
-
#define nxt_bswap32(val) \
( ((val) >> 24) \
| (((val) & 0x00FF0000) >> 8) \
@@ -252,7 +243,7 @@ nxt_popcount(unsigned int x)
#define nxt_length(s) \
- (sizeof(s) - 1)
+ (sizeof(s) - 1 + nxt_must_be_array(s))
#endif /* _NXT_CLANG_H_INCLUDED_ */
diff --git a/src/nxt_unit.h b/src/nxt_unit.h
index 35f9fa55..97e0e9df 100644
--- a/src/nxt_unit.h
+++ b/src/nxt_unit.h
@@ -15,6 +15,7 @@
#include "nxt_auto_config.h"
#include "nxt_version.h"
#include "nxt_unit_typedefs.h"
+#include <nxt_unit_cdefs.h>
enum {
diff --git a/src/nxt_unit_cdefs.h b/src/nxt_unit_cdefs.h
new file mode 100644
index 00000000..48389117
--- /dev/null
+++ b/src/nxt_unit_cdefs.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019-2023, Alejandro Colomar <alx@kernel.org>
+ * Copyright (C) NGINX, Inc.
+ */
+
+#ifndef _NXT_UNIT_CDEFS_H_INCLUDED_
+#define _NXT_UNIT_CDEFS_H_INCLUDED_
+
+
+#include <stddef.h>
+
+
+#define nxt_max(a, b) (((a) > (b)) ? (a) : (b))
+#define nxt_min(a, b) (((a) < (b)) ? (a) : (b))
+
+
+#define nxt_swap(ap, bp) \
+ do { \
+ __auto_type ap_ = (ap); \
+ __auto_type bp_ = (bp); \
+ typeof(*ap_) tmp_; \
+ \
+ _Static_assert(nxt_is_same_typeof(ap_, bp_), ""); \
+ \
+ tmp_ = *ap_; \
+ *ap_ = *bp_; \
+ *bp_ = tmp_; \
+ } while (0)
+
+
+#define nxt_sizeof_array(a) (sizeof(a) + nxt_must_be_array(a))
+#define nxt_nitems(a) (nxt_sizeof_array(a) / sizeof((a)[0]))
+#define nxt_memberof(T, member) ((T){}.member)
+
+#define nxt_sizeof_incomplete(x) \
+ ( \
+ sizeof( \
+ struct { \
+ max_align_t a; \
+ typeof(x) inc; \
+ } \
+ ) \
+ - sizeof(max_align_t) \
+ )
+
+#define nxt_sizeof_fam0(T, fam) \
+ (sizeof(nxt_memberof(T, fam[0])) + nxt_must_be_fam(T, fam))
+
+#define nxt_sizeof_fam(T, fam, n) \
+ (nxt_sizeof_fam0(T, fam) * (n))
+
+#define nxt_offsetof_fam(T, fam, n) \
+ (offsetof(T, fam) + nxt_sizeof_fam(T, fam, n))
+
+#define nxt_sizeof_struct(T, fam, n) \
+ nxt_max(sizeof(T), nxt_offsetof_fam(T, fam, n))
+
+
+#define nxt_is_near_end(T, m) (offsetof(T, m) > (sizeof(T) - _Alignof(T)))
+#define nxt_is_zero_sizeof(z) (nxt_sizeof_incomplete(z) == 0)
+#define nxt_is_same_type(a, b) __builtin_types_compatible_p(a, b)
+#define nxt_is_same_typeof(a, b) nxt_is_same_type(typeof(a), typeof(b))
+#define nxt_is_array(a) (!nxt_is_same_typeof(a, &(a)[0]))
+
+
+#define nxt_must_be(e) \
+ ( \
+ 0 * (int) sizeof( \
+ struct { \
+ _Static_assert(e, ""); \
+ int ISO_C_forbids_a_struct_with_no_members_; \
+ } \
+ ) \
+ )
+
+
+#define nxt_must_be_array(a) nxt_must_be(nxt_is_array(a))
+#define nxt_must_be_zero_sizeof(z) nxt_must_be(nxt_is_zero_sizeof(z))
+#define nxt_must_be_near_end(T, m) nxt_must_be(nxt_is_near_end(T, m))
+
+#define nxt_must_be_fam(T, fam) \
+ (nxt_must_be_array(nxt_memberof(T, fam)) \
+ + nxt_must_be_zero_sizeof(nxt_memberof(T, fam)) \
+ + nxt_must_be_near_end(T, fam))
+
+
+#endif /* _NXT_UNIT_CDEFS_H_INCLUDED_ */