Beispiel #1
0
/*
 * Returns true when moving line 'from' to line 'to' seems to be cost
 * effective. 'blank' indicates whether the line 'to' would become blank.
 */
static inline bool cost_effective(const int from, const int to, const bool blank)
{
    int new_from;

    if (from == to)
	return FALSE;

    new_from = OLDNUM(from);
    if (new_from == _NEWINDEX)
	new_from = from;

    /*
     * On the left side of >= is the cost before moving;
     * on the right side -- cost after moving.
     */
    return (((blank ? update_cost_from_blank(NEWTEXT(to))
		    : update_cost(OLDTEXT(to),NEWTEXT(to)))
	     + update_cost(OLDTEXT(new_from),NEWTEXT(from)))
	 >= ((new_from==from ? update_cost_from_blank(NEWTEXT(from))
			     : update_cost(OLDTEXT(new_from),NEWTEXT(from)))
	     + update_cost(OLDTEXT(from),NEWTEXT(to)))) ? TRUE : FALSE;
}
Beispiel #2
0
_nc_hash_map(void)
{
    HASHMAP *sp;
    register int i;
    int start, shift, size;

    if (screen_lines > lines_alloc) {
	if (hashtab)
	    free(hashtab);
	hashtab = typeMalloc(HASHMAP, (screen_lines + 1) * 2);
	if (!hashtab) {
	    if (oldhash) {
		FreeAndNull(oldhash);
	    }
	    lines_alloc = 0;
	    return;
	}
	lines_alloc = screen_lines;
    }

    if (oldhash && newhash) {
	/* re-hash only changed lines */
	for (i = 0; i < screen_lines; i++) {
	    if (PENDING(i))
		newhash[i] = hash(NEWTEXT(i));
	}
    } else {
	/* re-hash all */
	if (oldhash == 0)
	    oldhash = typeCalloc(unsigned long, (unsigned) screen_lines);
	if (newhash == 0)
	    newhash = typeCalloc(unsigned long, (unsigned) screen_lines);
	if (!oldhash || !newhash)
	    return;		/* malloc failure */
	for (i = 0; i < screen_lines; i++) {
	    newhash[i] = hash(NEWTEXT(i));
	    oldhash[i] = hash(OLDTEXT(i));
	}
    }

#ifdef HASH_VERIFY
    for (i = 0; i < screen_lines; i++) {
	if (newhash[i] != hash(NEWTEXT(i)))
	    fprintf(stderr, "error in newhash[%d]\n", i);
	if (oldhash[i] != hash(OLDTEXT(i)))
	    fprintf(stderr, "error in oldhash[%d]\n", i);
    }
#endif

    /*
     * Set up and count line-hash values.
     */
    memset(hashtab, '\0', sizeof(*hashtab) * (screen_lines + 1) * 2);
    for (i = 0; i < screen_lines; i++) {
	unsigned long hashval = oldhash[i];

	for (sp = hashtab; sp->hashval; sp++)
	    if (sp->hashval == hashval)
		break;
	sp->hashval = hashval;	/* in case this is a new entry */
	sp->oldcount++;
	sp->oldindex = i;
    }
    for (i = 0; i < screen_lines; i++) {
	unsigned long hashval = newhash[i];

	for (sp = hashtab; sp->hashval; sp++)
	    if (sp->hashval == hashval)
		break;
	sp->hashval = hashval;	/* in case this is a new entry */
	sp->newcount++;
	sp->newindex = i;

	OLDNUM(i) = _NEWINDEX;	/* initialize old indices array */
    }

    /*
     * Mark line pairs corresponding to unique hash pairs.
     *
     * We don't mark lines with offset 0, because it can make fail
     * extending hunks by cost_effective. Otherwise, it does not
     * have any side effects.
     */
    for (sp = hashtab; sp->hashval; sp++)
	if (sp->oldcount == 1 && sp->newcount == 1
	    && sp->oldindex != sp->newindex) {
	    TR(TRACE_UPDATE | TRACE_MOVE,
	       ("new line %d is hash-identical to old line %d (unique)",
		sp->newindex, sp->oldindex));
	    OLDNUM(sp->newindex) = sp->oldindex;
	}

    grow_hunks();

    /*
     * Eliminate bad or impossible shifts -- this includes removing
     * those hunks which could not grow because of conflicts, as well
     * those which are to be moved too far, they are likely to destroy
     * more than carry.
     */
    for (i = 0; i < screen_lines;) {
	while (i < screen_lines && OLDNUM(i) == _NEWINDEX)
	    i++;
	if (i >= screen_lines)
	    break;
	start = i;
	shift = OLDNUM(i) - i;
	i++;
	while (i < screen_lines && OLDNUM(i) != _NEWINDEX && OLDNUM(i) - i
	       == shift)
	    i++;
	size = i - start;
	if (size < 3 || size + min(size / 8, 2) < abs(shift)) {
	    while (start < i) {
		OLDNUM(start) = _NEWINDEX;
		start++;
	    }
	}
    }

    /* After clearing invalid hunks, try grow the rest. */
    grow_hunks();
}
Beispiel #3
0
static void
grow_hunks(void)
{
    int start, end, shift;
    int back_limit, forward_limit;	/* limits for cells to fill */
    int back_ref_limit, forward_ref_limit;	/* limits for refrences */
    int i;
    int next_hunk;

    /*
     * This is tricky part.  We have unique pairs to use as anchors.
     * Use these to deduce the presence of spans of identical lines.
     */
    back_limit = 0;
    back_ref_limit = 0;

    i = 0;
    while (i < screen_lines && OLDNUM(i) == _NEWINDEX)
	i++;
    for (; i < screen_lines; i = next_hunk) {
	start = i;
	shift = OLDNUM(i) - i;

	/* get forward limit */
	i = start + 1;
	while (i < screen_lines && OLDNUM(i) != _NEWINDEX && OLDNUM(i) - i
	       == shift)
	    i++;
	end = i;
	while (i < screen_lines && OLDNUM(i) == _NEWINDEX)
	    i++;
	next_hunk = i;
	forward_limit = i;
	if (i >= screen_lines || OLDNUM(i) >= i)
	    forward_ref_limit = i;
	else
	    forward_ref_limit = OLDNUM(i);

	i = start - 1;
	/* grow back */
	if (shift < 0)
	    back_limit = back_ref_limit + (-shift);
	while (i >= back_limit) {
	    if (newhash[i] == oldhash[i + shift]
		|| cost_effective(i + shift, i, shift < 0)) {
		OLDNUM(i) = i + shift;
		TR(TRACE_UPDATE | TRACE_MOVE,
		   ("connected new line %d to old line %d (backward continuation)",
		    i, i + shift));
	    } else {
		TR(TRACE_UPDATE | TRACE_MOVE,
		   ("not connecting new line %d to old line %d (backward continuation)",
		    i, i + shift));
		break;
	    }
	    i--;
	}

	i = end;
	/* grow forward */
	if (shift > 0)
	    forward_limit = forward_ref_limit - shift;
	while (i < forward_limit) {
	    if (newhash[i] == oldhash[i + shift]
		|| cost_effective(i + shift, i, shift > 0)) {
		OLDNUM(i) = i + shift;
		TR(TRACE_UPDATE | TRACE_MOVE,
		   ("connected new line %d to old line %d (forward continuation)",
		    i, i + shift));
	    } else {
		TR(TRACE_UPDATE | TRACE_MOVE,
		   ("not connecting new line %d to old line %d (forward continuation)",
		    i, i + shift));
		break;
	    }
	    i++;
	}

	back_ref_limit = back_limit = i;
	if (shift > 0)
	    back_ref_limit += shift;
    }
}