@@ -60,13 +60,6 @@ void *fill_tree_descriptor(struct tree_desc *desc, const unsigned char *sha1)
60
60
return buf ;
61
61
}
62
62
63
- static int entry_compare (struct name_entry * a , struct name_entry * b )
64
- {
65
- return df_name_compare (
66
- a -> path , tree_entry_len (a -> path , a -> sha1 ), a -> mode ,
67
- b -> path , tree_entry_len (b -> path , b -> sha1 ), b -> mode );
68
- }
69
-
70
63
static void entry_clear (struct name_entry * a )
71
64
{
72
65
memset (a , 0 , sizeof (* a ));
@@ -138,66 +131,264 @@ char *make_traverse_path(char *path, const struct traverse_info *info, const str
138
131
return path ;
139
132
}
140
133
134
+ struct tree_desc_skip {
135
+ struct tree_desc_skip * prev ;
136
+ const void * ptr ;
137
+ };
138
+
139
+ struct tree_desc_x {
140
+ struct tree_desc d ;
141
+ struct tree_desc_skip * skip ;
142
+ };
143
+
144
+ static int name_compare (const char * a , int a_len ,
145
+ const char * b , int b_len )
146
+ {
147
+ int len = (a_len < b_len ) ? a_len : b_len ;
148
+ int cmp = memcmp (a , b , len );
149
+ if (cmp )
150
+ return cmp ;
151
+ return (a_len - b_len );
152
+ }
153
+
154
+ static int check_entry_match (const char * a , int a_len , const char * b , int b_len )
155
+ {
156
+ /*
157
+ * The caller wants to pick *a* from a tree or nothing.
158
+ * We are looking at *b* in a tree.
159
+ *
160
+ * (0) If a and b are the same name, we are trivially happy.
161
+ *
162
+ * There are three possibilities where *a* could be hiding
163
+ * behind *b*.
164
+ *
165
+ * (1) *a* == "t", *b* == "ab" i.e. *b* sorts earlier than *a* no
166
+ * matter what.
167
+ * (2) *a* == "t", *b* == "t-2" and "t" is a subtree in the tree;
168
+ * (3) *a* == "t-2", *b* == "t" and "t-2" is a blob in the tree.
169
+ *
170
+ * Otherwise we know *a* won't appear in the tree without
171
+ * scanning further.
172
+ */
173
+
174
+ int cmp = name_compare (a , a_len , b , b_len );
175
+
176
+ /* Most common case first -- reading sync'd trees */
177
+ if (!cmp )
178
+ return cmp ;
179
+
180
+ if (0 < cmp ) {
181
+ /* a comes after b; it does not matter if it is case (3)
182
+ if (b_len < a_len && !memcmp(a, b, b_len) && a[b_len] < '/')
183
+ return 1;
184
+ */
185
+ return 1 ; /* keep looking */
186
+ }
187
+
188
+ /* b comes after a; are we looking at case (2)? */
189
+ if (a_len < b_len && !memcmp (a , b , a_len ) && b [a_len ] < '/' )
190
+ return 1 ; /* keep looking */
191
+
192
+ return -1 ; /* a cannot appear in the tree */
193
+ }
194
+
195
+ /*
196
+ * From the extended tree_desc, extract the first name entry, while
197
+ * paying attention to the candidate "first" name. Most importantly,
198
+ * when looking for an entry, if there are entries that sorts earlier
199
+ * in the tree object representation than that name, skip them and
200
+ * process the named entry first. We will remember that we haven't
201
+ * processed the first entry yet, and in the later call skip the
202
+ * entry we processed early when update_extended_entry() is called.
203
+ *
204
+ * E.g. if the underlying tree object has these entries:
205
+ *
206
+ * blob "t-1"
207
+ * blob "t-2"
208
+ * tree "t"
209
+ * blob "t=1"
210
+ *
211
+ * and the "first" asks for "t", remember that we still need to
212
+ * process "t-1" and "t-2" but extract "t". After processing the
213
+ * entry "t" from this call, the caller will let us know by calling
214
+ * update_extended_entry() that we can remember "t" has been processed
215
+ * already.
216
+ */
217
+
218
+ static void extended_entry_extract (struct tree_desc_x * t ,
219
+ struct name_entry * a ,
220
+ const char * first ,
221
+ int first_len )
222
+ {
223
+ const char * path ;
224
+ int len ;
225
+ struct tree_desc probe ;
226
+ struct tree_desc_skip * skip ;
227
+
228
+ /*
229
+ * Extract the first entry from the tree_desc, but skip the
230
+ * ones that we already returned in earlier rounds.
231
+ */
232
+ while (1 ) {
233
+ if (!t -> d .size ) {
234
+ entry_clear (a );
235
+ break ; /* not found */
236
+ }
237
+ entry_extract (& t -> d , a );
238
+ for (skip = t -> skip ; skip ; skip = skip -> prev )
239
+ if (a -> path == skip -> ptr )
240
+ break ; /* found */
241
+ if (!skip )
242
+ break ;
243
+ /* We have processed this entry already. */
244
+ update_tree_entry (& t -> d );
245
+ }
246
+
247
+ if (!first || !a -> path )
248
+ return ;
249
+
250
+ /*
251
+ * The caller wants "first" from this tree, or nothing.
252
+ */
253
+ path = a -> path ;
254
+ len = tree_entry_len (a -> path , a -> sha1 );
255
+ switch (check_entry_match (first , first_len , path , len )) {
256
+ case -1 :
257
+ entry_clear (a );
258
+ case 0 :
259
+ return ;
260
+ default :
261
+ break ;
262
+ }
263
+
264
+ /*
265
+ * We need to look-ahead -- we suspect that a subtree whose
266
+ * name is "first" may be hiding behind the current entry "path".
267
+ */
268
+ probe = t -> d ;
269
+ while (probe .size ) {
270
+ entry_extract (& probe , a );
271
+ path = a -> path ;
272
+ len = tree_entry_len (a -> path , a -> sha1 );
273
+ switch (check_entry_match (first , first_len , path , len )) {
274
+ case -1 :
275
+ entry_clear (a );
276
+ case 0 :
277
+ return ;
278
+ default :
279
+ update_tree_entry (& probe );
280
+ break ;
281
+ }
282
+ /* keep looking */
283
+ }
284
+ entry_clear (a );
285
+ }
286
+
287
+ static void update_extended_entry (struct tree_desc_x * t , struct name_entry * a )
288
+ {
289
+ if (t -> d .entry .path == a -> path ) {
290
+ update_tree_entry (& t -> d );
291
+ } else {
292
+ /* we have returned this entry early */
293
+ struct tree_desc_skip * skip = xmalloc (sizeof (* skip ));
294
+ skip -> ptr = a -> path ;
295
+ skip -> prev = t -> skip ;
296
+ t -> skip = skip ;
297
+ }
298
+ }
299
+
300
+ static void free_extended_entry (struct tree_desc_x * t )
301
+ {
302
+ struct tree_desc_skip * p , * s ;
303
+
304
+ for (s = t -> skip ; s ; s = p ) {
305
+ p = s -> prev ;
306
+ free (s );
307
+ }
308
+ }
309
+
141
310
int traverse_trees (int n , struct tree_desc * t , struct traverse_info * info )
142
311
{
143
312
int ret = 0 ;
144
313
struct name_entry * entry = xmalloc (n * sizeof (* entry ));
314
+ int i ;
315
+ struct tree_desc_x * tx = xcalloc (n , sizeof (* tx ));
316
+
317
+ for (i = 0 ; i < n ; i ++ )
318
+ tx [i ].d = t [i ];
145
319
146
320
for (;;) {
147
- unsigned long mask = 0 ;
148
- unsigned long dirmask = 0 ;
149
- int i , last ;
321
+ unsigned long mask , dirmask ;
322
+ const char * first = NULL ;
323
+ int first_len = 0 ;
324
+ struct name_entry * e ;
325
+ int len ;
150
326
151
- last = -1 ;
152
327
for (i = 0 ; i < n ; i ++ ) {
153
- if (!t [i ].size )
328
+ e = entry + i ;
329
+ extended_entry_extract (tx + i , e , NULL , 0 );
330
+ }
331
+
332
+ /*
333
+ * A tree may have "t-2" at the current location even
334
+ * though it may have "t" that is a subtree behind it,
335
+ * and another tree may return "t". We want to grab
336
+ * all "t" from all trees to match in such a case.
337
+ */
338
+ for (i = 0 ; i < n ; i ++ ) {
339
+ e = entry + i ;
340
+ if (!e -> path )
154
341
continue ;
155
- entry_extract (t + i , entry + i );
156
- if (last >= 0 ) {
157
- int cmp = entry_compare (entry + i , entry + last );
158
-
159
- /*
160
- * Is the new name bigger than the old one?
161
- * Ignore it
162
- */
163
- if (cmp > 0 )
342
+ len = tree_entry_len (e -> path , e -> sha1 );
343
+ if (!first ) {
344
+ first = e -> path ;
345
+ first_len = len ;
346
+ continue ;
347
+ }
348
+ if (name_compare (e -> path , len , first , first_len ) < 0 ) {
349
+ first = e -> path ;
350
+ first_len = len ;
351
+ }
352
+ }
353
+
354
+ if (first ) {
355
+ for (i = 0 ; i < n ; i ++ ) {
356
+ e = entry + i ;
357
+ extended_entry_extract (tx + i , e , first , first_len );
358
+ /* Cull the ones that are not the earliest */
359
+ if (!e -> path )
164
360
continue ;
165
- /*
166
- * Is the new name smaller than the old one?
167
- * Ignore all old ones
168
- */
169
- if (cmp < 0 )
170
- mask = 0 ;
361
+ len = tree_entry_len (e -> path , e -> sha1 );
362
+ if (name_compare (e -> path , len , first , first_len ))
363
+ entry_clear (e );
171
364
}
365
+ }
366
+
367
+ /* Now we have in entry[i] the earliest name from the trees */
368
+ mask = 0 ;
369
+ dirmask = 0 ;
370
+ for (i = 0 ; i < n ; i ++ ) {
371
+ if (!entry [i ].path )
372
+ continue ;
172
373
mask |= 1ul << i ;
173
374
if (S_ISDIR (entry [i ].mode ))
174
375
dirmask |= 1ul << i ;
175
- last = i ;
176
376
}
177
377
if (!mask )
178
378
break ;
179
- dirmask &= mask ;
180
-
181
- /*
182
- * Clear all the unused name-entries.
183
- */
184
- for (i = 0 ; i < n ; i ++ ) {
185
- if (mask & (1ul << i ))
186
- continue ;
187
- entry_clear (entry + i );
188
- }
189
379
ret = info -> fn (n , mask , dirmask , entry , info );
190
380
if (ret < 0 )
191
381
break ;
192
- if (ret )
193
- mask &= ret ;
382
+ mask &= ret ;
194
383
ret = 0 ;
195
- for (i = 0 ; i < n ; i ++ ) {
384
+ for (i = 0 ; i < n ; i ++ )
196
385
if (mask & (1ul << i ))
197
- update_tree_entry (t + i );
198
- }
386
+ update_extended_entry (tx + i , entry + i );
199
387
}
200
388
free (entry );
389
+ for (i = 0 ; i < n ; i ++ )
390
+ free_extended_entry (tx + i );
391
+ free (tx );
201
392
return ret ;
202
393
}
203
394
0 commit comments