libctf, include: new functions for looking up enumerators

Three new functions for looking up the enum type containing a given
enumeration constant, and optionally that constant's value.

The simplest, ctf_lookup_enumerator, looks up a root-visible enumerator by
name in one dict: if the dict contains multiple such constants (which is
possible for dicts created by older versions of the libctf deduplicator),
ECTF_DUPLICATE is returned.

The next simplest, ctf_lookup_enumerator_next, is an iterator which returns
all enumerators with a given name in a given dict, whether root-visible or
not.

The most elaborate, ctf_arc_lookup_enumerator_next, finds all
enumerators with a given name across all dicts in an entire CTF archive,
whether root-visible or not, starting looking in the shared parent dict;
opened dicts are cached (as with all other ctf_arc_*lookup functions) so
that repeated use does not incur repeated opening costs.

All three of these return enumerator values as int64_t: unfortunately, API
compatibility concerns prevent us from doing the same with the other older
enum-related functions, which all return enumerator constant values as ints.
We may be forced to add symbol-versioning compatibility aliases that fix the
other functions in due course, bumping the soname for platforms that do not
support such things.

ctf_arc_lookup_enumerator_next is implemented as a nested ctf_archive_next
iterator, and inside that, a nested ctf_lookup_enumerator_next iterator
within each dict.  To aid in this, add support to ctf_next_t iterators for
iterators that are implemented in terms of two simultaneous nested iterators
at once.  (It has always been possible for callers to use as many nested or
semi-overlapping ctf_next_t iterators as they need, which is one of the
advantages of this style over the _iter style that calls a function for each
thing iterated over: the iterator change here permits *ctf_next_t iterators
themselves* to be implemented by iterating using multiple other iterators as
part of their internal operation, transparently to the caller.)

Also add a testcase that tests all these functions (which is fairly easy
because ctf_arc_lookup_enumerator_next is implemented in terms of
ctf_lookup_enumerator_next) in addition to enumeration addition in
ctf_open()ed dicts, ctf_add_enumerator duplicate enumerator addition, and
conflicting enumerator constant deduplication.

include/
	* ctf-api.h (ctf_lookup_enumerator): New.
	(ctf_lookup_enumerator_next): Likewise.
	(ctf_arc_lookup_enumerator_next): Likewise.

libctf/
	* libctf.ver: Add them.
	* ctf-impl.h (ctf_next_t) <ctn_next_inner>: New.
	* ctf-util.c (ctf_next_copy): Copy it.
        (ctf_next_destroy): Destroy it.
	* ctf-lookup.c (ctf_lookup_enumerator): New.
	(ctf_lookup_enumerator_next): New.
	* ctf-archive.c (ctf_arc_lookup_enumerator_next): New.
	* testsuite/libctf-lookup/enumerator-iteration.*: New test.
	* testsuite/libctf-lookup/enum-ctf-2.c: New test CTF, used by the
	  above.
This commit is contained in:
Nick Alcock
2024-06-11 20:58:00 +01:00
parent 1f62f2a9b5
commit 2fa4b6e6df
9 changed files with 520 additions and 9 deletions

View File

@@ -262,6 +262,8 @@ ctf_next_destroy (ctf_next_t *i)
free (i->u.ctn_sorted_hkv);
if (i->ctn_next)
ctf_next_destroy (i->ctn_next);
if (i->ctn_next_inner)
ctf_next_destroy (i->ctn_next_inner);
free (i);
}
@@ -276,16 +278,35 @@ ctf_next_copy (ctf_next_t *i)
return NULL;
memcpy (i2, i, sizeof (struct ctf_next));
if (i2->ctn_next)
{
i2->ctn_next = ctf_next_copy (i2->ctn_next);
if (i2->ctn_next == NULL)
goto err_next;
}
if (i2->ctn_next_inner)
{
i2->ctn_next_inner = ctf_next_copy (i2->ctn_next_inner);
if (i2->ctn_next_inner == NULL)
goto err_next_inner;
}
if (i2->ctn_iter_fun == (void (*) (void)) ctf_dynhash_next_sorted)
{
size_t els = ctf_dynhash_elements ((ctf_dynhash_t *) i->cu.ctn_h);
if ((i2->u.ctn_sorted_hkv = calloc (els, sizeof (ctf_next_hkv_t))) == NULL)
{
free (i2);
return NULL;
}
goto err_sorted_hkv;
memcpy (i2->u.ctn_sorted_hkv, i->u.ctn_sorted_hkv,
els * sizeof (ctf_next_hkv_t));
}
return i2;
err_sorted_hkv:
ctf_next_destroy (i2->ctn_next_inner);
err_next_inner:
ctf_next_destroy (i2->ctn_next);
err_next:
ctf_next_destroy (i2);
return NULL;
}