@@ -11,6 +11,7 @@ typedef struct config_entry_list {
11
11
struct config_entry_list * next ;
12
12
struct config_entry_list * last ;
13
13
git_config_entry * entry ;
14
+ bool first ;
14
15
} config_entry_list ;
15
16
16
17
typedef struct config_entries_iterator {
@@ -25,31 +26,6 @@ struct git_config_entries {
25
26
config_entry_list * list ;
26
27
};
27
28
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
-
53
29
int git_config_entries_new (git_config_entries * * out )
54
30
{
55
31
git_config_entries * entries ;
@@ -127,12 +103,15 @@ static void config_entries_free(git_config_entries *entries)
127
103
{
128
104
config_entry_list * list = NULL , * next ;
129
105
130
- git_strmap_foreach_value (entries -> map , list , config_entry_list_free (list ));
131
106
git_strmap_free (entries -> map );
132
107
133
108
list = entries -> list ;
134
109
while (list != NULL ) {
135
110
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 );
136
115
git__free (list );
137
116
list = next ;
138
117
}
@@ -148,71 +127,54 @@ void git_config_entries_free(git_config_entries *entries)
148
127
149
128
int git_config_entries_append (git_config_entries * entries , git_config_entry * entry )
150
129
{
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 ;
171
145
} else {
172
- config_entry_list_append ( & existing , var ) ;
146
+ head -> first = 1 ;
173
147
}
174
148
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 ;
189
154
190
- * out = list ;
155
+ if (git_strmap_set (entries -> map , entry -> name , head ) < 0 )
156
+ return -1 ;
191
157
192
158
return 0 ;
193
159
}
194
160
195
161
int git_config_entries_get (git_config_entry * * out , git_config_entries * entries , const char * key )
196
162
{
197
163
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 ;
204
167
return 0 ;
205
168
}
206
169
207
170
int git_config_entries_get_unique (git_config_entry * * out , git_config_entries * entries , const char * key )
208
171
{
209
172
config_entry_list * entry ;
210
- int error ;
211
173
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 ;
214
176
215
- if (entry -> next != NULL ) {
177
+ if (! entry -> first ) {
216
178
git_error_set (GIT_ERROR_CONFIG , "entry is not unique due to being a multivar" );
217
179
return -1 ;
218
180
}
@@ -227,14 +189,14 @@ int git_config_entries_get_unique(git_config_entry **out, git_config_entries *en
227
189
return 0 ;
228
190
}
229
191
230
- void config_iterator_free (git_config_iterator * iter )
192
+ static void config_iterator_free (git_config_iterator * iter )
231
193
{
232
194
config_entries_iterator * it = (config_entries_iterator * ) iter ;
233
195
git_config_entries_free (it -> entries );
234
196
git__free (it );
235
197
}
236
198
237
- int config_iterator_next (
199
+ static int config_iterator_next (
238
200
git_config_entry * * entry ,
239
201
git_config_iterator * iter )
240
202
{
0 commit comments