applied event speed up patch (752928)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@22067 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2003-07-17 23:59:49 +00:00
parent 520200fd10
commit b5a98acdf2
3 changed files with 260 additions and 22 deletions

View File

@@ -122,6 +122,7 @@ All GUI ports:
styles for use with conservative idle and update event modes. styles for use with conservative idle and update event modes.
- wxMSW and wxGTK now send menu update events only when a menu is - wxMSW and wxGTK now send menu update events only when a menu is
about to be used. about to be used.
- improved event processing performance (Hans Van Leemputten)
Unix: Unix:

View File

@@ -27,6 +27,8 @@
#include "wx/thread.h" #include "wx/thread.h"
#include "wx/dynarray.h"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// forward declarations // forward declarations
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -86,6 +88,8 @@ typedef int wxEventType;
#define DECLARE_EVENT_TABLE_ENTRY(type, winid, idLast, fn, obj) \ #define DECLARE_EVENT_TABLE_ENTRY(type, winid, idLast, fn, obj) \
wxEventTableEntry(type, winid, idLast, fn, obj) wxEventTableEntry(type, winid, idLast, fn, obj)
#define EMPTY_PARAMETER_VALUE /* Fake macro parameter value */
#define BEGIN_DECLARE_EVENT_TYPES() #define BEGIN_DECLARE_EVENT_TYPES()
#define END_DECLARE_EVENT_TYPES() #define END_DECLARE_EVENT_TYPES()
#define DECLARE_EXPORTED_EVENT_TYPE(expdecl, name, value) \ #define DECLARE_EXPORTED_EVENT_TYPE(expdecl, name, value) \
@@ -93,7 +97,7 @@ typedef int wxEventType;
#define DECLARE_EVENT_TYPE(name, value) \ #define DECLARE_EVENT_TYPE(name, value) \
DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_CORE, name, value) DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_CORE, name, value)
#define DECLARE_LOCAL_EVENT_TYPE(name, value) \ #define DECLARE_LOCAL_EVENT_TYPE(name, value) \
DECLARE_EXPORTED_EVENT_TYPE(/* */, name, value) DECLARE_EXPORTED_EVENT_TYPE(EMPTY_PARAMETER_VALUE, name, value)
#define DEFINE_EVENT_TYPE(name) const wxEventType name = wxNewEventType(); #define DEFINE_EVENT_TYPE(name) const wxEventType name = wxNewEventType();
#define DEFINE_LOCAL_EVENT_TYPE(name) DEFINE_EVENT_TYPE(name) #define DEFINE_LOCAL_EVENT_TYPE(name) DEFINE_EVENT_TYPE(name)
@@ -2082,6 +2086,56 @@ struct WXDLLIMPEXP_BASE wxEventTable
const wxEventTableEntry *entries; // bottom of entry array const wxEventTableEntry *entries; // bottom of entry array
}; };
// ----------------------------------------------------------------------------
// wxEventHashTable: a helper of wxEvtHandler to speed up wxEventTable lookups.
// ----------------------------------------------------------------------------
WX_DEFINE_ARRAY(const wxEventTableEntry*, wxEventTableEntryPointerArray);
class WXDLLIMPEXP_BASE wxEvtHandler;
class WXDLLIMPEXP_BASE wxEventHashTable
{
private:
// Internal data structs
struct EventTypeTable
{
wxEventType eventType;
wxEventTableEntryPointerArray eventEntryTable;
};
typedef EventTypeTable* EventTypeTablePointer;
public:
// Constructor, needs the event table it needs to hash later on.
// Note: hashing of the event table is not done in the constructor as it
// can be that the event table is not yet full initialize, the hash
// will gets initialized when handling the first event look-up request.
wxEventHashTable(const wxEventTable &table);
// Destructor.
~wxEventHashTable();
// Handle the given event, in other words search the event table hash
// and call self->ProcessEvent() if a match was found.
bool HandleEvent(wxEvent &event, wxEvtHandler *self);
protected:
// Init the hash table with the entries of the static event table.
void InitHashTable();
// Helper funtion of InitHashTable() to insert 1 entry into the hash table.
void AddEntry(const wxEventTableEntry &entry);
// Allocate and init with null pointers the base hash table.
void AllocEventTypeTable(size_t size);
// Grow the hash table in size and transfer all items currently
// in the table to the correct location in the new table.
void GrowEventTypeTable();
protected:
const wxEventTable &m_table;
bool m_rebuildHash;
size_t m_size;
EventTypeTablePointer *m_eventTypeTable;
};
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxEvtHandler: the base class for all objects handling wxWindows events // wxEvtHandler: the base class for all objects handling wxWindows events
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -2202,9 +2256,11 @@ protected:
static const wxEventTable sm_eventTable; static const wxEventTable sm_eventTable;
virtual const wxEventTable *GetEventTable() const; virtual const wxEventTable *GetEventTable() const;
static wxEventHashTable sm_eventHashTable;
virtual wxEventHashTable& GetEventHashTable() const;
wxEvtHandler* m_nextHandler; wxEvtHandler* m_nextHandler;
wxEvtHandler* m_previousHandler; wxEvtHandler* m_previousHandler;
wxList* m_dynamicEvents; wxList* m_dynamicEvents;
@@ -2303,16 +2359,22 @@ typedef void (wxEvtHandler::*wxMouseCaptureChangedEventFunction)(wxMouseCaptureC
static const wxEventTableEntry sm_eventTableEntries[]; \ static const wxEventTableEntry sm_eventTableEntries[]; \
protected: \ protected: \
static const wxEventTable sm_eventTable; \ static const wxEventTable sm_eventTable; \
virtual const wxEventTable* GetEventTable() const; virtual const wxEventTable* GetEventTable() const; \
static wxEventHashTable sm_eventHashTable; \
virtual wxEventHashTable& GetEventHashTable() const;
// N.B.: when building DLL with Borland C++ 5.5 compiler, you must initialize // N.B.: when building DLL with Borland C++ 5.5 compiler, you must initialize
// sm_eventTable before using it in GetEventTable() or the compiler gives // sm_eventTable before using it in GetEventTable() or the compiler gives
// E2233 (see http://groups.google.com/groups?selm=397dcc8a%241_2%40dnews) // E2233 (see http://groups.google.com/groups?selm=397dcc8a%241_2%40dnews)
#define BEGIN_EVENT_TABLE(theClass, baseClass) \ #define BEGIN_EVENT_TABLE(theClass, baseClass) \
const wxEventTable theClass::sm_eventTable = \ const wxEventTable theClass::sm_eventTable = \
{ &baseClass::sm_eventTable, &theClass::sm_eventTableEntries[0] }; \ { &baseClass::sm_eventTable, &theClass::sm_eventTableEntries[0] }; \
const wxEventTable *theClass::GetEventTable() const \ const wxEventTable *theClass::GetEventTable() const \
{ return &theClass::sm_eventTable; } \ { return &theClass::sm_eventTable; } \
wxEventHashTable theClass::sm_eventHashTable(theClass::sm_eventTable); \
wxEventHashTable &theClass::GetEventHashTable() const \
{ return theClass::sm_eventHashTable; } \
const wxEventTableEntry theClass::sm_eventTableEntries[] = { \ const wxEventTableEntry theClass::sm_eventTableEntries[] = { \
#define END_EVENT_TABLE() DECLARE_EVENT_TABLE_ENTRY( wxEVT_NULL, 0, 0, 0, 0 ) }; #define END_EVENT_TABLE() DECLARE_EVENT_TABLE_ENTRY( wxEVT_NULL, 0, 0, 0, 0 ) };

View File

@@ -104,6 +104,11 @@ const wxEventTable *wxEvtHandler::GetEventTable() const
const wxEventTable wxEvtHandler::sm_eventTable = const wxEventTable wxEvtHandler::sm_eventTable =
{ (const wxEventTable *)NULL, &wxEvtHandler::sm_eventTableEntries[0] }; { (const wxEventTable *)NULL, &wxEvtHandler::sm_eventTableEntries[0] };
wxEventHashTable &wxEvtHandler::GetEventHashTable() const
{ return wxEvtHandler::sm_eventHashTable; }
wxEventHashTable wxEvtHandler::sm_eventHashTable(wxEvtHandler::sm_eventTable);
const wxEventTableEntry wxEvtHandler::sm_eventTableEntries[] = const wxEventTableEntry wxEvtHandler::sm_eventTableEntries[] =
{ DECLARE_EVENT_TABLE_ENTRY(wxEVT_NULL, 0, 0, (wxObjectEventFunction)NULL, NULL) }; { DECLARE_EVENT_TABLE_ENTRY(wxEVT_NULL, 0, 0, (wxObjectEventFunction)NULL, NULL) };
@@ -364,7 +369,6 @@ wxCommandEvent::wxCommandEvent(wxEventType commandType, int theId)
m_clientObject = (wxClientData *) NULL; m_clientObject = (wxClientData *) NULL;
m_extraLong = 0; m_extraLong = 0;
m_commandInt = 0; m_commandInt = 0;
m_commandString = wxEmptyString;
m_isCommandEvent = TRUE; m_isCommandEvent = TRUE;
} }
@@ -704,6 +708,182 @@ wxChildFocusEvent::wxChildFocusEvent(wxWindow *win)
#endif // wxUSE_GUI #endif // wxUSE_GUI
// ----------------------------------------------------------------------------
// wxEventHashTable
// ----------------------------------------------------------------------------
static const int EVENT_TYPE_TABLE_INIT_SIZE = 31; // Not to big not to small...
wxEventHashTable::wxEventHashTable(const wxEventTable &table)
: m_table(table),
m_rebuildHash(TRUE)
{
AllocEventTypeTable(EVENT_TYPE_TABLE_INIT_SIZE);
}
wxEventHashTable::~wxEventHashTable()
{
size_t i;
for(i = 0; i < m_size; i++)
{
EventTypeTablePointer eTTnode = m_eventTypeTable[i];
if (eTTnode)
{
delete eTTnode;
}
}
delete[] m_eventTypeTable;
}
bool wxEventHashTable::HandleEvent(wxEvent &event, wxEvtHandler *self)
{
if (m_rebuildHash)
{
InitHashTable();
m_rebuildHash = FALSE;
}
// Find all entries for the given event type.
wxEventType eventType = event.GetEventType();
const EventTypeTablePointer eTTnode = m_eventTypeTable[eventType % m_size];
if (eTTnode && eTTnode->eventType == eventType)
{
// Now start the search for an event handler
// that can handle an event with the given ID.
int eventId = event.GetId();
const wxEventTableEntryPointerArray &eventEntryTable = eTTnode->eventEntryTable;
size_t n;
size_t count = eventEntryTable.GetCount();
for (n = 0; n < count; n++)
{
const wxEventTableEntry* entry = eventEntryTable[n];
int tableId1 = entry->m_id,
tableId2 = entry->m_lastId;
if ((tableId1 == -1) ||
(tableId2 == -1 && tableId1 == eventId) ||
(tableId2 != -1 &&
(eventId >= tableId1 && eventId <= tableId2)))
{
event.Skip(FALSE);
event.m_callbackUserData = entry->m_callbackUserData;
(self->*((wxEventFunction) (entry->m_fn)))(event);
if (!event.GetSkipped())
return TRUE;
}
}
return FALSE;
}
return FALSE;
}
void wxEventHashTable::InitHashTable()
{
// Loop over the event tables and all its base tables.
const wxEventTable *table = &m_table;
while (table)
{
// Retrieve all valid event handler entries
const wxEventTableEntry *entry = table->entries;
while (entry->m_fn != 0)
{
// Add the event entry in the Hash.
AddEntry(*entry);
entry++;
}
table = table->baseTable;
}
// Lets free some memory.
size_t i;
for(i = 0; i < m_size; i++)
{
EventTypeTablePointer eTTnode = m_eventTypeTable[i];
if (eTTnode)
{
eTTnode->eventEntryTable.Shrink();
}
}
}
void wxEventHashTable::AddEntry(const wxEventTableEntry &entry)
{
EventTypeTablePointer *peTTnode = &m_eventTypeTable[entry.m_eventType % m_size];
EventTypeTablePointer eTTnode = *peTTnode;
if (eTTnode)
{
if (eTTnode->eventType != entry.m_eventType)
{
// Resize the table!
GrowEventTypeTable();
// Try again to add it.
AddEntry(entry);
return;
}
}
else
{
eTTnode = new EventTypeTable;
eTTnode->eventType = entry.m_eventType;
*peTTnode = eTTnode;
}
// Fill all hash entries between entry.m_id and entry.m_lastId...
eTTnode->eventEntryTable.Add(&entry);
}
void wxEventHashTable::AllocEventTypeTable(size_t size)
{
m_eventTypeTable = new EventTypeTablePointer[size];
memset((void *)m_eventTypeTable, 0, sizeof(EventTypeTablePointer)*size);
m_size = size;
}
void wxEventHashTable::GrowEventTypeTable()
{
size_t oldSize = m_size;
EventTypeTablePointer *oldEventTypeTable = m_eventTypeTable;
// TODO: Search the most optimal grow sequence
AllocEventTypeTable(/* GetNextPrime(oldSize) */oldSize*2+1);
for ( size_t i = 0; i < oldSize; /* */ )
{
EventTypeTablePointer eTToldNode = oldEventTypeTable[i];
if (eTToldNode)
{
EventTypeTablePointer *peTTnode = &m_eventTypeTable[eTToldNode->eventType % m_size];
EventTypeTablePointer eTTnode = *peTTnode;
// Check for collision, we don't want any.
if (eTTnode)
{
GrowEventTypeTable();
continue; // Don't increment the counter,
// as we still need to add this element.
}
else
{
// Get the old value and put it in the new table.
*peTTnode = oldEventTypeTable[i];
}
}
i++;
}
delete[] oldEventTypeTable;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxEvtHandler // wxEvtHandler
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -930,16 +1110,10 @@ bool wxEvtHandler::ProcessEvent(wxEvent& event)
if ( m_dynamicEvents && SearchDynamicEventTable(event) ) if ( m_dynamicEvents && SearchDynamicEventTable(event) )
return TRUE; return TRUE;
// Then static per-class event tables (and search upwards through the // Then static per-class event tables
// inheritance hierarchy) if ( GetEventHashTable().HandleEvent(event, this) )
for ( const wxEventTable *table = GetEventTable();
table;
table = table->baseTable )
{
if ( SearchEventTable((wxEventTable&)*table, event) )
return TRUE; return TRUE;
} }
}
// Try going down the event handler chain // Try going down the event handler chain
if ( GetNextHandler() ) if ( GetNextHandler() )
@@ -953,6 +1127,7 @@ bool wxEvtHandler::ProcessEvent(wxEvent& event)
return TryParent(event); return TryParent(event);
} }
bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event) bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event)
{ {
wxEventType eventType = event.GetEventType(); wxEventType eventType = event.GetEventType();