ccan/structeq: make it safe when there's padding.
[ccan] / ccan / structeq / structeq.h
1 /* MIT (BSD) license - see LICENSE file for details */
2 #ifndef CCAN_STRUCTEQ_H
3 #define CCAN_STRUCTEQ_H
4 #include <ccan/build_assert/build_assert.h>
5 #include <ccan/cppmagic/cppmagic.h>
6 #include <string.h>
7 #include <stdbool.h>
8
9 /**
10  * STRUCTEQ_DEF - define an ..._eq function to compare two structures.
11  * @sname: name of the structure, and function (<sname>_eq) to define.
12  * @padbytes: number of bytes of expected padding, or -1 if unknown.
13  * @...: name of every member of the structure.
14  *
15  * This generates a single memcmp() call in the common case where the
16  * structure contains no padding.  Since it can't tell the difference between
17  * padding and a missing member, @padbytes can be used to assert that
18  * there isn't any, or how many we expect.  -1 means "expect some", since
19  * it can be platform dependent.
20  */
21 #define STRUCTEQ_DEF(sname, padbytes, ...)                              \
22 static inline bool CPPMAGIC_GLUE2(sname, _eq)(const struct sname *_a, \
23                                               const struct sname *_b) \
24 {                                                                       \
25         BUILD_ASSERT(((padbytes) < 0 &&                                 \
26                       CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, \
27                                                     __VA_ARGS__))       \
28                       > sizeof(*_a))                                    \
29                      || CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, \
30                                                       __VA_ARGS__))     \
31                      + (padbytes) == sizeof(*_a));                      \
32         if (CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, __VA_ARGS__)) \
33             == sizeof(*_a))                                             \
34                 return memcmp(_a, _b, sizeof(*_a)) == 0;                \
35         else                                                            \
36                 return CPPMAGIC_JOIN(&&,                                \
37                                      CPPMAGIC_MAP(STRUCTEQ_MEMBER_CMP_, \
38                                                   __VA_ARGS__));        \
39 }
40
41 /* Helpers */
42 #define STRUCTEQ_MEMBER_SIZE_(m) sizeof((_a)->m)
43 #define STRUCTEQ_MEMBER_CMP_(m) memcmp(&_a->m, &_b->m, sizeof(_a->m)) == 0
44
45 #endif /* CCAN_STRUCTEQ_H */