@@ -11,6 +11,7 @@ typedef struct config_entry_list {
1111 struct config_entry_list * next ;
1212 struct config_entry_list * last ;
1313 git_config_entry * entry ;
14+ bool first ;
1415} config_entry_list ;
1516
1617typedef struct config_entries_iterator {
@@ -25,31 +26,6 @@ struct git_config_entries {
2526 config_entry_list * list ;
2627};
2728
28- static void config_entry_list_free (config_entry_list * list )
29- {
30- config_entry_list * next ;
31-
32- while (list != NULL ) {
33- next = list -> next ;
34-
35- git__free ((char * ) list -> entry -> name );
36- git__free ((char * ) list -> entry -> value );
37- git__free (list -> entry );
38- git__free (list );
39-
40- list = next ;
41- };
42- }
43-
44- static void config_entry_list_append (config_entry_list * * list , config_entry_list * entry )
45- {
46- if (* list )
47- (* list )-> last -> next = entry ;
48- else
49- * list = entry ;
50- (* list )-> last = entry ;
51- }
52-
5329int git_config_entries_new (git_config_entries * * out )
5430{
5531 git_config_entries * entries ;
@@ -127,12 +103,15 @@ static void config_entries_free(git_config_entries *entries)
127103{
128104 config_entry_list * list = NULL , * next ;
129105
130- git_strmap_foreach_value (entries -> map , list , config_entry_list_free (list ));
131106 git_strmap_free (entries -> map );
132107
133108 list = entries -> list ;
134109 while (list != NULL ) {
135110 next = list -> next ;
111+ if (list -> first )
112+ git__free ((char * ) list -> entry -> name );
113+ git__free ((char * ) list -> entry -> value );
114+ git__free (list -> entry );
136115 git__free (list );
137116 list = next ;
138117 }
@@ -148,71 +127,54 @@ void git_config_entries_free(git_config_entries *entries)
148127
149128int git_config_entries_append (git_config_entries * entries , git_config_entry * entry )
150129{
151- config_entry_list * existing , * var ;
152- int error = 0 ;
153-
154- var = git__calloc (1 , sizeof (config_entry_list ));
155- GIT_ERROR_CHECK_ALLOC (var );
156- var -> entry = entry ;
157-
158- if ((existing = git_strmap_get (entries -> map , entry -> name )) == NULL ) {
159- /*
160- * We only ever inspect `last` from the first config
161- * entry in a multivar. In case where this new entry is
162- * the first one in the entry map, it will also be the
163- * last one at the time of adding it, which is
164- * why we set `last` here to itself. Otherwise we
165- * do not have to set `last` and leave it set to
166- * `NULL`.
167- */
168- var -> last = var ;
169-
170- error = git_strmap_set (entries -> map , entry -> name , var );
130+ config_entry_list * existing , * head ;
131+
132+ head = git__calloc (1 , sizeof (config_entry_list ));
133+ GIT_ERROR_CHECK_ALLOC (head );
134+ head -> entry = entry ;
135+
136+ /*
137+ * This is a micro-optimization for configuration files
138+ * with a lot of same keys. As for multivars the entry's
139+ * key will be the same for all entries, we can just free
140+ * all except the first entry's name and just re-use it.
141+ */
142+ if ((existing = git_strmap_get (entries -> map , entry -> name )) != NULL ) {
143+ git__free ((char * ) entry -> name );
144+ entry -> name = existing -> entry -> name ;
171145 } else {
172- config_entry_list_append ( & existing , var ) ;
146+ head -> first = 1 ;
173147 }
174148
175- var = git__calloc (1 , sizeof (config_entry_list ));
176- GIT_ERROR_CHECK_ALLOC (var );
177- var -> entry = entry ;
178- config_entry_list_append (& entries -> list , var );
179-
180- return error ;
181- }
182-
183- int config_entry_get (config_entry_list * * out , git_config_entries * entries , const char * key )
184- {
185- config_entry_list * list ;
186-
187- if ((list = git_strmap_get (entries -> map , key )) == NULL )
188- return GIT_ENOTFOUND ;
149+ if (entries -> list )
150+ entries -> list -> last -> next = head ;
151+ else
152+ entries -> list = head ;
153+ entries -> list -> last = head ;
189154
190- * out = list ;
155+ if (git_strmap_set (entries -> map , entry -> name , head ) < 0 )
156+ return -1 ;
191157
192158 return 0 ;
193159}
194160
195161int git_config_entries_get (git_config_entry * * out , git_config_entries * entries , const char * key )
196162{
197163 config_entry_list * entry ;
198- int error ;
199-
200- if ((error = config_entry_get (& entry , entries , key )) < 0 )
201- return error ;
202- * out = entry -> last -> entry ;
203-
164+ if ((entry = git_strmap_get (entries -> map , key )) == NULL )
165+ return GIT_ENOTFOUND ;
166+ * out = entry -> entry ;
204167 return 0 ;
205168}
206169
207170int git_config_entries_get_unique (git_config_entry * * out , git_config_entries * entries , const char * key )
208171{
209172 config_entry_list * entry ;
210- int error ;
211173
212- if ((error = config_entry_get ( & entry , entries , key )) < 0 )
213- return error ;
174+ if ((entry = git_strmap_get ( entries -> map , key )) == NULL )
175+ return GIT_ENOTFOUND ;
214176
215- if (entry -> next != NULL ) {
177+ if (! entry -> first ) {
216178 git_error_set (GIT_ERROR_CONFIG , "entry is not unique due to being a multivar" );
217179 return -1 ;
218180 }
@@ -227,14 +189,14 @@ int git_config_entries_get_unique(git_config_entry **out, git_config_entries *en
227189 return 0 ;
228190}
229191
230- void config_iterator_free (git_config_iterator * iter )
192+ static void config_iterator_free (git_config_iterator * iter )
231193{
232194 config_entries_iterator * it = (config_entries_iterator * ) iter ;
233195 git_config_entries_free (it -> entries );
234196 git__free (it );
235197}
236198
237- int config_iterator_next (
199+ static int config_iterator_next (
238200 git_config_entry * * entry ,
239201 git_config_iterator * iter )
240202{
0 commit comments