commit 7b5b670e542e9a69edcd9c3d76ce9ab4a3855c6f from: Stefan Sperling date: Fri Dec 25 21:38:17 2020 UTC implement an object ID map for reference lists ok naddy commit - 4c4ce67b628a0b29afb50487072e667ee37e1dad commit + 7b5b670e542e9a69edcd9c3d76ce9ab4a3855c6f blob - 5f2594f5af806ea9b99c358f35fa4e7ce16f7efb blob + 8a7ddd1fed280c5ace7be5e759d1b7ef2c6cc784 --- include/got_reference.h +++ include/got_reference.h @@ -139,3 +139,28 @@ const struct got_error *got_ref_delete(struct got_refe /* Unlock a reference which was opened in locked state. */ const struct got_error *got_ref_unlock(struct got_reference *); + +/* Map object IDs to references. */ +struct got_reflist_object_id_map; + +/* + * Create and populate an object ID map for a given list of references. + * Map entries will contain deep-copies of elements of the reflist. + * The caller must dispose of the map with got_reflist_object_map_free(). + */ +const struct got_error *got_reflist_object_id_map_create( + struct got_reflist_object_id_map **, struct got_reflist_head *, + struct got_repository *); + +/* + * Return a list of references which correspond to a given object ID. + * The returned list must be considered read-only. + * The caller must _not_ call free(3) on the returned pointer! + * If no references are associated with the ID, return NULL. + */ +struct got_reflist_head * +got_reflist_object_id_map_lookup(struct got_reflist_object_id_map *, + struct got_object_id *); + +/* Free the specified object ID map. */ +void got_reflist_object_map_free(struct got_reflist_object_id_map *); blob - 7df07c953f7657dda28101ec2213bf5c222db220 blob + d9f1596591be3332b0a51e1ec4e6c77a90720fae --- lib/reference.c +++ lib/reference.c @@ -43,6 +43,7 @@ #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" +#include "got_lib_object_idset.h" #include "got_lib_lockfile.h" #ifndef nitems @@ -1400,3 +1401,97 @@ got_ref_unlock(struct got_reference *ref) ref->lf = NULL; return err; } + +struct got_reflist_object_id_map { + struct got_object_idset *idset; +}; + +struct got_reflist_object_id_map_entry { + struct got_reflist_head refs; +}; + +const struct got_error * +got_reflist_object_id_map_create(struct got_reflist_object_id_map **map, + struct got_reflist_head *refs, struct got_repository *repo) +{ + const struct got_error *err = NULL; + struct got_object_idset *idset; + struct got_object_id *id = NULL; + struct got_reflist_entry *re; + + idset = got_object_idset_alloc(); + if (idset == NULL) + return got_error_from_errno("got_object_idset_alloc"); + + *map = malloc(sizeof(**map)); + if (*map == NULL) { + got_object_idset_free(idset); + return got_error_from_errno("malloc"); + } + (*map)->idset = idset; + + SIMPLEQ_FOREACH(re, refs, entry) { + struct got_reflist_entry *new; + struct got_reflist_object_id_map_entry *ent; + + err = got_ref_resolve(&id, repo, re->ref); + if (err) + goto done; + + ent = got_object_idset_get(idset, id); + if (ent == NULL) { + ent = malloc(sizeof(*ent)); + if (ent == NULL) { + err = got_error_from_errno("malloc"); + goto done; + } + SIMPLEQ_INIT(&ent->refs); + err = got_object_idset_add(idset, id, ent); + if (err) + goto done; + } + + err = got_reflist_entry_dup(&new, re); + if (err) + goto done; + SIMPLEQ_INSERT_TAIL(&ent->refs, new, entry); + free(id); + id = NULL; + } +done: + free(id); + if (err) { + got_reflist_object_map_free(*map); + *map = NULL; + } + return NULL; +} + +struct got_reflist_head * +got_reflist_object_id_map_lookup(struct got_reflist_object_id_map *map, + struct got_object_id *id) +{ + struct got_reflist_object_id_map_entry *ent; + ent = got_object_idset_get(map->idset, id); + if (ent) + return &ent->refs; + return NULL; +} + +static const struct got_error * +free_id_map_entry(struct got_object_id *id, void *data, void *arg) +{ + struct got_reflist_object_id_map_entry *ent = data; + + got_ref_list_free(&ent->refs); + free(ent); + return NULL; +} + +void +got_reflist_object_map_free(struct got_reflist_object_id_map *map) +{ + got_object_idset_for_each(map->idset, free_id_map_entry, NULL); + got_object_idset_free(map->idset); + free(map); +}