+define_commit_slab(indegree_slab, int);
+define_commit_slab(author_date_slab, timestamp_t);
+
+struct topo_walk_info {
+ uint32_t min_generation;
+ struct prio_queue explore_queue;
+ struct prio_queue indegree_queue;
+ struct prio_queue topo_queue;
+ struct indegree_slab indegree;
+ struct author_date_slab author_date;
+};
+
+static inline void test_flag_and_insert(struct prio_queue *q, struct commit *c, int flag)
+{
+ if (c->object.flags & flag)
+ return;
+
+ c->object.flags |= flag;
+ prio_queue_put(q, c);
+}
+
+static void explore_walk_step(struct rev_info *revs)
+{
+ struct topo_walk_info *info = revs->topo_walk_info;
+ struct commit_list *p;
+ struct commit *c = prio_queue_get(&info->explore_queue);
+
+ if (!c)
+ return;
+
+ if (parse_commit_gently(c, 1) < 0)
+ return;
+
+ if (revs->sort_order == REV_SORT_BY_AUTHOR_DATE)
+ record_author_date(&info->author_date, c);
+
+ if (revs->max_age != -1 && (c->date < revs->max_age))
+ c->object.flags |= UNINTERESTING;
+
+ if (process_parents(revs, c, NULL, NULL) < 0)
+ return;
+
+ if (c->object.flags & UNINTERESTING)
+ mark_parents_uninteresting(c);
+
+ for (p = c->parents; p; p = p->next)
+ test_flag_and_insert(&info->explore_queue, p->item, TOPO_WALK_EXPLORED);
+}
+
+static void explore_to_depth(struct rev_info *revs,
+ uint32_t gen_cutoff)
+{
+ struct topo_walk_info *info = revs->topo_walk_info;
+ struct commit *c;
+ while ((c = prio_queue_peek(&info->explore_queue)) &&
+ c->generation >= gen_cutoff)
+ explore_walk_step(revs);
+}
+
+static void indegree_walk_step(struct rev_info *revs)
+{
+ struct commit_list *p;
+ struct topo_walk_info *info = revs->topo_walk_info;
+ struct commit *c = prio_queue_get(&info->indegree_queue);
+
+ if (!c)
+ return;
+
+ if (parse_commit_gently(c, 1) < 0)
+ return;
+
+ explore_to_depth(revs, c->generation);
+
+ for (p = c->parents; p; p = p->next) {
+ struct commit *parent = p->item;
+ int *pi = indegree_slab_at(&info->indegree, parent);
+
+ if (*pi)
+ (*pi)++;
+ else
+ *pi = 2;
+
+ test_flag_and_insert(&info->indegree_queue, parent, TOPO_WALK_INDEGREE);
+
+ if (revs->first_parent_only)
+ return;
+ }
+}
+
+static void compute_indegrees_to_depth(struct rev_info *revs,
+ uint32_t gen_cutoff)
+{
+ struct topo_walk_info *info = revs->topo_walk_info;
+ struct commit *c;
+ while ((c = prio_queue_peek(&info->indegree_queue)) &&
+ c->generation >= gen_cutoff)
+ indegree_walk_step(revs);
+}