More work. Much clearer now... not yet complete though.

This commit is contained in:
Pietro Gagliardi 2016-12-17 23:07:48 -05:00
parent 2f449887d8
commit 4c99899a1d
1 changed files with 100 additions and 3 deletions

View File

@ -53,10 +53,36 @@ static void linkInsertBefore(struct attrlist *alist, struct attr *what, struct a
a->prev->next = a;
}
static int attrHasPos(struct attr *a, size_t pos)
{
if (pos < a->start)
return 0;
return pos < a->end;
}
// returns 1 if there was an intersection and 0 otherwise
static int attrRangeIntersect(struct attr *a, size_t *start, size_t *end)
{
// is the range outside a entirely?
if (*start >= a->end)
return 0;
if (*end < a->start)
return 0;
// okay, so there is an overlap
// compute the intersection
if (*start < a->start)
*start = a->start;
if (*end > a->end)
*end = a->end;
return 1;
}
#if 0
void attrlistInsertAt(struct attrlist *alist, uiAttribute type, uintptr_t val, size_t start, size_t end)
{
struct attr *a;
struct attr *after;
struct attr *before;
a = uiNew(struct attr);
a->type = type;
@ -65,10 +91,81 @@ void attrlistInsertAt(struct attrlist *alist, uiAttribute type, uintptr_t val, s
a->end = end;
// place a before the first element that starts after a does
for (before = alist->first; before != NULL; before = before->next)
for (before = alist->first; before != NULL; before = before->next) {
size_t lstart, lend;
if (before->start > a->start)
break;
// TODO this does not handle cases where the attribute overwrites an existing attribute
// if this attribute overrides another, we have to split
lstart = start;
lend = end;
if (!attrRangeIntersect(before, &lstart, &lend))
continue;
if (before->type != type)
continue;
if (before->val == val)
continue;
// TODO now split around start/end and drop the overlap
}
linkInsertBefore(alist, a, before);
// TODO see if adding this attribute leads to a fragmented contiguous run
}
#endif
void attrlistInsertAt(struct attrlist *alist, uiAttribute type, uintptr_t val, size_t start, size_t end)
{
struct attr *a;
struct attr *before;
struct attr *tail = NULL;
// first, figure out where in the list this should go
// in addition, if this attribute overrides one that already exists, split that one apart so this one can take over
before = alist->first;
while (before != NULL) {
size_t lstart, lend;
// once we get to the first point after start, we know where to insert
if (before->start > start)
break;
// if we have already split a prior instance of this attribute, don't bother doing it again
if (tail != NULL)
goto next;
// should we split this?
if (before->type != type)
goto next;
lstart = start;
lend = end;
if (!attrRangeIntersects(before, &lstart, &lend))
goto next;
// okay so this might conflict; if the val is the same as the one we want, we need to expand the existing attribute, not fragment anything
// TODO this might cause problems with system specific attributes, if we support those; maybe also user-specific?
if (before->val == val) {
// TODO
}
// okay the values are different; we need to split apart
// TODO
next:
before = before->next;
}
// if we got here, we know we have to add the attribute before before
a = uiNew(struct attr);
a->type = type;
a->val = val;
a->start = start;
a->end = end;
linkInsertBefore(alist, a, before);
// and finally, if we split, insert the remainder
if (tail == NULL)
return;
// note we start at before; it won't be inserted before that by the sheer nature of how the code above works
for (; before != NULL; before = before->next)
if (before->start > tail->start)
break;
linkInsertBefore(alist, tail, before);
}