Re: CMap - can it do this?
"Doug Harrison [MVP]" <dsh@mvps.org> wrote in message
news:f6ll44dvfb3436p2d3uflg5ebnt40f45tt@4ax.com...
You originally mentioned "caching the key/value". That causes problems for
unsynchronized read-only access because the values can get out of sync,
and
they may not be thread-safe themselves for copying. As for storing just
the
POSITION, which I'll assume is just a pointer, how would it work? Inside
RemoveKey(k), would you hash the key the saved POSITION points to and the
function argument, and if they agree, perform the comparison, and then
fall
back on the general search? Or would you be optimistic and perform the
comparison first? Wouldn't you also want to do this for Lookup? I guess it
can work if a POSITION is all you store, you're careful to invalidate it
when you need to, and every operation that depends on its value is a
modifying operation, such that the user will have to provide
synchronization anyway for all concurrent access.
When considering caching information internally to a class to speed up its
operations, besides the thread-safety and other correctness questions, I'd
also wonder (a) How much of a speed-up should I expect, and (b) How can I
avoid it? For a class such as CMap, which is based on a hash table, I
wouldn't expect a huge speed improvement, and given the possibility of
spurious hashing/comparing, I'd expect slowdowns in some cases. I'd also
note that I could avoid it all by providing erase(POSITION).
The caching would be used more generally than just for RemoveKey().
Altering the given code:
// m_map is a CMap<void*, void*, int, int>
void* key;
int value;
POSITION pos = m_map.GetStartPosition();
while (pos)
{
m_map.GetNextAssoc(pos, key, value);
MyFunc(key);
}
void MyFunc (void *key)
{
int value;
m_map.Lookup(key, value);
// use value
}
Here, CMap::RemoveKey() is not called. Only MyFunc(key) is called. Even
though CMap::GetNextAssoc() returns the value, say it is convenient for
MyFunc() to take a key, not the value. The first thing MyFunc() does is to
lookup the value from the key.
My point about caching the last requested key/value is that I provide a
strong hint to CMap by calling CMap::GetNextAssoc() that I am interested in
the key that it returns, so if I immediately call CMap::Lookup() (which
MyFunc() does), then the caching should save some work and provide the
desired value immediately.
So I'm not advocating caching POSITION (as I implied earlier, sorry), I'm
advocating caching the last key/value that was looked up, either through
CMap::Lookup() or CMap::GetNextAssoc().
You're right that if CMap is written to, it could invalidate the cached
key/value, so they would have to be invalidated in that case. CMap is not
thread safe to begin with; it is already possible for one thread to start an
iteration and in the middle of it have another thread insert or remove a
value that renders inaccurate the iteration. Since it is already
inaccurate, having an inaccurate cache due to thread insafety is not making
things worse. Already the caller would be responsible for thread-safe
access to the CMap, so that could be assumed.
You're probably right that neither CMap or other maps use caching. But it
does sound like a good idea. In .NET, I could iterate a dictionary like:
Dictionary<void *, int> dict;
foreach (KeyValuePair<void *, int> kvp in dict)
FuncTakingValue(kvp.Value);
But it is a little cleaner this way:
foreach (void *key in dict)
FuncTakingValue(dict[key]);
Performance-wise, I would hope these are identical, but without caching,
they are not.
-- David