diff --git a/src/sortedcache.c b/src/sortedcache.c index 6015d616d..2efa3c4e9 100644 --- a/src/sortedcache.c +++ b/src/sortedcache.c @@ -295,3 +295,62 @@ void *git_sortedcache_entry(const git_sortedcache *sc, size_t pos) { return git_vector_get(&sc->items, pos); } + +struct sortedcache_magic_key { + size_t offset; + const char *key; +}; + +static int sortedcache_magic_cmp(const void *key, const void *value) +{ + const struct sortedcache_magic_key *magic = key; + const char *value_key = ((const char *)value) + magic->offset; + return strcmp(magic->key, value_key); +} + +/* lookup index of item by key */ +int git_sortedcache_lookup_index( + size_t *out, git_sortedcache *sc, const char *key) +{ + struct sortedcache_magic_key magic; + + magic.offset = sc->item_path_offset; + magic.key = key; + + return git_vector_bsearch2(out, &sc->items, sortedcache_magic_cmp, &magic); +} + +/* remove entry from cache */ +int git_sortedcache_remove(git_sortedcache *sc, size_t pos, bool lock) +{ + int error = 0; + char *item; + khiter_t mappos; + + if (lock && git_sortedcache_lock(sc) < 0) + return -1; + + /* because of pool allocation, this can't actually remove the item, + * but we can remove it from the items vector and the hash table. + */ + + if ((item = git_vector_get(&sc->items, pos)) == NULL) { + giterr_set(GITERR_INVALID, "Removing item out of range"); + error = GIT_ENOTFOUND; + goto done; + } + + (void)git_vector_remove(&sc->items, pos); + + mappos = git_strmap_lookup_index(sc->map, item + sc->item_path_offset); + git_strmap_delete_at(sc->map, mappos); + + if (sc->free_item) + sc->free_item(sc->free_item_payload, item); + +done: + if (lock) + git_sortedcache_unlock(sc); + return error; +} + diff --git a/src/sortedcache.h b/src/sortedcache.h index 5d0d8f5a7..f63ad645b 100644 --- a/src/sortedcache.h +++ b/src/sortedcache.h @@ -98,4 +98,11 @@ size_t git_sortedcache_entrycount(const git_sortedcache *sc); /* lookup item by index */ void *git_sortedcache_entry(const git_sortedcache *sc, size_t pos); +/* lookup index of item by key */ +int git_sortedcache_lookup_index( + size_t *out, git_sortedcache *sc, const char *key); + +/* remove entry from cache */ +int git_sortedcache_remove(git_sortedcache *sc, size_t pos, bool lock); + #endif diff --git a/tests-clar/core/sortedcache.c b/tests-clar/core/sortedcache.c index f192af31d..91415943d 100644 --- a/tests-clar/core/sortedcache.c +++ b/tests-clar/core/sortedcache.c @@ -10,6 +10,7 @@ void test_core_sortedcache__name_only(void) { git_sortedcache *sc; void *item; + size_t pos; cl_git_pass(git_sortedcache_new( &sc, 0, NULL, NULL, name_only_cmp, NULL)); @@ -44,6 +45,15 @@ void test_core_sortedcache__name_only(void) cl_assert_equal_s("zzz", item); cl_assert(git_sortedcache_entry(sc, 5) == NULL); + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "aaa")); + cl_assert_equal_sz(0, pos); + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "iii")); + cl_assert_equal_sz(2, pos); + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "zzz")); + cl_assert_equal_sz(4, pos); + cl_assert_equal_i( + GIT_ENOTFOUND, git_sortedcache_lookup_index(&pos, sc, "abc")); + git_sortedcache_clear(sc, true); cl_assert_equal_sz(0, git_sortedcache_entrycount(sc)); @@ -182,6 +192,34 @@ void test_core_sortedcache__in_memory(void) cl_assert_equal_i(10, item->value); cl_assert(git_sortedcache_entry(sc, 3) == NULL); + { + size_t pos; + + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "again")); + cl_assert_equal_sz(0, pos); + cl_git_pass(git_sortedcache_remove(sc, pos, true)); + cl_assert_equal_i( + GIT_ENOTFOUND, git_sortedcache_lookup_index(&pos, sc, "again")); + + cl_assert_equal_sz(2, git_sortedcache_entrycount(sc)); + + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "testing")); + cl_assert_equal_sz(1, pos); + cl_git_pass(git_sortedcache_remove(sc, pos, true)); + cl_assert_equal_i( + GIT_ENOTFOUND, git_sortedcache_lookup_index(&pos, sc, "testing")); + + cl_assert_equal_sz(1, git_sortedcache_entrycount(sc)); + + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "final")); + cl_assert_equal_sz(0, pos); + cl_git_pass(git_sortedcache_remove(sc, pos, true)); + cl_assert_equal_i( + GIT_ENOTFOUND, git_sortedcache_lookup_index(&pos, sc, "final")); + + cl_assert_equal_sz(0, git_sortedcache_entrycount(sc)); + } + git_sortedcache_free(sc); cl_assert_equal_i(3, free_count); @@ -223,6 +261,7 @@ void test_core_sortedcache__on_disk(void) git_sortedcache *sc; sortedcache_test_struct *item; int free_count = 0; + size_t pos; cl_git_mkfile("cacheitems.txt", "10 abc\n20 bcd\n30 cde\n"); @@ -291,6 +330,19 @@ void test_core_sortedcache__on_disk(void) cl_assert_equal_s("zzz", item->path); cl_assert_equal_i(200, item->value); + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "aaa")); + cl_assert_equal_sz(0, pos); + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "abc")); + cl_assert_equal_sz(1, pos); + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "final")); + cl_assert_equal_sz(2, pos); + cl_git_pass(git_sortedcache_lookup_index(&pos, sc, "zzz")); + cl_assert_equal_sz(3, pos); + cl_assert_equal_i( + GIT_ENOTFOUND, git_sortedcache_lookup_index(&pos, sc, "missing")); + cl_assert_equal_i( + GIT_ENOTFOUND, git_sortedcache_lookup_index(&pos, sc, "cde")); + git_sortedcache_free(sc); cl_assert_equal_i(7, free_count);