- BLI_ghashutil_strhash_n takes string length, to avoid terminating the string before hashing. - BLI_ghashutil_inthash/uinthash take ints, to avoid casting to (void *) This also showed up incorrect use of inthash, which was using a pointer.
		
			
				
	
	
		
			165 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			165 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * ***** BEGIN GPL LICENSE BLOCK *****
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of the GNU General Public License
 | 
						|
 * as published by the Free Software Foundation; either version 2
 | 
						|
 * of the License, or (at your option) any later version.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
 * GNU General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License
 | 
						|
 * along with this program; if not, write to the Free Software Foundation,
 | 
						|
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | 
						|
 *
 | 
						|
 * Contributor(s): Blender Foundation 2013
 | 
						|
 *
 | 
						|
 * ***** END GPL LICENSE BLOCK *****
 | 
						|
 */
 | 
						|
 | 
						|
/** \file treehash.c
 | 
						|
 *  \ingroup bke
 | 
						|
 *
 | 
						|
 * Tree hash for the outliner space.
 | 
						|
 */
 | 
						|
 | 
						|
#include <stdlib.h>
 | 
						|
 | 
						|
#include "BKE_treehash.h"
 | 
						|
 | 
						|
#include "BLI_utildefines.h"
 | 
						|
#include "BLI_ghash.h"
 | 
						|
#include "BLI_mempool.h"
 | 
						|
 | 
						|
#include "DNA_outliner_types.h"
 | 
						|
 | 
						|
#include "MEM_guardedalloc.h"
 | 
						|
 | 
						|
typedef struct TseGroup
 | 
						|
{
 | 
						|
	TreeStoreElem **elems;
 | 
						|
	int size;
 | 
						|
	int allocated;
 | 
						|
} TseGroup;
 | 
						|
 | 
						|
/* Allocate structure for TreeStoreElements;
 | 
						|
 * Most of elements in treestore have no duplicates,
 | 
						|
 * so there is no need to preallocate memory for more than one pointer */
 | 
						|
static TseGroup *tse_group_create(void)
 | 
						|
{
 | 
						|
	TseGroup *tse_group = MEM_mallocN(sizeof(TseGroup), "TseGroup");
 | 
						|
	tse_group->elems = MEM_mallocN(sizeof(TreeStoreElem *), "TseGroupElems");
 | 
						|
	tse_group->size = 0;
 | 
						|
	tse_group->allocated = 1;
 | 
						|
	return tse_group;
 | 
						|
}
 | 
						|
 | 
						|
static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem)
 | 
						|
{
 | 
						|
	if (tse_group->size == tse_group->allocated) {
 | 
						|
		tse_group->allocated *= 2;
 | 
						|
		tse_group->elems = MEM_reallocN(tse_group->elems, sizeof(TreeStoreElem *) * tse_group->allocated);
 | 
						|
	}
 | 
						|
	tse_group->elems[tse_group->size] = elem;
 | 
						|
	tse_group->size++;
 | 
						|
}
 | 
						|
 | 
						|
static void tse_group_free(TseGroup *tse_group)
 | 
						|
{
 | 
						|
	MEM_freeN(tse_group->elems);
 | 
						|
	MEM_freeN(tse_group);
 | 
						|
}
 | 
						|
 | 
						|
static unsigned int tse_hash(const void *ptr)
 | 
						|
{
 | 
						|
	const TreeStoreElem *tse = ptr;
 | 
						|
	unsigned int hash;
 | 
						|
	BLI_assert(tse->type || !tse->nr);
 | 
						|
	hash = BLI_ghashutil_inthash((tse->nr << 16) + tse->type);
 | 
						|
	hash ^= BLI_ghashutil_ptrhash(tse->id);
 | 
						|
	return hash;
 | 
						|
}
 | 
						|
 | 
						|
static int tse_cmp(const void *a, const void *b)
 | 
						|
{
 | 
						|
	const TreeStoreElem *tse_a = a;
 | 
						|
	const TreeStoreElem *tse_b = b;
 | 
						|
	return tse_a->type != tse_b->type || tse_a->nr != tse_b->nr || tse_a->id != tse_b->id;
 | 
						|
}
 | 
						|
 | 
						|
static void fill_treehash(void *treehash, BLI_mempool *treestore)
 | 
						|
{
 | 
						|
	TreeStoreElem *tselem;
 | 
						|
	BLI_mempool_iter iter;
 | 
						|
	BLI_mempool_iternew(treestore, &iter);
 | 
						|
	while ((tselem = BLI_mempool_iterstep(&iter))) {
 | 
						|
		BKE_treehash_add_element(treehash, tselem);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void *BKE_treehash_create_from_treestore(BLI_mempool *treestore)
 | 
						|
{
 | 
						|
	GHash *treehash = BLI_ghash_new_ex(tse_hash, tse_cmp, "treehash", BLI_mempool_count(treestore));
 | 
						|
	fill_treehash(treehash, treestore);
 | 
						|
	return treehash;
 | 
						|
}
 | 
						|
 | 
						|
static void free_treehash_group(void *key)
 | 
						|
{
 | 
						|
	tse_group_free(key);
 | 
						|
}
 | 
						|
 | 
						|
void *BKE_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore)
 | 
						|
{
 | 
						|
	BLI_ghash_clear_ex(treehash, NULL, free_treehash_group, BLI_mempool_count(treestore));
 | 
						|
	fill_treehash(treehash, treestore);
 | 
						|
	return treehash;
 | 
						|
}
 | 
						|
 | 
						|
void BKE_treehash_add_element(void *treehash, TreeStoreElem *elem)
 | 
						|
{
 | 
						|
	TseGroup *group = BLI_ghash_lookup(treehash, elem);
 | 
						|
	if (!group) {
 | 
						|
		group = tse_group_create();
 | 
						|
		BLI_ghash_insert(treehash, elem, group);
 | 
						|
	}
 | 
						|
	tse_group_add(group, elem);
 | 
						|
}
 | 
						|
 | 
						|
static TseGroup *BKE_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id)
 | 
						|
{
 | 
						|
	TreeStoreElem tse_template;
 | 
						|
	tse_template.type = type;
 | 
						|
	tse_template.nr = type ? nr : 0;  // we're picky! :)
 | 
						|
	tse_template.id = id;
 | 
						|
	return BLI_ghash_lookup(th, &tse_template);
 | 
						|
}
 | 
						|
 | 
						|
TreeStoreElem *BKE_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id)
 | 
						|
{
 | 
						|
	TseGroup *group = BKE_treehash_lookup_group(treehash, type, nr, id);
 | 
						|
	if (group) {
 | 
						|
		int i;
 | 
						|
		for (i = 0; i < group->size; i++) {
 | 
						|
			if (!group->elems[i]->used) {
 | 
						|
				return group->elems[i];
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
TreeStoreElem *BKE_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id)
 | 
						|
{
 | 
						|
	TseGroup *group = BKE_treehash_lookup_group(treehash, type, nr, id);
 | 
						|
	return group ? group->elems[0] : NULL;
 | 
						|
}
 | 
						|
 | 
						|
void BKE_treehash_free(void *treehash)
 | 
						|
{
 | 
						|
	BLI_ghash_free(treehash, NULL, free_treehash_group);
 | 
						|
}
 |