diff --git a/spine-c/spine-c/include/spine/Skin.h b/spine-c/spine-c/include/spine/Skin.h index 806cde8776..3b3f8b2493 100644 --- a/spine-c/spine-c/include/spine/Skin.h +++ b/spine-c/spine-c/include/spine/Skin.h @@ -38,6 +38,9 @@ extern "C" { #endif +/* Size of hashtable used in skin structure for fast attachment lookup. */ +#define SKIN_ENTRIES_HASH_TABLE_SIZE 100 + struct spSkeleton; typedef struct spSkin { @@ -59,9 +62,16 @@ struct _Entry { _Entry* next; }; +typedef struct _SkinHashTableEntry _SkinHashTableEntry; +struct _SkinHashTableEntry { + _Entry* entry; + _SkinHashTableEntry* next; /* list for elements with same hashes */ +}; + typedef struct { spSkin super; - _Entry* entries; + _Entry* entries; /* entries list stored for getting attachment name by attachment index */ + _SkinHashTableEntry* entriesHashTable[SKIN_ENTRIES_HASH_TABLE_SIZE]; /* hashtable for fast attachment lookup */ } _spSkin; SP_API spSkin* spSkin_create (const char* name); diff --git a/spine-c/spine-c/src/spine/Skin.c b/spine-c/spine-c/src/spine/Skin.c index 91f2d21fe7..e222babbca 100644 --- a/spine-c/spine-c/src/spine/Skin.c +++ b/spine-c/spine-c/src/spine/Skin.c @@ -45,6 +45,16 @@ void _Entry_dispose (_Entry* self) { FREE(self); } +static _SkinHashTableEntry* _SkinHashTableEntry_create (_Entry* entry) { + _SkinHashTableEntry* self = NEW(_SkinHashTableEntry); + self->entry = entry; + return self; +} + +static void _SkinHashTableEntry_dispose (_SkinHashTableEntry* self) { + FREE(self); +} + /**/ spSkin* spSkin_create (const char* name) { @@ -55,12 +65,28 @@ spSkin* spSkin_create (const char* name) { void spSkin_dispose (spSkin* self) { _Entry* entry = SUB_CAST(_spSkin, self)->entries; + while (entry) { _Entry* nextEntry = entry->next; _Entry_dispose(entry); entry = nextEntry; } + { + _SkinHashTableEntry** currentHashtableEntry = SUB_CAST(_spSkin, self)->entriesHashTable; + int i; + + for (i = 0; i < SKIN_ENTRIES_HASH_TABLE_SIZE; ++i, ++currentHashtableEntry) { + _SkinHashTableEntry* hashtableEntry = *currentHashtableEntry; + + while (hashtableEntry) { + _SkinHashTableEntry* nextEntry = hashtableEntry->next; + _SkinHashTableEntry_dispose(hashtableEntry); + hashtableEntry = nextEntry; + } + } + } + FREE(self->name); FREE(self); } @@ -69,13 +95,21 @@ void spSkin_addAttachment (spSkin* self, int slotIndex, const char* name, spAtta _Entry* newEntry = _Entry_create(slotIndex, name, attachment); newEntry->next = SUB_CAST(_spSkin, self)->entries; SUB_CAST(_spSkin, self)->entries = newEntry; + + { + unsigned int hashTableIndex = (unsigned int)slotIndex % SKIN_ENTRIES_HASH_TABLE_SIZE; + + _SkinHashTableEntry* newHashEntry = _SkinHashTableEntry_create(newEntry); + newHashEntry->next = SUB_CAST(_spSkin, self)->entriesHashTable[hashTableIndex]; + SUB_CAST(_spSkin, self)->entriesHashTable[hashTableIndex] = newHashEntry; + } } spAttachment* spSkin_getAttachment (const spSkin* self, int slotIndex, const char* name) { - const _Entry* entry = SUB_CAST(_spSkin, self)->entries; - while (entry) { - if (entry->slotIndex == slotIndex && strcmp(entry->name, name) == 0) return entry->attachment; - entry = entry->next; + const _SkinHashTableEntry* hashEntry = SUB_CAST(_spSkin, self)->entriesHashTable[(unsigned int)slotIndex % SKIN_ENTRIES_HASH_TABLE_SIZE]; + while (hashEntry) { + if (hashEntry->entry->slotIndex == slotIndex && strcmp(hashEntry->entry->name, name) == 0) return hashEntry->entry->attachment; + hashEntry = hashEntry->next; } return 0; }