@@ -60,13 +60,6 @@ void *fill_tree_descriptor(struct tree_desc *desc, const unsigned char *sha1)
6060 return buf ;
6161}
6262
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-
7063static void entry_clear (struct name_entry * a )
7164{
7265 memset (a , 0 , sizeof (* a ));
@@ -138,66 +131,264 @@ char *make_traverse_path(char *path, const struct traverse_info *info, const str
138131 return path ;
139132}
140133
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+
141310int traverse_trees (int n , struct tree_desc * t , struct traverse_info * info )
142311{
143312 int ret = 0 ;
144313 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 ];
145319
146320 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 ;
150326
151- last = -1 ;
152327 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 )
154341 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 )
164360 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 );
171364 }
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 ;
172373 mask |= 1ul << i ;
173374 if (S_ISDIR (entry [i ].mode ))
174375 dirmask |= 1ul << i ;
175- last = i ;
176376 }
177377 if (!mask )
178378 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- }
189379 ret = info -> fn (n , mask , dirmask , entry , info );
190380 if (ret < 0 )
191381 break ;
192- if (ret )
193- mask &= ret ;
382+ mask &= ret ;
194383 ret = 0 ;
195- for (i = 0 ; i < n ; i ++ ) {
384+ for (i = 0 ; i < n ; i ++ )
196385 if (mask & (1ul << i ))
197- update_tree_entry (t + i );
198- }
386+ update_extended_entry (tx + i , entry + i );
199387 }
200388 free (entry );
389+ for (i = 0 ; i < n ; i ++ )
390+ free_extended_entry (tx + i );
391+ free (tx );
201392 return ret ;
202393}
203394
0 commit comments