2424#include "dir.h"
2525#include "submodule.h"
2626
27+ struct path_hashmap_entry {
28+ struct hashmap_entry e ;
29+ char path [FLEX_ARRAY ];
30+ };
31+
32+ static int path_hashmap_cmp (const void * cmp_data ,
33+ const void * entry ,
34+ const void * entry_or_key ,
35+ const void * keydata )
36+ {
37+ const struct path_hashmap_entry * a = entry ;
38+ const struct path_hashmap_entry * b = entry_or_key ;
39+ const char * key = keydata ;
40+
41+ if (ignore_case )
42+ return strcasecmp (a -> path , key ? key : b -> path );
43+ else
44+ return strcmp (a -> path , key ? key : b -> path );
45+ }
46+
47+ static unsigned int path_hash (const char * path )
48+ {
49+ return ignore_case ? strihash (path ) : strhash (path );
50+ }
51+
2752static void flush_output (struct merge_options * o )
2853{
2954 if (o -> buffer_output < 2 && o -> obuf .len ) {
@@ -314,29 +339,25 @@ static int save_files_dirs(const unsigned char *sha1,
314339 struct strbuf * base , const char * path ,
315340 unsigned int mode , int stage , void * context )
316341{
342+ struct path_hashmap_entry * entry ;
317343 int baselen = base -> len ;
318344 struct merge_options * o = context ;
319345
320346 strbuf_addstr (base , path );
321347
322- if (S_ISDIR (mode ))
323- string_list_insert (& o -> current_directory_set , base -> buf );
324- else
325- string_list_insert (& o -> current_file_set , base -> buf );
348+ FLEX_ALLOC_MEM (entry , path , base -> buf , base -> len );
349+ hashmap_entry_init (entry , path_hash (entry -> path ));
350+ hashmap_add (& o -> current_file_dir_set , entry );
326351
327352 strbuf_setlen (base , baselen );
328353 return (S_ISDIR (mode ) ? READ_TREE_RECURSIVE : 0 );
329354}
330355
331- static int get_files_dirs (struct merge_options * o , struct tree * tree )
356+ static void get_files_dirs (struct merge_options * o , struct tree * tree )
332357{
333- int n ;
334358 struct pathspec match_all ;
335359 memset (& match_all , 0 , sizeof (match_all ));
336- if (read_tree_recursive (tree , "" , 0 , 0 , & match_all , save_files_dirs , o ))
337- return 0 ;
338- n = o -> current_file_set .nr + o -> current_directory_set .nr ;
339- return n ;
360+ read_tree_recursive (tree , "" , 0 , 0 , & match_all , save_files_dirs , o );
340361}
341362
342363/*
@@ -646,6 +667,7 @@ static void add_flattened_path(struct strbuf *out, const char *s)
646667
647668static char * unique_path (struct merge_options * o , const char * path , const char * branch )
648669{
670+ struct path_hashmap_entry * entry ;
649671 struct strbuf newpath = STRBUF_INIT ;
650672 int suffix = 0 ;
651673 size_t base_len ;
@@ -654,14 +676,16 @@ static char *unique_path(struct merge_options *o, const char *path, const char *
654676 add_flattened_path (& newpath , branch );
655677
656678 base_len = newpath .len ;
657- while (string_list_has_string (& o -> current_file_set , newpath . buf ) ||
658- string_list_has_string ( & o -> current_directory_set , newpath .buf ) ||
679+ while (hashmap_get_from_hash (& o -> current_file_dir_set ,
680+ path_hash ( newpath . buf ) , newpath .buf ) ||
659681 (!o -> call_depth && file_exists (newpath .buf ))) {
660682 strbuf_setlen (& newpath , base_len );
661683 strbuf_addf (& newpath , "_%d" , suffix ++ );
662684 }
663685
664- string_list_insert (& o -> current_file_set , newpath .buf );
686+ FLEX_ALLOC_MEM (entry , path , newpath .buf , newpath .len );
687+ hashmap_entry_init (entry , path_hash (entry -> path ));
688+ hashmap_add (& o -> current_file_dir_set , entry );
665689 return strbuf_detach (& newpath , NULL );
666690}
667691
@@ -1945,8 +1969,14 @@ int merge_trees(struct merge_options *o,
19451969 if (unmerged_cache ()) {
19461970 struct string_list * entries , * re_head , * re_merge ;
19471971 int i ;
1948- string_list_clear (& o -> current_file_set , 1 );
1949- string_list_clear (& o -> current_directory_set , 1 );
1972+ /*
1973+ * Only need the hashmap while processing entries, so
1974+ * initialize it here and free it when we are done running
1975+ * through the entries. Keeping it in the merge_options as
1976+ * opposed to decaring a local hashmap is for convenience
1977+ * so that we don't have to pass it to around.
1978+ */
1979+ hashmap_init (& o -> current_file_dir_set , path_hashmap_cmp , NULL , 512 );
19501980 get_files_dirs (o , head );
19511981 get_files_dirs (o , merge );
19521982
@@ -1956,16 +1986,18 @@ int merge_trees(struct merge_options *o,
19561986 re_merge = get_renames (o , merge , common , head , merge , entries );
19571987 clean = process_renames (o , re_head , re_merge );
19581988 if (clean < 0 )
1959- return clean ;
1989+ goto cleanup ;
19601990 for (i = entries -> nr - 1 ; 0 <= i ; i -- ) {
19611991 const char * path = entries -> items [i ].string ;
19621992 struct stage_data * e = entries -> items [i ].util ;
19631993 if (!e -> processed ) {
19641994 int ret = process_entry (o , path , e );
19651995 if (!ret )
19661996 clean = 0 ;
1967- else if (ret < 0 )
1968- return ret ;
1997+ else if (ret < 0 ) {
1998+ clean = ret ;
1999+ goto cleanup ;
2000+ }
19692001 }
19702002 }
19712003 for (i = 0 ; i < entries -> nr ; i ++ ) {
@@ -1975,13 +2007,19 @@ int merge_trees(struct merge_options *o,
19752007 entries -> items [i ].string );
19762008 }
19772009
2010+ cleanup :
19782011 string_list_clear (re_merge , 0 );
19792012 string_list_clear (re_head , 0 );
19802013 string_list_clear (entries , 1 );
19812014
2015+ hashmap_free (& o -> current_file_dir_set , 1 );
2016+
19822017 free (re_merge );
19832018 free (re_head );
19842019 free (entries );
2020+
2021+ if (clean < 0 )
2022+ return clean ;
19852023 }
19862024 else
19872025 clean = 1 ;
@@ -2177,8 +2215,6 @@ void init_merge_options(struct merge_options *o)
21772215 if (o -> verbosity >= 5 )
21782216 o -> buffer_output = 0 ;
21792217 strbuf_init (& o -> obuf , 0 );
2180- string_list_init (& o -> current_file_set , 1 );
2181- string_list_init (& o -> current_directory_set , 1 );
21822218 string_list_init (& o -> df_conflict_file_set , 1 );
21832219}
21842220
0 commit comments