Revision a20d3c0de1f107ddd719a4a9cec3addd56e8444f authored by Junio C Hamano on 27 November 2012, 19:47:46 UTC, committed by Junio C Hamano on 27 November 2012, 21:21:15 UTC
The diffstat generation logic, with --stat-count limit, is
implemented as three loops.

 - The first counts the width necessary to show stats up to
   specified number of entries, and notes up to how many entries in
   the data we need to iterate to show the graph;

 - The second iterates that many times to draw the graph, adjusts
   the number of "total modified files", and counts the total
   added/deleted lines for the part that was shown in the graph;

 - The third iterates over the remainder and only does the part to
   count "total added/deleted lines" and to adjust "total modified
   files" without drawing anything.

Move the logic to count added/deleted lines and modified files from
the second loop to the third loop.

This incidentally fixes a bug.  The third loop was not filtering
binary changes (counted in bytes) from the total added/deleted as it
should.  The second loop implemented this correctly, so if a binary
change appeared earlier than the --stat-count cutoff, the code
counted number of added/deleted lines correctly, but if it appeared
beyond the cutoff, the number of lines would have mixed with the
byte count in the buggy third loop.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent af0ed81
Raw File
hash.c
/*
 * Some generic hashing helpers.
 */
#include "cache.h"
#include "hash.h"

/*
 * Look up a hash entry in the hash table. Return the pointer to
 * the existing entry, or the empty slot if none existed. The caller
 * can then look at the (*ptr) to see whether it existed or not.
 */
static struct hash_table_entry *lookup_hash_entry(unsigned int hash, const struct hash_table *table)
{
	unsigned int size = table->size, nr = hash % size;
	struct hash_table_entry *array = table->array;

	while (array[nr].ptr) {
		if (array[nr].hash == hash)
			break;
		nr++;
		if (nr >= size)
			nr = 0;
	}
	return array + nr;
}


/*
 * Insert a new hash entry pointer into the table.
 *
 * If that hash entry already existed, return the pointer to
 * the existing entry (and the caller can create a list of the
 * pointers or do anything else). If it didn't exist, return
 * NULL (and the caller knows the pointer has been inserted).
 */
static void **insert_hash_entry(unsigned int hash, void *ptr, struct hash_table *table)
{
	struct hash_table_entry *entry = lookup_hash_entry(hash, table);

	if (!entry->ptr) {
		entry->ptr = ptr;
		entry->hash = hash;
		table->nr++;
		return NULL;
	}
	return &entry->ptr;
}

static void grow_hash_table(struct hash_table *table)
{
	unsigned int i;
	unsigned int old_size = table->size, new_size;
	struct hash_table_entry *old_array = table->array, *new_array;

	new_size = alloc_nr(old_size);
	new_array = xcalloc(sizeof(struct hash_table_entry), new_size);
	table->size = new_size;
	table->array = new_array;
	table->nr = 0;
	for (i = 0; i < old_size; i++) {
		unsigned int hash = old_array[i].hash;
		void *ptr = old_array[i].ptr;
		if (ptr)
			insert_hash_entry(hash, ptr, table);
	}
	free(old_array);
}

void *lookup_hash(unsigned int hash, const struct hash_table *table)
{
	if (!table->array)
		return NULL;
	return lookup_hash_entry(hash, table)->ptr;
}

void **insert_hash(unsigned int hash, void *ptr, struct hash_table *table)
{
	unsigned int nr = table->nr;
	if (nr >= table->size/2)
		grow_hash_table(table);
	return insert_hash_entry(hash, ptr, table);
}

int for_each_hash(const struct hash_table *table, int (*fn)(void *, void *), void *data)
{
	int sum = 0;
	unsigned int i;
	unsigned int size = table->size;
	struct hash_table_entry *array = table->array;

	for (i = 0; i < size; i++) {
		void *ptr = array->ptr;
		array++;
		if (ptr) {
			int val = fn(ptr, data);
			if (val < 0)
				return val;
			sum += val;
		}
	}
	return sum;
}

void free_hash(struct hash_table *table)
{
	free(table->array);
	table->array = NULL;
	table->size = 0;
	table->nr = 0;
}
back to top