summaryrefslogtreecommitdiff
path: root/src/cplxdeps.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cplxdeps.c')
-rw-r--r--src/cplxdeps.c404
1 files changed, 187 insertions, 217 deletions
diff --git a/src/cplxdeps.c b/src/cplxdeps.c
index aadbc48..6c40752 100644
--- a/src/cplxdeps.c
+++ b/src/cplxdeps.c
@@ -29,7 +29,7 @@ pool_is_complex_dep_rd(Pool *pool, Reldep *rd)
{
for (;;)
{
- if (rd->flags == REL_AND || rd->flags == REL_COND) /* those two are the complex ones */
+ if (rd->flags == REL_AND || rd->flags == REL_COND || rd->flags == REL_UNLESS) /* those two are the complex ones */
return 1;
if (rd->flags != REL_OR)
return 0;
@@ -127,6 +127,167 @@ invert_depblocks(Pool *pool, Queue *bq, int start, int r)
return -1;
}
+/* distributive property: (a1*a2 + b1*b2) * (c1*c2 + d1*d2) =
+ a1*a2*c1*c2 + a1*a2*d1*d2 + b1*b2*c1*c2 + b1*b2*d1*d2 */
+static int
+distribute_depblocks(Pool *pool, Queue *bq, int bqcnt, int bqcnt2, int flags)
+{
+ int i, j, bqcnt3;
+#ifdef CPLXDEBUG
+ printf("COMPLEX DISTRIBUTE %d %d %d\n", bqcnt, bqcnt2, bq->count);
+#endif
+ bqcnt2 = expand_simpledeps(pool, bq, bqcnt, bqcnt2);
+ bqcnt3 = bq->count;
+ for (i = bqcnt; i < bqcnt2; i++)
+ {
+ for (j = bqcnt2; j < bqcnt3; j++)
+ {
+ int a, b;
+ int bqcnt4 = bq->count;
+ int k = i;
+
+ /* mix i block with j block, both blocks are sorted */
+ while (bq->elements[k] && bq->elements[j])
+ {
+ if (bq->elements[k] < bq->elements[j])
+ queue_push(bq, bq->elements[k++]);
+ else
+ {
+ if (bq->elements[k] == bq->elements[j])
+ k++;
+ queue_push(bq, bq->elements[j++]);
+ }
+ }
+ while (bq->elements[j])
+ queue_push(bq, bq->elements[j++]);
+ while (bq->elements[k])
+ queue_push(bq, bq->elements[k++]);
+
+ /* block is finished, check for A + -A */
+ for (a = bqcnt4, b = bq->count - 1; a < b; )
+ {
+ if (-bq->elements[a] == bq->elements[b])
+ break;
+ if (-bq->elements[a] > bq->elements[b])
+ a++;
+ else
+ b--;
+ }
+ if (a < b)
+ queue_truncate(bq, bqcnt4); /* ignore this block */
+ else
+ queue_push(bq, 0); /* finish block */
+ }
+ /* advance to next block */
+ while (bq->elements[i])
+ i++;
+ }
+ queue_deleten(bq, bqcnt, bqcnt3 - bqcnt);
+ if (bqcnt == bq->count)
+ return flags & CPLXDEPS_TODNF ? 0 : 1;
+ return -1;
+}
+
+static int normalize_dep(Pool *pool, Id dep, Queue *bq, int flags);
+
+static int
+normalize_dep_or(Pool *pool, Id dep1, Id dep2, Queue *bq, int flags, int invflags)
+{
+ int r1, r2, bqcnt2, bqcnt = bq->count;
+ r1 = normalize_dep(pool, dep1, bq, flags);
+ if (r1 == 1)
+ return 1; /* early exit */
+ bqcnt2 = bq->count;
+ r2 = normalize_dep(pool, dep2, bq, flags ^ invflags);
+ if (invflags)
+ r2 = invert_depblocks(pool, bq, bqcnt2, r2);
+ if (r1 == 1 || r2 == 1)
+ {
+ queue_truncate(bq, bqcnt);
+ return 1;
+ }
+ if (r1 == 0)
+ return r2;
+ if (r2 == 0)
+ return r1;
+ if ((flags & CPLXDEPS_TODNF) == 0)
+ return distribute_depblocks(pool, bq, bqcnt, bqcnt2, flags);
+ return -1;
+}
+
+static int
+normalize_dep_and(Pool *pool, Id dep1, Id dep2, Queue *bq, int flags, int invflags)
+{
+ int r1, r2, bqcnt2, bqcnt = bq->count;
+ r1 = normalize_dep(pool, dep1, bq, flags);
+ if (r1 == 0)
+ return 0; /* early exit */
+ bqcnt2 = bq->count;
+ r2 = normalize_dep(pool, dep2, bq, flags ^ invflags);
+ if (invflags)
+ r2 = invert_depblocks(pool, bq, bqcnt2, r2);
+ if (r1 == 0 || r2 == 0)
+ {
+ queue_truncate(bq, bqcnt);
+ return 0;
+ }
+ if (r1 == 1)
+ return r2;
+ if (r2 == 1)
+ return r1;
+ if ((flags & CPLXDEPS_TODNF) != 0)
+ return distribute_depblocks(pool, bq, bqcnt, bqcnt2, flags);
+ return -1;
+}
+
+static int
+normalize_dep_if_else(Pool *pool, Id dep1, Id dep2, Id dep3, Queue *bq, int flags)
+{
+ /* A IF (B ELSE C) -> (A OR ~B) AND (C OR B) */
+ int r1, r2, bqcnt2, bqcnt = bq->count;
+ r1 = normalize_dep_or(pool, dep1, dep2, bq, flags, CPLXDEPS_TODNF);
+ if (r1 == 0)
+ return 0; /* early exit */
+ bqcnt2 = bq->count;
+ r2 = normalize_dep_or(pool, dep2, dep3, bq, flags, 0);
+ if (r1 == 0 || r2 == 0)
+ {
+ queue_truncate(bq, bqcnt);
+ return 0;
+ }
+ if (r1 == 1)
+ return r2;
+ if (r2 == 1)
+ return r1;
+ if ((flags & CPLXDEPS_TODNF) != 0)
+ return distribute_depblocks(pool, bq, bqcnt, bqcnt2, flags);
+ return -1;
+}
+
+static int
+normalize_dep_unless_else(Pool *pool, Id dep1, Id dep2, Id dep3, Queue *bq, int flags)
+{
+ /* A UNLESS (B ELSE C) -> (A AND ~B) OR (C AND B) */
+ int r1, r2, bqcnt2, bqcnt = bq->count;
+ r1 = normalize_dep_and(pool, dep1, dep2, bq, flags, CPLXDEPS_TODNF);
+ if (r1 == 1)
+ return 1; /* early exit */
+ bqcnt2 = bq->count;
+ r2 = normalize_dep_and(pool, dep2, dep3, bq, flags, 0);
+ if (r1 == 1 || r2 == 1)
+ {
+ queue_truncate(bq, bqcnt);
+ return 1;
+ }
+ if (r1 == 0)
+ return r2;
+ if (r2 == 0)
+ return r1;
+ if ((flags & CPLXDEPS_TODNF) == 0)
+ return distribute_depblocks(pool, bq, bqcnt, bqcnt2, flags);
+ return -1;
+}
+
/*
* returns:
* 0: no blocks
@@ -136,229 +297,38 @@ invert_depblocks(Pool *pool, Queue *bq, int start, int r)
static int
normalize_dep(Pool *pool, Id dep, Queue *bq, int flags)
{
- int bqcnt = bq->count;
- int bqcnt2;
- int todnf = flags & CPLXDEPS_TODNF ? 1 : 0;
Id p, dp;
+ int bqcnt;
-#ifdef CPLXDEBUG
- printf("normalize_dep %s todnf:%d\n", pool_dep2str(pool, dep), todnf);
-#endif
if (pool_is_complex_dep(pool, dep))
{
Reldep *rd = GETRELDEP(pool, dep);
- if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_COND)
+ if (rd->flags == REL_COND)
{
- int rdflags = rd->flags;
- Id name = rd->name;
Id evr = rd->evr;
- int r, mode;
-
- if (rdflags == REL_COND)
- {
- /* check for relly complex ELSE case */
- if (ISRELDEP(evr))
- {
- Reldep *rd2 = GETRELDEP(pool, evr);
- if (rd2->flags == REL_ELSE)
- {
- int r2;
- /* really complex case */
- if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_AND_1)
- {
- /* A OR ~B */
- rdflags = REL_COND;
- evr = rd2->name;
- }
- else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_AND_2)
- {
- /* C OR B */
- rdflags = REL_OR;
- name = rd2->evr;
- evr = rd2->name;
- }
- else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_OR_1)
- {
- /* A AND B */
- rdflags = REL_AND;
- evr = rd2->name;
- }
- else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_OR_2)
- {
- /* A AND C */
- rdflags = REL_AND;
- evr = rd2->evr;
- }
- else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_OR_3)
- {
- /* C AND ~B */
- rdflags = REL_ELSE;
- name = rd2->evr;
- evr = rd2->name;
- }
- else if (!todnf)
- {
- /* we want AND: A IF (B ELSE C) -> (A OR ~B) AND (C OR B) */
- r = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_AND_1);
- if (r == 0 && (flags & CPLXDEPS_DONTFIX) == 0)
- return 0;
- r2 = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_AND_2);
- if (r2 == 0 && (flags & CPLXDEPS_DONTFIX) == 0)
- {
- queue_truncate(bq, bqcnt);
- return 0;
- }
- if (r == -1 || r2 == -1)
- return -1;
- return r == 1 || r2 == 1 ? 1 : 0;
- }
- else
- {
- int r2, r3;
- /* we want OR: A IF (B ELSE C) -> (A AND B) OR (A AND C) OR (~B AND C) */
- r = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_OR_1);
- if (r == 1)
- return 1;
- r2 = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_OR_2);
- if (r2 == 1)
- {
- queue_truncate(bq, bqcnt);
- return 1;
- }
- r3 = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_OR_3);
- if (r3 == 1)
- {
- queue_truncate(bq, bqcnt);
- return 1;
- }
- if (r == -1 || r2 == -1 || r3 == -1)
- return -1;
- return 0;
- }
- }
- }
- }
- mode = rdflags == REL_AND || rdflags == REL_ELSE ? 0 : 1;
-
- /* get blocks of first argument */
- r = normalize_dep(pool, name, bq, flags);
- if (r == 0)
- {
- if (rdflags == REL_ELSE)
- return 0;
- if (rdflags == REL_AND && (flags & CPLXDEPS_DONTFIX) == 0)
- return 0;
- if (rdflags == REL_COND)
- {
- r = normalize_dep(pool, evr, bq, (flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX);
- return invert_depblocks(pool, bq, bqcnt, r); /* invert block for COND */
- }
- return normalize_dep(pool, evr, bq, flags);
- }
- if (r == 1)
- {
- if (rdflags == REL_ELSE)
- {
- r = normalize_dep(pool, evr, bq, (flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX);
- return invert_depblocks(pool, bq, bqcnt, r); /* invert block for ELSE */
- }
- if (rdflags == REL_OR || rdflags == REL_COND)
- return 1;
- return normalize_dep(pool, evr, bq, flags);
- }
-
- /* get blocks of second argument */
- bqcnt2 = bq->count;
- /* COND is OR with NEG on evr block, so we invert the todnf flag in that case */
- r = normalize_dep(pool, evr, bq, rdflags == REL_COND || rdflags == REL_ELSE ? ((flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX) : flags);
- if (rdflags == REL_COND || rdflags == REL_ELSE)
- r = invert_depblocks(pool, bq, bqcnt2, r); /* invert 2nd block */
- if (r == 0)
+ if (ISRELDEP(evr))
{
- if (rdflags == REL_OR)
- return -1;
- if (rdflags == REL_AND && (flags & CPLXDEPS_DONTFIX) != 0)
- return -1;
- queue_truncate(bq, bqcnt);
- return 0;
- }
- if (r == 1)
- {
- if (rdflags == REL_COND || rdflags == REL_OR)
- {
- queue_truncate(bq, bqcnt);
- return 1;
- }
- return -1;
- }
- if (mode == todnf)
- {
- /* simple case: just join em. nothing more to do here. */
-#ifdef CPLXDEBUG
- printf("SIMPLE JOIN %d %d %d\n", bqcnt, bqcnt2, bq->count);
-#endif
- return -1;
+ Reldep *rd2 = GETRELDEP(pool, evr);
+ if (rd2->flags == REL_ELSE)
+ return normalize_dep_if_else(pool, rd->name, rd2->name, rd2->evr, bq, flags);
}
- else
+ return normalize_dep_or(pool, rd->name, rd->evr, bq, flags, CPLXDEPS_TODNF);
+ }
+ if (rd->flags == REL_UNLESS)
+ {
+ Id evr = rd->evr;
+ if (ISRELDEP(evr))
{
- /* complex case: mix em */
- int i, j, bqcnt3;
-#ifdef CPLXDEBUG
- printf("COMPLEX JOIN %d %d %d\n", bqcnt, bqcnt2, bq->count);
-#endif
- bqcnt2 = expand_simpledeps(pool, bq, bqcnt, bqcnt2);
- bqcnt3 = bq->count;
- for (i = bqcnt; i < bqcnt2; i++)
- {
- for (j = bqcnt2; j < bqcnt3; j++)
- {
- int a, b;
- int bqcnt4 = bq->count;
- int k = i;
-
- /* mix i block with j block, both blocks are sorted */
- while (bq->elements[k] && bq->elements[j])
- {
- if (bq->elements[k] < bq->elements[j])
- queue_push(bq, bq->elements[k++]);
- else
- {
- if (bq->elements[k] == bq->elements[j])
- k++;
- queue_push(bq, bq->elements[j++]);
- }
- }
- while (bq->elements[j])
- queue_push(bq, bq->elements[j++]);
- while (bq->elements[k])
- queue_push(bq, bq->elements[k++]);
-
- /* block is finished, check for A + -A */
- for (a = bqcnt4, b = bq->count - 1; a < b; )
- {
- if (-bq->elements[a] == bq->elements[b])
- break;
- if (-bq->elements[a] > bq->elements[b])
- a++;
- else
- b--;
- }
- if (a < b)
- queue_truncate(bq, bqcnt4); /* ignore this block */
- else
- queue_push(bq, 0); /* finish block */
- }
- /* advance to next block */
- while (bq->elements[i])
- i++;
- }
- i = -1;
- if (bqcnt3 == bq->count) /* ignored all blocks? */
- i = todnf ? 0 : 1;
- queue_deleten(bq, bqcnt, bqcnt3 - bqcnt);
- return i;
+ Reldep *rd2 = GETRELDEP(pool, evr);
+ if (rd2->flags == REL_ELSE)
+ return normalize_dep_unless_else(pool, rd->name, rd2->name, rd2->evr, bq, flags);
}
+ return normalize_dep_and(pool, rd->name, rd->evr, bq, flags, CPLXDEPS_TODNF);
}
+ if (rd->flags == REL_OR)
+ return normalize_dep_or(pool, rd->name, rd->evr, bq, flags, 0);
+ if (rd->flags == REL_AND)
+ return normalize_dep_and(pool, rd->name, rd->evr, bq, flags, 0);
}
/* fallback case: just use package list */
@@ -375,11 +345,11 @@ normalize_dep(Pool *pool, Id dep, Queue *bq, int flags)
if (!pool_match_nevr(pool, pool->solvables + p, dep))
continue;
queue_push(bq, p);
- if (todnf)
+ if ((flags & CPLXDEPS_TODNF) != 0)
queue_push(bq, 0);
}
}
- else if (todnf)
+ else if ((flags & CPLXDEPS_TODNF) != 0)
{
while ((p = pool->whatprovidesdata[dp++]) != 0)
queue_push2(bq, p, 0);
@@ -388,7 +358,7 @@ normalize_dep(Pool *pool, Id dep, Queue *bq, int flags)
queue_push2(bq, pool->nsolvables, dp); /* not yet expanded marker + offset */
if (bq->count == bqcnt)
return 0; /* no provider */
- if (!todnf)
+ if (!(flags & CPLXDEPS_TODNF))
queue_push(bq, 0); /* finish block */
return -1;
}
@@ -423,11 +393,11 @@ pool_add_pos_literals_complex_dep(Pool *pool, Id dep, Queue *q, Map *m, int neg)
while (ISRELDEP(dep))
{
Reldep *rd = GETRELDEP(pool, dep);
- if (rd->flags != REL_AND && rd->flags != REL_OR && rd->flags != REL_COND)
+ if (rd->flags != REL_AND && rd->flags != REL_OR && rd->flags != REL_COND && rd->flags != REL_UNLESS)
break;
pool_add_pos_literals_complex_dep(pool, rd->name, q, m, neg);
dep = rd->evr;
- if (rd->flags == REL_COND)
+ if (rd->flags == REL_COND || rd->flags == REL_UNLESS)
{
neg = !neg;
if (ISRELDEP(dep))