Skip to content

Commit 5ead0bd

Browse files
authored
Merge pull request libgit2#6897 from libgit2/ethomson/hashmap
hashmap: a libgit2-idiomatic khash
2 parents 751c68f + 9d57a7a commit 5ead0bd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1508
-2569
lines changed

.github/workflows/experimental.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ jobs:
4848
SKIP_NEGOTIATE_TESTS: true
4949
- name: "Windows (SHA256, amd64, Visual Studio)"
5050
id: windows-sha256
51-
os: windows-2019
51+
os: windows-2022
5252
env:
5353
ARCH: amd64
54-
CMAKE_GENERATOR: Visual Studio 16 2019
54+
CMAKE_GENERATOR: Visual Studio 17 2022
5555
CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON
5656
SKIP_SSH_TESTS: true
5757
SKIP_NEGOTIATE_TESTS: true

src/libgit2/apply.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "reader.h"
2121
#include "index.h"
2222
#include "repository.h"
23+
#include "hashmap_str.h"
2324
#include "apply.h"
2425

2526
typedef struct {
@@ -452,7 +453,7 @@ static int apply_one(
452453
git_reader *postimage_reader,
453454
git_index *postimage,
454455
git_diff *diff,
455-
git_strmap *removed_paths,
456+
git_hashset_str *removed_paths,
456457
size_t i,
457458
const git_apply_options *opts)
458459
{
@@ -489,7 +490,7 @@ static int apply_one(
489490
*/
490491
if (delta->status != GIT_DELTA_RENAMED &&
491492
delta->status != GIT_DELTA_ADDED) {
492-
if (git_strmap_exists(removed_paths, delta->old_file.path)) {
493+
if (git_hashset_str_contains(removed_paths, delta->old_file.path)) {
493494
error = apply_err("path '%s' has been renamed or deleted", delta->old_file.path);
494495
goto done;
495496
}
@@ -573,11 +574,11 @@ static int apply_one(
573574

574575
if (delta->status == GIT_DELTA_RENAMED ||
575576
delta->status == GIT_DELTA_DELETED)
576-
error = git_strmap_set(removed_paths, delta->old_file.path, (char *) delta->old_file.path);
577+
error = git_hashset_str_add(removed_paths, delta->old_file.path);
577578

578579
if (delta->status == GIT_DELTA_RENAMED ||
579580
delta->status == GIT_DELTA_ADDED)
580-
git_strmap_delete(removed_paths, delta->new_file.path);
581+
git_hashset_str_remove(removed_paths, delta->new_file.path);
581582

582583
done:
583584
git_str_dispose(&pre_contents);
@@ -597,20 +598,17 @@ static int apply_deltas(
597598
git_diff *diff,
598599
const git_apply_options *opts)
599600
{
600-
git_strmap *removed_paths;
601+
git_hashset_str removed_paths = GIT_HASHSET_INIT;
601602
size_t i;
602603
int error = 0;
603604

604-
if (git_strmap_new(&removed_paths) < 0)
605-
return -1;
606-
607605
for (i = 0; i < git_diff_num_deltas(diff); i++) {
608-
if ((error = apply_one(repo, pre_reader, preimage, post_reader, postimage, diff, removed_paths, i, opts)) < 0)
606+
if ((error = apply_one(repo, pre_reader, preimage, post_reader, postimage, diff, &removed_paths, i, opts)) < 0)
609607
goto done;
610608
}
611609

612610
done:
613-
git_strmap_free(removed_paths);
611+
git_hashset_str_dispose(&removed_paths);
614612
return error;
615613
}
616614

src/libgit2/attr.c

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "attr_file.h"
1414
#include "ignore.h"
1515
#include "git2/oid.h"
16+
#include "hashmap_str.h"
1617
#include <ctype.h>
1718

1819
const char *git_attr__true = "[internal]__TRUE__";
@@ -254,7 +255,7 @@ int git_attr_foreach_ext(
254255
git_attr_file *file;
255256
git_attr_rule *rule;
256257
git_attr_assignment *assign;
257-
git_strmap *seen = NULL;
258+
git_hashset_str seen = GIT_HASHSET_INIT;
258259
git_dir_flag dir_flag = GIT_DIR_FLAG_UNKNOWN;
259260

260261
GIT_ASSERT_ARG(repo);
@@ -267,8 +268,7 @@ int git_attr_foreach_ext(
267268
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), dir_flag) < 0)
268269
return -1;
269270

270-
if ((error = collect_attr_files(repo, NULL, opts, pathname, &files)) < 0 ||
271-
(error = git_strmap_new(&seen)) < 0)
271+
if ((error = collect_attr_files(repo, NULL, opts, pathname, &files)) < 0)
272272
goto cleanup;
273273

274274
git_vector_foreach(&files, i, file) {
@@ -277,10 +277,10 @@ int git_attr_foreach_ext(
277277

278278
git_vector_foreach(&rule->assigns, k, assign) {
279279
/* skip if higher priority assignment was already seen */
280-
if (git_strmap_exists(seen, assign->name))
280+
if (git_hashset_str_contains(&seen, assign->name))
281281
continue;
282282

283-
if ((error = git_strmap_set(seen, assign->name, assign)) < 0)
283+
if ((error = git_hashset_str_add(&seen, assign->name)) < 0)
284284
goto cleanup;
285285

286286
error = callback(assign->name, assign->value, payload);
@@ -293,7 +293,7 @@ int git_attr_foreach_ext(
293293
}
294294

295295
cleanup:
296-
git_strmap_free(seen);
296+
git_hashset_str_dispose(&seen);
297297
release_attr_files(&files);
298298
git_attr_path__free(&path);
299299

@@ -384,6 +384,8 @@ static int attr_setup(
384384
git_attr_file_source index_source = { GIT_ATTR_FILE_SOURCE_INDEX, NULL, GIT_ATTR_FILE, NULL };
385385
git_attr_file_source head_source = { GIT_ATTR_FILE_SOURCE_HEAD, NULL, GIT_ATTR_FILE, NULL };
386386
git_attr_file_source commit_source = { GIT_ATTR_FILE_SOURCE_COMMIT, NULL, GIT_ATTR_FILE, NULL };
387+
git_attr_cache *attrcache;
388+
const char *attr_cfg_file = NULL;
387389
git_index *idx = NULL;
388390
const char *workdir;
389391
int error = 0;
@@ -407,8 +409,10 @@ static int attr_setup(
407409
error = 0;
408410
}
409411

410-
if ((error = preload_attr_file(repo, attr_session, NULL,
411-
git_repository_attr_cache(repo)->cfg_attr_file)) < 0)
412+
if ((attrcache = git_repository_attr_cache(repo)) != NULL)
413+
attr_cfg_file = git_attr_cache_attributesfile(attrcache);
414+
415+
if ((error = preload_attr_file(repo, attr_session, NULL, attr_cfg_file)) < 0)
412416
goto out;
413417

414418
if ((error = git_repository__item_path(&info, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 ||
@@ -464,6 +468,7 @@ int git_attr_add_macro(
464468
{
465469
int error;
466470
git_attr_rule *macro = NULL;
471+
git_attr_cache *attrcache;
467472
git_pool *pool;
468473

469474
GIT_ASSERT_ARG(repo);
@@ -475,7 +480,8 @@ int git_attr_add_macro(
475480
macro = git__calloc(1, sizeof(git_attr_rule));
476481
GIT_ERROR_CHECK_ALLOC(macro);
477482

478-
pool = &git_repository_attr_cache(repo)->pool;
483+
attrcache = git_repository_attr_cache(repo);
484+
pool = git_attr_cache_pool(attrcache);
479485

480486
macro->match.pattern = git_pool_strdup(pool, name);
481487
GIT_ERROR_CHECK_ALLOC(macro->match.pattern);
@@ -631,6 +637,8 @@ static int collect_attr_files(
631637
int error = 0;
632638
git_str dir = GIT_STR_INIT, attrfile = GIT_STR_INIT;
633639
const char *workdir = git_repository_workdir(repo);
640+
git_attr_cache *attrcache;
641+
const char *attr_cfg_file = NULL;
634642
attr_walk_up_info info = { NULL };
635643

636644
GIT_ASSERT(!git_fs_path_is_absolute(path));
@@ -679,8 +687,13 @@ static int collect_attr_files(
679687
if (error < 0)
680688
goto cleanup;
681689

682-
if (git_repository_attr_cache(repo)->cfg_attr_file != NULL) {
683-
error = push_attr_file(repo, attr_session, files, NULL, git_repository_attr_cache(repo)->cfg_attr_file);
690+
if ((attrcache = git_repository_attr_cache(repo)) != NULL)
691+
attr_cfg_file = git_attr_cache_attributesfile(attrcache);
692+
693+
694+
if (attr_cfg_file) {
695+
error = push_attr_file(repo, attr_session, files, NULL, attr_cfg_file);
696+
684697
if (error < 0)
685698
goto cleanup;
686699
}

src/libgit2/attrcache.c

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,38 @@
1313
#include "sysdir.h"
1414
#include "ignore.h"
1515
#include "path.h"
16+
#include "hashmap_str.h"
17+
18+
GIT_HASHMAP_STR_SETUP(git_attr_cache_filemap, git_attr_file_entry *);
19+
GIT_HASHMAP_STR_SETUP(git_attr_cache_macromap, git_attr_rule *);
20+
21+
struct git_attr_cache {
22+
char *cfg_attr_file; /* cached value of core.attributesfile */
23+
char *cfg_excl_file; /* cached value of core.excludesfile */
24+
25+
/* hash path to git_attr_file_entry records */
26+
git_attr_cache_filemap files;
27+
/* hash name to git_attr_rule */
28+
git_attr_cache_macromap macros;
29+
30+
git_mutex lock;
31+
git_pool pool;
32+
};
33+
34+
const char *git_attr_cache_attributesfile(git_attr_cache *cache)
35+
{
36+
return cache->cfg_attr_file;
37+
}
38+
39+
const char *git_attr_cache_excludesfile(git_attr_cache *cache)
40+
{
41+
return cache->cfg_excl_file;
42+
}
43+
44+
git_pool *git_attr_cache_pool(git_attr_cache *cache)
45+
{
46+
return &cache->pool;
47+
}
1648

1749
GIT_INLINE(int) attr_cache_lock(git_attr_cache *cache)
1850
{
@@ -34,7 +66,12 @@ GIT_INLINE(void) attr_cache_unlock(git_attr_cache *cache)
3466
GIT_INLINE(git_attr_file_entry *) attr_cache_lookup_entry(
3567
git_attr_cache *cache, const char *path)
3668
{
37-
return git_strmap_get(cache->files, path);
69+
git_attr_file_entry *result;
70+
71+
if (git_attr_cache_filemap_get(&result, &cache->files, path) == 0)
72+
return result;
73+
74+
return NULL;
3875
}
3976

4077
int git_attr_cache__alloc_file_entry(
@@ -92,7 +129,7 @@ static int attr_cache_make_entry(
92129
git_repository_workdir(repo), path, &cache->pool)) < 0)
93130
return error;
94131

95-
if ((error = git_strmap_set(cache->files, entry->path, entry)) < 0)
132+
if ((error = git_attr_cache_filemap_put(&cache->files, entry->path, entry)) < 0)
96133
return error;
97134

98135
*out = entry;
@@ -271,12 +308,11 @@ bool git_attr_cache__is_cached(
271308
{
272309
git_attr_cache *cache = git_repository_attr_cache(repo);
273310
git_attr_file_entry *entry;
274-
git_strmap *files;
275311

276-
if (!cache || !(files = cache->files))
312+
if (!cache)
277313
return false;
278314

279-
if ((entry = git_strmap_get(files, filename)) == NULL)
315+
if (git_attr_cache_filemap_get(&entry, &cache->files, filename) != 0)
280316
return false;
281317

282318
return entry && (entry->file[source_type] != NULL);
@@ -318,37 +354,34 @@ static int attr_cache__lookup_path(
318354

319355
static void attr_cache__free(git_attr_cache *cache)
320356
{
357+
git_hashmap_iter_t iter = GIT_HASHMAP_ITER_INIT;
358+
git_attr_rule *rule;
359+
git_attr_file_entry *entry;
321360
bool unlock;
322361

323362
if (!cache)
324363
return;
325364

326365
unlock = (attr_cache_lock(cache) == 0);
327366

328-
if (cache->files != NULL) {
329-
git_attr_file_entry *entry;
367+
while (git_attr_cache_filemap_iterate(&iter, NULL, &entry, &cache->files) == 0) {
330368
git_attr_file *file;
331-
int i;
332-
333-
git_strmap_foreach_value(cache->files, entry, {
334-
for (i = 0; i < GIT_ATTR_FILE_NUM_SOURCES; ++i) {
335-
if ((file = git_atomic_swap(entry->file[i], NULL)) != NULL) {
336-
GIT_REFCOUNT_OWN(file, NULL);
337-
git_attr_file__free(file);
338-
}
369+
size_t i;
370+
371+
for (i = 0; i < GIT_ATTR_FILE_NUM_SOURCES; i++) {
372+
if ((file = git_atomic_swap(entry->file[i], NULL)) != NULL) {
373+
GIT_REFCOUNT_OWN(file, NULL);
374+
git_attr_file__free(file);
339375
}
340-
});
341-
git_strmap_free(cache->files);
376+
}
342377
}
343378

344-
if (cache->macros != NULL) {
345-
git_attr_rule *rule;
379+
iter = GIT_HASHMAP_ITER_INIT;
380+
while (git_attr_cache_macromap_iterate(&iter, NULL, &rule, &cache->macros) == 0)
381+
git_attr_rule__free(rule);
346382

347-
git_strmap_foreach_value(cache->macros, rule, {
348-
git_attr_rule__free(rule);
349-
});
350-
git_strmap_free(cache->macros);
351-
}
383+
git_attr_cache_filemap_dispose(&cache->files);
384+
git_attr_cache_macromap_dispose(&cache->macros);
352385

353386
git_pool_clear(&cache->pool);
354387

@@ -401,9 +434,7 @@ int git_attr_cache__init(git_repository *repo)
401434
/* allocate hashtable for attribute and ignore file contents,
402435
* hashtable for attribute macros, and string pool
403436
*/
404-
if ((ret = git_strmap_new(&cache->files)) < 0 ||
405-
(ret = git_strmap_new(&cache->macros)) < 0 ||
406-
(ret = git_pool_init(&cache->pool, 1)) < 0)
437+
if ((ret = git_pool_init(&cache->pool, 1)) < 0)
407438
goto cancel;
408439

409440
if (git_atomic_compare_and_swap(&repo->attrcache, NULL, cache) != NULL)
@@ -457,11 +488,11 @@ int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro)
457488
goto out;
458489
locked = true;
459490

460-
if ((preexisting = git_strmap_get(cache->macros, macro->match.pattern)) != NULL)
461-
git_attr_rule__free(preexisting);
491+
if (git_attr_cache_macromap_get(&preexisting, &cache->macros, macro->match.pattern) == 0)
492+
git_attr_rule__free(preexisting);
462493

463-
if ((error = git_strmap_set(cache->macros, macro->match.pattern, macro)) < 0)
464-
goto out;
494+
if ((error = git_attr_cache_macromap_put(&cache->macros, macro->match.pattern, macro)) < 0)
495+
goto out;
465496

466497
out:
467498
if (locked)
@@ -472,7 +503,12 @@ int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro)
472503
git_attr_rule *git_attr_cache__lookup_macro(
473504
git_repository *repo, const char *name)
474505
{
475-
git_strmap *macros = git_repository_attr_cache(repo)->macros;
506+
git_attr_cache *cache = git_repository_attr_cache(repo);
507+
git_attr_rule *rule;
508+
509+
if (!cache ||
510+
git_attr_cache_macromap_get(&rule, &cache->macros, name) != 0)
511+
return NULL;
476512

477-
return git_strmap_get(macros, name);
513+
return rule;
478514
}

src/libgit2/attrcache.h

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,18 @@
1010
#include "common.h"
1111

1212
#include "attr_file.h"
13-
#include "strmap.h"
1413

1514
#define GIT_ATTR_CONFIG "core.attributesfile"
1615
#define GIT_IGNORE_CONFIG "core.excludesfile"
1716

18-
typedef struct {
19-
char *cfg_attr_file; /* cached value of core.attributesfile */
20-
char *cfg_excl_file; /* cached value of core.excludesfile */
21-
git_strmap *files; /* hash path to git_attr_cache_entry records */
22-
git_strmap *macros; /* hash name to vector<git_attr_assignment> */
23-
git_mutex lock;
24-
git_pool pool;
25-
} git_attr_cache;
17+
typedef struct git_attr_cache git_attr_cache;
2618

2719
extern int git_attr_cache__init(git_repository *repo);
2820

21+
extern const char *git_attr_cache_attributesfile(git_attr_cache *ac);
22+
extern const char *git_attr_cache_excludesfile(git_attr_cache *ac);
23+
extern git_pool *git_attr_cache_pool(git_attr_cache *ac);
24+
2925
/* get file - loading and reload as needed */
3026
extern int git_attr_cache__get(
3127
git_attr_file **file,

0 commit comments

Comments
 (0)