From 3d455fc05fa08fb1f24553782c5e5345c085f746 Mon Sep 17 00:00:00 2001 From: janwas Date: Wed, 18 Aug 2004 02:08:15 +0000 Subject: [PATCH] h_find now via hash multimap instead of linear search (it's called often) This was SVN commit r1015. --- source/lib/res/h_mgr.cpp | 63 +++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/source/lib/res/h_mgr.cpp b/source/lib/res/h_mgr.cpp index 0df25e61ca..ff85aa1c86 100755 --- a/source/lib/res/h_mgr.cpp +++ b/source/lib/res/h_mgr.cpp @@ -186,7 +186,7 @@ static HDATA* h_data(const i32 idx) return 0; } - // note: VC7.1 optimizes the divisions to shift and mask. + // note: VC7.1 optimizes the divides to shift and mask. return &page[idx % hdata_per_page]; } @@ -346,6 +346,12 @@ static int free_idx(i32 idx) } +// speed up h_find (called every h_alloc) +// multimap, because we want to add handles of differing type but same key +// (e.g. a VFile and Tex object for the same underlying filename hash key) +typedef STL_HASH_MULTIMAP Key2Idx; +typedef Key2Idx::iterator It; +static Key2Idx key2idx; int h_free(Handle& h, H_Type type) @@ -378,6 +384,26 @@ int h_free(Handle& h, H_Type type) if(vtbl->dtor) vtbl->dtor(hd->user); + if(hd->key) + { + It it = key2idx.find(hd->key); + // not found in mapping + if(it == key2idx.end()) + debug_warn("h_free: not in key2idx"); + It end = key2idx.upper_bound(hd->key); + for(; it != end; ++it) + { + i32 idx = it->second; + HDATA* hd2 = h_data(idx); + // found match + if(hd2 && hd2->type == type && hd2->key == hd->key) + { + key2idx.erase(it); + break; + } + } + } + free((void*)hd->fn); memset(hd, 0, sizeof(HDATA)); @@ -444,13 +470,11 @@ Handle h_alloc(H_Type type, const char* fn, uint flags, ...) //debug_out("alloc %s %s\n", type->name, fn); - // disable caching if no key, because it would never be found + // no key => can never be found. disallow caching if(!key) flags |= RES_NO_CACHE; // changes scope to RES_TEMP - - const uint scope = flags & RES_SCOPE_MASK; - - if(key) + // check if already loaded (cached) + else { // object already loaded? h = h_find(type, key); @@ -480,6 +504,8 @@ Handle h_alloc(H_Type type, const char* fn, uint flags, ...) CHECK_ERR(alloc_idx(idx, hd)); skip_alloc: + const uint scope = flags & RES_SCOPE_MASK; + // generate next tag value. // don't want to do this before the add-reference exit, // so as not to waste tags for often allocated handles. @@ -505,7 +531,8 @@ skip_alloc: return h; } - + if(key) + key2idx.insert(std::make_pair(key, idx)); // one-time init hd->tag = tag; @@ -636,21 +663,31 @@ int h_reload(const char* fn) } -// TODO: more efficient search; currently linear Handle h_find(H_Type type, uintptr_t key) { - for(i32 i = 0; i < last_in_use; i++) + It it = key2idx.find(key); + // not found in mapping + if(it == key2idx.end()) + return -1; + It end = key2idx.upper_bound(key); + for(; it != end; ++it) { - HDATA* hd = h_data(i); - if(hd) - if(hd->type == type && hd->key == key) - return handle(i, hd->tag); + i32 idx = it->second; + HDATA* hd = h_data(idx); + // found match + if(hd && hd->type == type && hd->key == key) + return handle(idx, hd->tag); } + // key is in the mapping, but it's of the wrong type. + // this happens when called by h_alloc to check if + // e.g. a Tex object already exists; at that time, + // only the corresponding VFile exists. return -1; } + int res_cur_scope;