diff options
| author | Jordi Vilalta Prat | 2009-02-15 06:10:59 +0000 | 
|---|---|---|
| committer | Jordi Vilalta Prat | 2009-02-15 06:10:59 +0000 | 
| commit | fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc (patch) | |
| tree | ce87338830cc8c149e1de545246bcefe4f45da00 /engines/sci/gfx/sbtree.c | |
| parent | 7c148ddf021c990fa866b7600f979aac9a5b26c9 (diff) | |
| download | scummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.tar.gz scummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.tar.bz2 scummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.zip | |
Import the SCI engine sources from the FreeSCI Glutton branch (it doesn't compile yet)
svn-id: r38192
Diffstat (limited to 'engines/sci/gfx/sbtree.c')
| -rw-r--r-- | engines/sci/gfx/sbtree.c | 473 | 
1 files changed, 473 insertions, 0 deletions
| diff --git a/engines/sci/gfx/sbtree.c b/engines/sci/gfx/sbtree.c new file mode 100644 index 0000000000..b5e2c6b068 --- /dev/null +++ b/engines/sci/gfx/sbtree.c @@ -0,0 +1,473 @@ +/*************************************************************************** + sbtree.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + +    Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ +/* Static binary lookup tree lookup */ + + +#include <sci_memory.h> +#include <sbtree.h> +#include <stdlib.h> +#include <stdio.h> + +#define NOT_A_KEY -1 + +typedef struct { +	int key; +	void *value; +} sbcell_t; + +int +int_compar(const void *a, const void *b) +{ +	return (*((int *)a))-(*((int *)b)); +} + + +void +insert_interval(sbcell_t *data, int start, int stop, int *keys, int plus) +{ +	int center = start + ((stop - start) >> 1); + +	data->key = keys[center]; + +	if (start == stop) +		return; + +	if (center > start) +		insert_interval(data + plus, start, center - 1, keys, plus << 1); + +	if (center < stop) +		insert_interval(data + plus + 1, center + 1, stop, keys, ((plus << 1) + 1)); +} + +sbtree_t * +sbtree_new(int size, int *keys) +{ +	int table_size = 2; +	int levels = 0; +	sbcell_t *table; +	sbtree_t *tree; +	int i; + +	if (size < 0) +		return NULL; + +	while (table_size <= size) { +		table_size <<= 1; +		++levels; +	} + +	if (table_size > 1) +		--table_size; + +	table = (sbcell_t*)sci_calloc(sizeof(sbcell_t), table_size); +	for (i = 0; i < table_size; i++) +		table[i].key = NOT_A_KEY; + +	if (!table) { +		fprintf(stderr,"SBTree: Out of memory: Could not allocate %d cells\n", table_size); +		return NULL; +	} + +	tree = (sbtree_t*)sci_malloc(sizeof(sbtree_t)); + +	if (!tree) { +		fprintf(stderr,"SBTree: Could not allocate tree structure\n"); +		free(table); +		return NULL; +	} + +	qsort(keys, size, sizeof(int), int_compar); + +	insert_interval(table, 0, size-1, keys, 1); + +	tree->levels = levels; +	tree->entries_nr = size; +	if ((tree->min_entry = keys[0]) < 0) { +		fprintf(stderr,"SBTree: Error: Using negative keys\n"); +		free(table); +		free(tree); +		return NULL; +	} +	tree->max_entry = keys[size - 1]; +	tree->data = (void *) table; +	tree->alloced_entries = table_size; +	return tree; +} + + +void +sbtree_free(sbtree_t *tree) +{ +	if (!tree) { +		fprintf(stderr,"SBTree: Attempt to free NULL sbtree\n"); +		return; +	} + +	free(tree->data); +	free(tree); +} + + +void +sbtree_foreach(sbtree_t *tree, void *args, void *(*operation)(sbtree_t *, const int, +							      const void *, void *)) +{ +	int i; +	sbcell_t *cell = (sbcell_t *) tree->data; + +	for (i = 0; i < tree->alloced_entries; i++) { +		if (cell->key != NOT_A_KEY) +			cell->value = operation(tree, cell->key, cell->value, args); +		cell = cell + 1; +	} +} + +sbcell_t * +locate(sbcell_t *start, int key, int level, int levels, int plus) +{ +	int comparison; + +	if (level >= levels && (level != levels || start->key == NOT_A_KEY)) +		/* For large tables, the speed improvement caused by this comparison +		** scheme is almost (cough) measurable... +		*/ +		return NULL; + +	comparison = key - start->key; + +	if (!comparison) +		return start; + +	return locate(start + plus + (comparison > 0), key, level + 1, levels, (plus << 1) + (comparison > 0)); +} + + +int +sbtree_set(sbtree_t *tree, int key, void *value) +{ +	sbcell_t *cell = locate((sbcell_t *) tree->data, key, 0, tree->levels, 1); + +	if (cell) +		cell->value = value; +	else +		return -1; + +	return 0; +} + + +void * +sbtree_get(sbtree_t *tree, int key) +{ +	sbcell_t *cell = locate((sbcell_t *) tree->data, key, 0, tree->levels, 1); + +	if (cell) +		return cell->value; +	else +		return NULL; +} + +static void +sbtree_print(sbtree_t *tree) +{ +	int l, i; +	sbcell_t *cells = (sbcell_t *) tree->data; + +	fprintf(stderr,"\tTree:\n"); +	for (l = 0; l <= tree->levels; l++) { +		fprintf(stderr,"\t  "); +		for (i = 0; i < (1 << l); i++) { +			if (cells->key == NOT_A_KEY) +				fprintf(stderr,"-- "); +			else { +				if (cells->value) +					fprintf(stderr,"%d+ ", cells->key); +				else +					fprintf(stderr,"%d  ", cells->key); +			} + +			cells = cells + 1; +		} +		fprintf(stderr,"\n"); +	} +	fprintf(stderr,"\n"); +} + + + +/***************************** TEST CODE ********************************/ + + +#ifdef SBTREE_DEBUG + +static int any_error; + + +void * +foreach_double_func(sbtree_t *tree, const int key, const void *value, void *args) +{ +	int *real_value = (int *) value; + +	if (!real_value) +		fprintf(stderr,"foreach_double_func(): key %d mapped to non-value!\n", key); +	else *real_value *= 2; + +	return real_value; +} + +int * +generate_linear_forward(int numbers) +{ +	int i; +	int *data = sci_malloc(sizeof(int) * numbers); +	for (i = 0; i < numbers; i++) +		data[i] = i + 1; + +	return data; +} + +int * +generate_linear_backward(int numbers) +{ +	int i; +	int *data = sci_malloc(sizeof(int) * numbers); +	for (i = 0; i < numbers; i++) +		data[i] = numbers - i; + +	return data; +} + +int * +generate_random(int numbers, int max) +{ +	int i; +	int *data = sci_malloc(sizeof(int) * numbers); + +	for (i = 0; i < numbers; i++) +		data[i] = 1 + (int) ((rand() * 1.0 * max) / (RAND_MAX + 1.0)); + +	return data; +} + + +void +insert_values(sbtree_t *tree, int nr, int *data) +{ +	int i; + +	for (i = 0; i < nr; i++) +		if (sbtree_set(tree, data[i], (void *)(data + i))) { +			fprintf(stderr, "While inserting: %d incorrectly deemed invalid\n", data[i]); +			any_error = 1; +		} +} + + +#define MODE_LINEAR 0 +#define MODE_LINEAR_MAP 1 +#define MODE_RANDOM 2 +#define MODE_LINEAR_DOUBLE 3 + +void +test_value(sbtree_t *tree, int times, int max, int numbers, int *data, int mode) +{ +	int i; +	int failed = 0; + +	for (i = 0; i < times; i++) { +		int key = (mode == MODE_LINEAR || mode == MODE_LINEAR_DOUBLE)? i : +			(mode == MODE_LINEAR_MAP)? data[i % numbers] : +			(int) ((rand() * 1.0 * max) / (RAND_MAX + 1.0)); +		int *value = (int *) sbtree_get(tree, (mode == MODE_LINEAR_DOUBLE)? key >> 1 : key); +		int found = 0; +		int j; + +		for (j = 0; j < numbers && !found; j++) +			if (data[j] == key) +				found = 1; + +		if (found && !value) { +			fprintf(stderr, "!%d ", key); +			++failed; +		} +		else if (!found && found) { +			fprintf(stderr, "?[%d]=%d ", key, *value); +			++failed; +		} +	} + +	if (failed) +		fprintf(stderr, "(%d/%d errors)\n", any_error = failed, times); +	else +		fprintf(stderr, "OK\n"); +} + + +void +test_boundary(sbtree_t *tree, int max, int random) +{ +	int *value_too_low = sbtree_get(tree, 0); +	int *value_too_high = sbtree_get(tree, max + 1); +	int *value_low = sbtree_get(tree, 1); +	int *value_high = sbtree_get(tree, max); +	int failure = (value_too_low || value_too_high || (!random && (!value_low || !value_high))); + +	if (!failure) +		fprintf(stderr, "OK\n"); +	else { +		any_error = 1; + +		fprintf(stderr, "Errors: "); +		if (value_too_low) +			fprintf(stderr, "too-low=%d ", *value_too_low); +		if (value_too_high) +			fprintf(stderr, "too-high=%d ", *value_too_high); + +		if (!random) { +			if (!value_low) +				fprintf(stderr, "!low "); +			if (!value_high) +				fprintf(stderr, "!high "); +		} +		fprintf(stderr, "\n"); +	} +} + + +void +test_empty(sbtree_t *tree, int count, int max) +{ +	int i; +	int errors = 0; + +	for (i = 0; i < count; i++) { +		int key = 1 + (int) ((rand() * 1.0 * max) / (RAND_MAX + 1.0)); +		int *value; + +		if ((value = (int *) sbtree_get(tree, key))) { +			fprintf(stderr, "?[%d]=%d\n", key, *value); +			++errors; +		} +	} + +	if (errors) +		fprintf(stderr," (%d/%d errors)\n", any_error = errors, count); +	else +		fprintf(stderr,"OK\n"); +} + +void +run_test(sbtree_t *tree, int entries, int *data, int random, int max_value) +{ +	char *tests[] = {"\tLinear reference test: \t\t", "\tKey map reference test: \t", "\tRandom access test: \t\t"}; +	int i; + +	any_error = 0; + +	fprintf(stderr, "\tEmpty test: \t\t\t"); +	test_empty(tree, entries * 2, entries + 1); +	insert_values(tree, entries, data); +	fprintf(stderr, "\tBoundary test: \t\t\t"); +	test_boundary(tree, max_value, random); + +	for (i = 0; i < 3; i++) { +		fprintf(stderr, tests[i]); +		test_value(tree, entries * 2, entries * 2, entries, data, i); +	} + +	if (!random) { +		i = data[0]; +		sbtree_foreach(tree, NULL, foreach_double_func); +		fprintf(stderr, "\tForeach test: \t\t\t"); +		if (i * 2 != data[0]) { +			fprintf(stderr,"Error: No effect: %d * 2 != %d\n", i, data[0]); +			any_error = 1; +		} else +			test_value(tree, entries * 2, entries * 2, entries, data, MODE_LINEAR_DOUBLE); +	} + +	if (any_error) +		sbtree_print(tree); + +	free(data); +	sbtree_free(tree); +} + + +#define TESTS_NR 11 + +int +main(int argc, char **argv) +{ +	int tests_nr = TESTS_NR; +	int test_sizes[TESTS_NR] = {1, 2, 3, 7, 8, 9, 1000, 16383, 16384, 16385, 1000000}; +	int i; +	fprintf(stderr, "sbtree.c Copyright (C) 2000 Christoph Reichenbach <jameson@linuxgames.com>\n" +		"This program is provided WITHOUT WARRANTY of any kind\n" +		"Please refer to the file COPYING that should have come with this program\n"); +	fprintf(stderr, "Static Binary Tree testing facility\n"); + +	free(malloc(42)); /* Make sure libefence's Copyright message is print here if we're using it */ + +	fprintf(stderr,"\nsbtree.c: Running %d tests.\n", tests_nr); + +	for (i = 0; i < tests_nr; i++) { +		int entries = test_sizes[i]; +		sbtree_t *tree; +		int *data; + +		fprintf(stderr,"Test #%d: %d entries\n", i+1, entries); + +		fprintf(stderr,"\t%da: Linear values\n", i+1); +		data = generate_linear_forward(entries); +		tree = sbtree_new(entries, data); +		run_test(tree, entries, data, 0, entries); + +		fprintf(stderr,"\t%db: Reverse linear values\n", i+1); +		data = generate_linear_backward(entries); +		tree = sbtree_new(entries, data); +		run_test(tree, entries, data, 0, entries); + +		fprintf(stderr,"\t%dc: Dense random values\n", i+1); +		data = generate_random(entries, 1 + (entries >> 2)); +		tree = sbtree_new(entries, data); +		run_test(tree, entries, data, 1, 1 + (entries >> 2)); + +		fprintf(stderr,"\t%dc: Sparse random values\n", i+1); +		data = generate_random(entries, (entries << 2)); +		tree = sbtree_new(entries, data); +		run_test(tree, entries, data, 1, entries << 2); + +		fprintf(stderr,"Test #%d completed.\n\n", i+1); +	} + +	fprintf(stderr,"Test suite completed.\n"); +	return 0; +} + + +#endif /* SBTREE_DEBUG */ | 
