Ejemplo n.º 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;
}
Ejemplo n.º 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();
}