version 1.7, 2001/04/18 17:57:28 |
version 1.8, 2001/04/30 21:03:55 |
|
|
* heap. The resulting complexity is O(e+v log v) for the worst case. |
* heap. The resulting complexity is O(e+v log v) for the worst case. |
* The average should actually be near O(e). |
* The average should actually be near O(e). |
* |
* |
|
* If the hints file is incomplete, there is some extra complexity incurred |
|
* by make_transparent, which does propagate order values to unmarked |
|
* nodes. In the worst case, make_transparent is O(e u), |
|
* where u is the number of originally unmarked nodes. |
|
* In practice, it is much faster. |
|
* |
* The simple topological sort algorithm detects cycles. This program |
* The simple topological sort algorithm detects cycles. This program |
* goes further, breaking cycles through the use of simple heuristics. |
* goes further, breaking cycles through the use of simple heuristics. |
* Each cycle break checks the whole set of nodes, hence if c cycles break |
* Each cycle break checks the whole set of nodes, hence if c cycles break |
|
|
static struct node *new_node __P((const char *, const char *)); |
static struct node *new_node __P((const char *, const char *)); |
|
|
static unsigned int read_pairs __P((FILE *, struct ohash *, int, |
static unsigned int read_pairs __P((FILE *, struct ohash *, int, |
const char *, unsigned int)); |
const char *, unsigned int, int)); |
static void split_nodes __P((struct ohash *, struct array *, struct array *)); |
static void split_nodes __P((struct ohash *, struct array *, struct array *)); |
|
static void make_transparent __P((struct ohash *)); |
static void insert_arc __P((struct node *, struct node *)); |
static void insert_arc __P((struct node *, struct node *)); |
|
|
#ifdef DEBUG |
#ifdef DEBUG |
|
|
|
|
if (n->refs == 0) |
if (n->refs == 0) |
return; |
return; |
printf("%s (%u): ", n->k, n->refs); |
printf("%s (%u/%u): ", n->k, n->order, n->refs); |
for (l = n->arcs; l != NULL; l = l->next) |
for (l = n->arcs; l != NULL; l = l->next) |
if (n->refs != 0) |
if (n->refs != 0) |
printf("%s(%u) ", l->node->k, l->node->refs); |
printf("%s(%u/%u) ", l->node->k, l->node->order, l->node->refs); |
putchar('\n'); |
putchar('\n'); |
} |
} |
|
|
|
|
|
|
static void |
static void |
dump_hash(h) |
dump_hash(h) |
struct hash *h; |
struct ohash *h; |
{ |
{ |
unsigned int i; |
unsigned int i; |
struct node *n; |
struct node *n; |
|
|
} |
} |
|
|
static unsigned int |
static unsigned int |
read_pairs(f, h, reverse, name, order) |
read_pairs(f, h, reverse, name, order, hint) |
FILE *f; |
FILE *f; |
struct ohash *h; |
struct ohash *h; |
int reverse; |
int reverse; |
const char *name; |
const char *name; |
unsigned int order; |
unsigned int order; |
|
int hint; |
{ |
{ |
int toggle; |
int toggle; |
struct node *a; |
struct node *a; |
|
|
continue; |
continue; |
if (toggle) { |
if (toggle) { |
a = node_lookup(h, str, e); |
a = node_lookup(h, str, e); |
if (a->order == NO_ORDER) |
if (a->order == NO_ORDER && hint) |
a->order = order++; |
a->order = order++; |
} else { |
} else { |
struct node *b; |
struct node *b; |
|
|
unsigned int i; |
unsigned int i; |
|
|
for (i = h->entries; i != 0;) { |
for (i = h->entries; i != 0;) { |
if (h->t[--i]->order == 0 && verbose) |
if (h->t[--i]->order == NO_ORDER && verbose) |
warnx("node %s absent from hints file", h->t[i]->k); |
warnx("node %s absent from hints file", h->t[i]->k); |
heap_down(h, i); |
heap_down(h, i); |
} |
} |
|
|
} |
} |
} |
} |
|
|
|
/* Nodes without order should not hinder direct dependencies. |
|
* Iterate until no nodes are left. |
|
*/ |
|
static void |
|
make_transparent(hash) |
|
struct ohash *hash; |
|
{ |
|
struct node *n; |
|
unsigned int i; |
|
struct link *l; |
|
int adjusted; |
|
int bad; |
|
unsigned int min; |
|
|
|
/* first try to solve complete nodes */ |
|
do { |
|
adjusted = 0; |
|
bad = 0; |
|
for (n = ohash_first(hash, &i); n != NULL; |
|
n = ohash_next(hash, &i)) { |
|
if (n->order == NO_ORDER) { |
|
min = NO_ORDER; |
|
|
|
for (l = n->arcs; l != NULL; l = l->next) { |
|
/* unsolved node -> delay resolution */ |
|
if (l->node->order == NO_ORDER) { |
|
bad = 1; |
|
break; |
|
} else if (l->node->order < min) |
|
min = l->node->order; |
|
} |
|
if (min < NO_ORDER && l == NULL) { |
|
n->order = min; |
|
adjusted = 1; |
|
} |
|
} |
|
} |
|
|
|
} while (adjusted); |
|
|
|
/* then, if incomplete nodes are left, do them */ |
|
if (bad) do { |
|
adjusted = 0; |
|
for (n = ohash_first(hash, &i); n != NULL; |
|
n = ohash_next(hash, &i)) |
|
if (n->order == NO_ORDER) |
|
for (l = n->arcs; l != NULL; l = l->next) |
|
if (l->node->order < n->order) { |
|
n->order = l->node->order; |
|
adjusted = 1; |
|
} |
|
} while (adjusted); |
|
} |
|
|
|
|
/*** |
/*** |
*** Search through hash array for nodes. |
*** Search through hash array for nodes. |
|
|
|
|
struct node *n; |
struct node *n; |
unsigned int i; |
unsigned int i; |
|
unsigned int total = ohash_entries(hash); |
|
|
heap->t = emalloc(sizeof(struct node *) * ohash_entries(hash)); |
heap->t = emalloc(sizeof(struct node *) * ohash_entries(hash)); |
remaining->t = emalloc(sizeof(struct node *) * ohash_entries(hash)); |
|
heap->entries = 0; |
heap->entries = 0; |
remaining->entries = 0; |
remaining->entries = 0; |
|
|
|
|
if (n->refs == 0) |
if (n->refs == 0) |
heap->t[heap->entries++] = n; |
heap->t[heap->entries++] = n; |
else |
else |
remaining->t[remaining->entries++] = n; |
heap->t[total-1-remaining->entries++] = n; |
} |
} |
|
remaining->t = heap->t + heap->entries; |
} |
} |
|
|
/* Good point to break a cycle: live node with as few refs as possible. */ |
/* Good point to break a cycle: live node with as few refs as possible. */ |
|
|
warn_flag, hints_flag, verbose_flag; |
warn_flag, hints_flag, verbose_flag; |
unsigned int order; |
unsigned int order; |
|
|
order = 1; |
order = 0; |
|
|
reverse_flag = quiet_flag = long_flag = |
reverse_flag = quiet_flag = long_flag = |
warn_flag = hints_flag = verbose_flag = 0; |
warn_flag = hints_flag = verbose_flag = 0; |
|
|
optarg, order); |
optarg, order); |
fclose(f); |
fclose(f); |
} |
} |
|
hints_flag = 1; |
|
break; |
/*FALLTHRU*/ |
/*FALLTHRU*/ |
case 'f': |
case 'f': |
if (hints_flag == 1) |
hints_flag = 2; |
usage(); |
|
hints_flag = 1; |
|
break; |
break; |
case 'l': |
case 'l': |
long_flag = 1; |
long_flag = 1; |
|
|
f = fopen(argv[0], "r"); |
f = fopen(argv[0], "r"); |
if (f == NULL) |
if (f == NULL) |
err(EX_NOINPUT, "Can't open file %s", argv[1]); |
err(EX_NOINPUT, "Can't open file %s", argv[1]); |
order = read_pairs(f, &pairs, reverse_flag, argv[1], order); |
order = read_pairs(f, &pairs, reverse_flag, argv[1], order, |
|
hints_flag == 2); |
fclose(f); |
fclose(f); |
break; |
break; |
} |
} |
case 0: |
case 0: |
order = read_pairs(stdin, &pairs, reverse_flag, "stdin", order); |
order = read_pairs(stdin, &pairs, reverse_flag, "stdin", |
|
order, hints_flag == 2); |
break; |
break; |
default: |
default: |
usage(); |
usage(); |
|
|
broken_arcs = 0; |
broken_arcs = 0; |
broken_cycles = 0; |
broken_cycles = 0; |
|
|
|
if (hints_flag) |
|
make_transparent(&pairs); |
split_nodes(&pairs, &aux, &remaining); |
split_nodes(&pairs, &aux, &remaining); |
ohash_delete(&pairs); |
ohash_delete(&pairs); |
|
|