summaryrefslogtreecommitdiff
path: root/revision.h
blob: 4f140ca611236bdc4dd32c436616cafe7ef02249 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#ifndef REVISION_H
#define REVISION_H
 
/*
 * The low 16 bits of the "flags" field shows whether
 * a commit is part of the path to the root for that
 * parent.
 *
 * Bit 16 is an internal flag that we've seen the
 * definition for this rev, and not just seen it as
 * a parent target.
 */
#define marked(rev)	((rev)->flags & 0xffff)
#define SEEN 0x10000
#define USED 0x20000
#define REACHABLE 0x40000
 
struct parent {
	struct revision *parent;
	struct parent *next;
};
 
struct revision {
	unsigned int flags;
	unsigned char sha1[20];
	unsigned long date;
	struct parent *parent;
};
 
static struct revision **revs;
static int nr_revs, rev_allocs;
 
static int find_rev(unsigned char *sha1)
{
	int first = 0, last = nr_revs;
 
	while (first < last) {
		int next = (first + last) / 2;
		struct revision *rev = revs[next];
		int cmp;
 
		cmp = memcmp(sha1, rev->sha1, 20);
		if (!cmp)
			return next;
		if (cmp < 0) {
			last = next;
			continue;
		}
		first = next+1;
	}
	return -first-1;
}
 
static struct revision *lookup_rev(unsigned char *sha1)
{
	int pos = find_rev(sha1);
	struct revision *n;
 
	if (pos >= 0)
		return revs[pos];
 
	pos = -pos-1;
 
	if (rev_allocs == nr_revs) {
		rev_allocs = alloc_nr(rev_allocs);
		revs = realloc(revs, rev_allocs * sizeof(struct revision *));
	}
	n = malloc(sizeof(struct revision));
 
	n->flags = 0;
	memcpy(n->sha1, sha1, 20);
	n->parent = NULL;
 
	/* Insert it into the right place */
	memmove(revs + pos + 1, revs + pos, (nr_revs - pos) * sizeof(struct revision *));
	revs[pos] = n;
	nr_revs++;
 
	return n;
}
 
static struct revision *add_relationship(struct revision *rev, unsigned char *needs)
{
	struct revision *parent_rev = lookup_rev(needs);
	struct parent **pp = &rev->parent, *p;
 
	while ((p = *pp) != NULL) {
		if (p->parent == parent_rev)
			return parent_rev;
		pp = &p->next;
	}
 
	p = malloc(sizeof(*p));
	p->parent = parent_rev;
	p->next = NULL;
	*pp = p;
	return parent_rev;
}
 
static void mark_reachable(struct revision *rev)
{
	struct parent *p = rev->parent;
 
	/* If we've been here already, don't bother */
	if (rev->flags & REACHABLE)
		return;
	rev->flags |= REACHABLE | USED;
	while (p) {
		mark_reachable(p->parent);
		p = p->next;
	}
}
 
#endif /* REVISION_H */