Ok more about hashing. I read Prelude's site and now I'm eternally confuzzled.
Here is what we have. In our script system we wanted a way to let the user or programmer respond to messages w/o having to write a function for every single script command. Essentially if the handler has not been created, the message is not handled.
We tore into the MFC code that does this, much to our chagrin, and figured out how they did it.
The macro they use to declare the message map actually emits code into the classes for the static array that contains the message map information. The macros in the cpp file for the class emit code into the class and then begins a static array buildup. Essentially when you do an ON_COMMAND() or something else, those macros are just adding to an array. Kind of like this:
Code:
typedef void (*CDummyClass::MSG_MAP)(void);
struct MESSAGE_MAP_ENTRY
{
UINT nMessageID;
MSG_MAP pfn;
};
struct MESSAGE_MAP
{
MESSAGE_MAP_ENTRY *pEntries;
MESSAGE_MAP *pBaseMap;
};
#define DECLARE_MESSAGE_MAP() \
protected: \
static const MESSAGE_MAP_ENTRY *m_pEntries; \
static const MESSAGE_MAP *m_pMsgMap; \
public: \
MESSAGE_MAP*GetMessageMap(); \
...
class MyClass:public MyBase
{
DECLARE_MESSAGE_MAP();
};
Code:
#define BEGIN_MESSAGE_MAP(theClass,baseClass) \
MESSAGE_MAP *GetMessageMap() {return &theClass::m_pMsgMap;} \
theClass::m_pFinalMap={baseClass::m_pMsgMap,m_pEntries[0] }; \
const MESSAGE_MAP theClass::m_pEntries[] = {
#define ON_COMMAND(id,memberFxn) \
{id,(MSG_MAP)memberFxn},
....
So as you can see they are just having you build up a static array of message map entries by using those macros. It's ugly and it gets worse but it doesn't add to this discussion.
Now here is their hash algo. Sadly MS doesn't believe in commenting code except every 100 or so lines so it's a bit of a mess.
Code:
...
const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();
UINT iHash; iHash = (LOWORD((DWORD_PTR)pMessageMap) ^ message) & (iHashMax-1);
winMsgLock.Lock(CRIT_WINMSGCACHE);
AFX_MSG_CACHE* pMsgCache; pMsgCache = &_afxMsgCache[iHash];
const AFX_MSGMAP_ENTRY* lpEntry;
if (message == pMsgCache->nMsg && pMessageMap == pMsgCache->pMessageMap)
{
// cache hit
lpEntry = pMsgCache->lpEntry;
winMsgLock.Unlock();
if (lpEntry == NULL) return FALSE;
// cache hit, and it needs to be handled
if (message < 0xC000)
goto LDispatch;
else
goto LDispatchRegistered;
}
....
....
Don't yell at me I didn't code it and I know it's ugly but it's MS. Now how is this going to determine if a message with a certain ID is in the static array or not? The ID could be anywhere in the static array or not in it at all. There must be something in the _afxMsgCache[] array to get this all to work. I'm quite lost on most of it.
Help.
EDIT:
Another question. How would you overload the assignment operator relative to this:
Code:
struct MESSAGE_MAP
{
MESSAGE_MAP_ENTRY *pEntries;
MESSAGE_MAP *pBaseMap;
};
Isn't this going to cause a stack overflow?
Code:
...
friend MESSAGE_MAP &operator=(const MESSAGE_MAP &map)
{
pEntries=map.pEntries;
//This line confuses me - won't this just call this operator we are in...again and again and again?
pBaseMap=map.pBaseMap;
return *this;
}