|
26 | 26 | #include "argv-array.h"
|
27 | 27 | #include "commit-reach.h"
|
28 | 28 | #include "commit-graph.h"
|
| 29 | +#include "prio-queue.h" |
29 | 30 |
|
30 | 31 | volatile show_early_output_fn_t show_early_output;
|
31 | 32 |
|
@@ -2895,31 +2896,215 @@ static int mark_uninteresting(const struct object_id *oid,
|
2895 | 2896 | return 0;
|
2896 | 2897 | }
|
2897 | 2898 |
|
2898 |
| -struct topo_walk_info {}; |
| 2899 | +define_commit_slab(indegree_slab, int); |
| 2900 | +define_commit_slab(author_date_slab, timestamp_t); |
| 2901 | + |
| 2902 | +struct topo_walk_info { |
| 2903 | + uint32_t min_generation; |
| 2904 | + struct prio_queue explore_queue; |
| 2905 | + struct prio_queue indegree_queue; |
| 2906 | + struct prio_queue topo_queue; |
| 2907 | + struct indegree_slab indegree; |
| 2908 | + struct author_date_slab author_date; |
| 2909 | +}; |
| 2910 | + |
| 2911 | +static inline void test_flag_and_insert(struct prio_queue *q, struct commit *c, int flag) |
| 2912 | +{ |
| 2913 | + if (c->object.flags & flag) |
| 2914 | + return; |
| 2915 | + |
| 2916 | + c->object.flags |= flag; |
| 2917 | + prio_queue_put(q, c); |
| 2918 | +} |
| 2919 | + |
| 2920 | +static void explore_walk_step(struct rev_info *revs) |
| 2921 | +{ |
| 2922 | + struct topo_walk_info *info = revs->topo_walk_info; |
| 2923 | + struct commit_list *p; |
| 2924 | + struct commit *c = prio_queue_get(&info->explore_queue); |
| 2925 | + |
| 2926 | + if (!c) |
| 2927 | + return; |
| 2928 | + |
| 2929 | + if (parse_commit_gently(c, 1) < 0) |
| 2930 | + return; |
| 2931 | + |
| 2932 | + if (revs->sort_order == REV_SORT_BY_AUTHOR_DATE) |
| 2933 | + record_author_date(&info->author_date, c); |
| 2934 | + |
| 2935 | + if (revs->max_age != -1 && (c->date < revs->max_age)) |
| 2936 | + c->object.flags |= UNINTERESTING; |
| 2937 | + |
| 2938 | + if (process_parents(revs, c, NULL, NULL) < 0) |
| 2939 | + return; |
| 2940 | + |
| 2941 | + if (c->object.flags & UNINTERESTING) |
| 2942 | + mark_parents_uninteresting(c); |
| 2943 | + |
| 2944 | + for (p = c->parents; p; p = p->next) |
| 2945 | + test_flag_and_insert(&info->explore_queue, p->item, TOPO_WALK_EXPLORED); |
| 2946 | +} |
| 2947 | + |
| 2948 | +static void explore_to_depth(struct rev_info *revs, |
| 2949 | + uint32_t gen_cutoff) |
| 2950 | +{ |
| 2951 | + struct topo_walk_info *info = revs->topo_walk_info; |
| 2952 | + struct commit *c; |
| 2953 | + while ((c = prio_queue_peek(&info->explore_queue)) && |
| 2954 | + c->generation >= gen_cutoff) |
| 2955 | + explore_walk_step(revs); |
| 2956 | +} |
| 2957 | + |
| 2958 | +static void indegree_walk_step(struct rev_info *revs) |
| 2959 | +{ |
| 2960 | + struct commit_list *p; |
| 2961 | + struct topo_walk_info *info = revs->topo_walk_info; |
| 2962 | + struct commit *c = prio_queue_get(&info->indegree_queue); |
| 2963 | + |
| 2964 | + if (!c) |
| 2965 | + return; |
| 2966 | + |
| 2967 | + if (parse_commit_gently(c, 1) < 0) |
| 2968 | + return; |
| 2969 | + |
| 2970 | + explore_to_depth(revs, c->generation); |
| 2971 | + |
| 2972 | + for (p = c->parents; p; p = p->next) { |
| 2973 | + struct commit *parent = p->item; |
| 2974 | + int *pi = indegree_slab_at(&info->indegree, parent); |
| 2975 | + |
| 2976 | + if (*pi) |
| 2977 | + (*pi)++; |
| 2978 | + else |
| 2979 | + *pi = 2; |
| 2980 | + |
| 2981 | + test_flag_and_insert(&info->indegree_queue, parent, TOPO_WALK_INDEGREE); |
| 2982 | + |
| 2983 | + if (revs->first_parent_only) |
| 2984 | + return; |
| 2985 | + } |
| 2986 | +} |
| 2987 | + |
| 2988 | +static void compute_indegrees_to_depth(struct rev_info *revs, |
| 2989 | + uint32_t gen_cutoff) |
| 2990 | +{ |
| 2991 | + struct topo_walk_info *info = revs->topo_walk_info; |
| 2992 | + struct commit *c; |
| 2993 | + while ((c = prio_queue_peek(&info->indegree_queue)) && |
| 2994 | + c->generation >= gen_cutoff) |
| 2995 | + indegree_walk_step(revs); |
| 2996 | +} |
2899 | 2997 |
|
2900 | 2998 | static void init_topo_walk(struct rev_info *revs)
|
2901 | 2999 | {
|
2902 | 3000 | struct topo_walk_info *info;
|
| 3001 | + struct commit_list *list; |
2903 | 3002 | revs->topo_walk_info = xmalloc(sizeof(struct topo_walk_info));
|
2904 | 3003 | info = revs->topo_walk_info;
|
2905 | 3004 | memset(info, 0, sizeof(struct topo_walk_info));
|
2906 | 3005 |
|
2907 |
| - limit_list(revs); |
2908 |
| - sort_in_topological_order(&revs->commits, revs->sort_order); |
| 3006 | + init_indegree_slab(&info->indegree); |
| 3007 | + memset(&info->explore_queue, 0, sizeof(info->explore_queue)); |
| 3008 | + memset(&info->indegree_queue, 0, sizeof(info->indegree_queue)); |
| 3009 | + memset(&info->topo_queue, 0, sizeof(info->topo_queue)); |
| 3010 | + |
| 3011 | + switch (revs->sort_order) { |
| 3012 | + default: /* REV_SORT_IN_GRAPH_ORDER */ |
| 3013 | + info->topo_queue.compare = NULL; |
| 3014 | + break; |
| 3015 | + case REV_SORT_BY_COMMIT_DATE: |
| 3016 | + info->topo_queue.compare = compare_commits_by_commit_date; |
| 3017 | + break; |
| 3018 | + case REV_SORT_BY_AUTHOR_DATE: |
| 3019 | + init_author_date_slab(&info->author_date); |
| 3020 | + info->topo_queue.compare = compare_commits_by_author_date; |
| 3021 | + info->topo_queue.cb_data = &info->author_date; |
| 3022 | + break; |
| 3023 | + } |
| 3024 | + |
| 3025 | + info->explore_queue.compare = compare_commits_by_gen_then_commit_date; |
| 3026 | + info->indegree_queue.compare = compare_commits_by_gen_then_commit_date; |
| 3027 | + |
| 3028 | + info->min_generation = GENERATION_NUMBER_INFINITY; |
| 3029 | + for (list = revs->commits; list; list = list->next) { |
| 3030 | + struct commit *c = list->item; |
| 3031 | + |
| 3032 | + if (parse_commit_gently(c, 1)) |
| 3033 | + continue; |
| 3034 | + |
| 3035 | + test_flag_and_insert(&info->explore_queue, c, TOPO_WALK_EXPLORED); |
| 3036 | + test_flag_and_insert(&info->indegree_queue, c, TOPO_WALK_INDEGREE); |
| 3037 | + |
| 3038 | + if (c->generation < info->min_generation) |
| 3039 | + info->min_generation = c->generation; |
| 3040 | + |
| 3041 | + *(indegree_slab_at(&info->indegree, c)) = 1; |
| 3042 | + |
| 3043 | + if (revs->sort_order == REV_SORT_BY_AUTHOR_DATE) |
| 3044 | + record_author_date(&info->author_date, c); |
| 3045 | + } |
| 3046 | + compute_indegrees_to_depth(revs, info->min_generation); |
| 3047 | + |
| 3048 | + for (list = revs->commits; list; list = list->next) { |
| 3049 | + struct commit *c = list->item; |
| 3050 | + |
| 3051 | + if (*(indegree_slab_at(&info->indegree, c)) == 1) |
| 3052 | + prio_queue_put(&info->topo_queue, c); |
| 3053 | + } |
| 3054 | + |
| 3055 | + /* |
| 3056 | + * This is unfortunate; the initial tips need to be shown |
| 3057 | + * in the order given from the revision traversal machinery. |
| 3058 | + */ |
| 3059 | + if (revs->sort_order == REV_SORT_IN_GRAPH_ORDER) |
| 3060 | + prio_queue_reverse(&info->topo_queue); |
2909 | 3061 | }
|
2910 | 3062 |
|
2911 | 3063 | static struct commit *next_topo_commit(struct rev_info *revs)
|
2912 | 3064 | {
|
2913 |
| - return pop_commit(&revs->commits); |
| 3065 | + struct commit *c; |
| 3066 | + struct topo_walk_info *info = revs->topo_walk_info; |
| 3067 | + |
| 3068 | + /* pop next off of topo_queue */ |
| 3069 | + c = prio_queue_get(&info->topo_queue); |
| 3070 | + |
| 3071 | + if (c) |
| 3072 | + *(indegree_slab_at(&info->indegree, c)) = 0; |
| 3073 | + |
| 3074 | + return c; |
2914 | 3075 | }
|
2915 | 3076 |
|
2916 | 3077 | static void expand_topo_walk(struct rev_info *revs, struct commit *commit)
|
2917 | 3078 | {
|
2918 |
| - if (process_parents(revs, commit, &revs->commits, NULL) < 0) { |
| 3079 | + struct commit_list *p; |
| 3080 | + struct topo_walk_info *info = revs->topo_walk_info; |
| 3081 | + if (process_parents(revs, commit, NULL, NULL) < 0) { |
2919 | 3082 | if (!revs->ignore_missing_links)
|
2920 | 3083 | die("Failed to traverse parents of commit %s",
|
2921 | 3084 | oid_to_hex(&commit->object.oid));
|
2922 | 3085 | }
|
| 3086 | + |
| 3087 | + for (p = commit->parents; p; p = p->next) { |
| 3088 | + struct commit *parent = p->item; |
| 3089 | + int *pi; |
| 3090 | + |
| 3091 | + if (parse_commit_gently(parent, 1) < 0) |
| 3092 | + continue; |
| 3093 | + |
| 3094 | + if (parent->generation < info->min_generation) { |
| 3095 | + info->min_generation = parent->generation; |
| 3096 | + compute_indegrees_to_depth(revs, info->min_generation); |
| 3097 | + } |
| 3098 | + |
| 3099 | + pi = indegree_slab_at(&info->indegree, parent); |
| 3100 | + |
| 3101 | + (*pi)--; |
| 3102 | + if (*pi == 1) |
| 3103 | + prio_queue_put(&info->topo_queue, parent); |
| 3104 | + |
| 3105 | + if (revs->first_parent_only) |
| 3106 | + return; |
| 3107 | + } |
2923 | 3108 | }
|
2924 | 3109 |
|
2925 | 3110 | int prepare_revision_walk(struct rev_info *revs)
|
|
0 commit comments