sd-id128: add convenience functions to compare multiple sd_id128_t

Similar to sd_bus_error_has_names() that was added in
2b07ec316a.

It is made inline in the hope that the compiler will be able to optimize
all the va_args boilerplate away, and do an efficient comparison when
the arguments are all constants.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2021-04-19 15:36:10 +02:00
parent 78aa5b6f59
commit 64b21afc72
4 changed files with 66 additions and 0 deletions

View File

@ -128,6 +128,9 @@ manpages = [
'SD_ID128_NULL',
'SD_ID128_UUID_FORMAT_STR',
'sd_id128_equal',
'sd_id128_in_set',
'sd_id128_in_set_sentinel',
'sd_id128_in_setv',
'sd_id128_is_allf',
'sd_id128_is_null',
'sd_id128_t'],

View File

@ -27,6 +27,9 @@
<refname>SD_ID128_NULL</refname>
<refname>SD_ID128_UUID_FORMAT_STR</refname>
<refname>sd_id128_equal</refname>
<refname>sd_id128_in_set</refname>
<refname>sd_id128_in_set_sentinel</refname>
<refname>sd_id128_in_setv</refname>
<refname>sd_id128_is_allf</refname>
<refname>sd_id128_is_null</refname>
<refname>sd_id128_t</refname>
@ -148,6 +151,32 @@ int main(int argc, char **argv) {
<programlisting>assert(sd_id128_is_allf(SD_ID128_ALLF));</programlisting>
<para>For convenience, <function>sd_id128_in_set()</function> takes a list of IDs and
returns true if any are equal to the first argument:</para>
<programlisting>int main(int argc, char *argv[]) {
sd_id12_t a = SD_ID128_MAKE(ee,89,be,71,bd,6e,43,d6,91,e6,c5,5d,eb,03,02,07);
assert(sd_id128_in_set(a, a));
assert(sd_id128_in_set(a, a, a));
assert(!sd_id128_in_set(a));
assert(!sd_id128_in_set(a,
SD_ID128_MAKE(f2,28,88,9c,5f,09,44,15,9d,d7,04,77,58,cb,e7,3e)
SD_ID128_MAKE(2f,88,28,5f,9c,44,09,9d,d7,15,77,04,bc,85,7e,e3)
SD_ID128_ALLF));
return 0;
}
</programlisting>
<para><function>sd_id128_in_set()</function> is defined as a macro over
<function>sd_id128_in_set_sentinel()</function>, adding the <constant>SD_ID128_NULL</constant>
sentinel. Since <function>sd_id128_in_set_sentinel()</function> uses <constant>SD_ID128_NULL</constant>
as the sentinel, <constant>SD_ID128_NULL</constant> cannot be otherwise placed in the argument list.
</para>
<para><function>sd_id128_in_setv()</function> is similar to
<function>sd_id128_in_set_sentinel()</function>, but takes a <structname>struct varargs</structname>
argument.</para>
<para>Note that new, randomized IDs may be generated with
<citerefentry><refentrytitle>systemd-id128</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>new</command> command.</para>

View File

@ -18,6 +18,7 @@
***/
#include <inttypes.h>
#include <stdarg.h>
#include <string.h>
#include "_sd-common.h"
@ -119,6 +120,32 @@ _sd_pure_ static __inline__ int sd_id128_is_allf(sd_id128_t a) {
#define SD_ID128_NULL ((const sd_id128_t) { .qwords = { 0, 0 }})
#define SD_ID128_ALLF ((const sd_id128_t) { .qwords = { UINT64_C(0xFFFFFFFFFFFFFFFF), UINT64_C(0xFFFFFFFFFFFFFFFF) }})
_sd_pure_ static __inline__ int sd_id128_in_setv(sd_id128_t a, va_list ap) {
for (;;) {
sd_id128_t b = va_arg(ap, sd_id128_t);
if (sd_id128_is_null(b))
return 0;
if (sd_id128_equal(a, b))
return 1;
}
}
_sd_pure_ static __inline__ int sd_id128_in_set_sentinel(sd_id128_t a, ...) {
va_list ap;
int r;
va_start(ap, a);
r = sd_id128_in_setv(a, ap);
va_end(ap);
return r;
}
#define sd_id128_in_set(a, ...) \
sd_id128_in_set_sentinel(a, ##__VA_ARGS__, SD_ID128_NULL)
_SD_END_DECLARATIONS;
#endif

View File

@ -31,6 +31,13 @@ int main(int argc, char *argv[]) {
assert_se(sd_id128_from_string(t, &id2) == 0);
assert_se(sd_id128_equal(id, id2));
assert_se(sd_id128_in_set(id, id));
assert_se(sd_id128_in_set(id, id2));
assert_se(sd_id128_in_set(id, id2, id));
assert_se(sd_id128_in_set(id, ID128_WALDI, id));
assert_se(!sd_id128_in_set(id));
assert_se(!sd_id128_in_set(id, ID128_WALDI));
assert_se(!sd_id128_in_set(id, ID128_WALDI, ID128_WALDI));
if (sd_booted() > 0) {
assert_se(sd_id128_get_machine(&id) == 0);