]> git.saurik.com Git - wxWidgets.git/commitdiff
Allow reusing the same wxWindowID more than 254 times.
authorVadim Zeitlin <vadim@wxwidgets.org>
Sat, 5 Nov 2011 11:24:04 +0000 (11:24 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sat, 5 Nov 2011 11:24:04 +0000 (11:24 +0000)
Extend the id reference count storage to use an overflow hash map for the ids
used more than 254 times. This allows to use the same id an arbitrarily large
number of times.

Closes #13618.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@69682 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
src/common/windowid.cpp

index 84207570872559b440aafe5516715b2385791b63..5048f67c6743e749f21431713768fbee9858e924 100644 (file)
@@ -489,6 +489,7 @@ All (GUI):
 - Added wxDataViewCustomRenderer::ActivateCell().
 - Add "checked" property for toolbar tool elements in XRC.
 - Allow customization of the locations where persistent settings are stored.
+- Restore support for reusing ids more than 254 times (Armel Asselin).
 
 OSX:
 
index 795b8c6260d21deb43961725a3920f5e0122d13f..609188384ca66eab0b1cc26d172fc19c3e9058c6 100644 (file)
@@ -22,6 +22,8 @@
     #include "wx/intl.h"
 #endif //WX_PRECOMP
 
+#include "wx/hashmap.h"
+
 // Not needed, included in defs.h
 // #include "wx/windowid.h"
 
@@ -38,11 +40,22 @@ namespace
 // meanwhile
 static const wxUint8 ID_FREE = 0;
 static const wxUint8 ID_STARTCOUNT = 1;
-static const wxUint8 ID_MAXCOUNT = 254;
+static const wxUint8 ID_COUNTTOOLARGE = 254;
 static const wxUint8 ID_RESERVED = 255;
 
+// we use a two level count, most IDs will be used less than ID_COUNTTOOLARGE-1
+// thus we store their count directly in this array, however when the same ID
+// is reused a great number of times (more than or equal to ID_COUNTTOOLARGE),
+// the hash map stores the actual count
 wxUint8 gs_autoIdsRefCount[wxID_AUTO_HIGHEST - wxID_AUTO_LOWEST + 1] = { 0 };
 
+// NB: this variable is allocated (again) only when an ID gets at least
+// ID_COUNTTOOLARGE refs, and is freed when the latest entry in the map gets
+// freed. The cell storing the count for an ID is freed only when its count
+// gets to zero (not when it goes below ID_COUNTTOOLARGE, so as to avoid
+// degenerate cases)
+wxLongToLongHashMap *gs_autoIdsLargeRefCount = NULL;
+
 // this is an optimization used until we wrap around wxID_AUTO_HIGHEST: if this
 // value is < wxID_AUTO_HIGHEST we know that we haven't wrapped yet and so can
 // allocate the ids simply by incrementing it
@@ -81,7 +94,10 @@ int GetIdRefCount(wxWindowID winid)
             wxT("invalid id range"));
 
     winid -= wxID_AUTO_LOWEST;
-    return gs_autoIdsRefCount[winid];
+    int refCount = gs_autoIdsRefCount[winid];
+    if (refCount == ID_COUNTTOOLARGE)
+        refCount = (*gs_autoIdsLargeRefCount)[winid];
+    return refCount;
 }
 
 // Increase the count for an id
@@ -92,16 +108,32 @@ void IncIdRefCount(wxWindowID winid)
 
     winid -= wxID_AUTO_LOWEST;
 
-    wxCHECK_RET(gs_autoIdsRefCount[winid] != ID_MAXCOUNT, wxT("id count at max"));
     wxCHECK_RET(gs_autoIdsRefCount[winid] != ID_FREE, wxT("id should first be reserved"));
 
     if(gs_autoIdsRefCount[winid] == ID_RESERVED)
+    {
         gs_autoIdsRefCount[winid] = ID_STARTCOUNT;
+    }
+    else if (gs_autoIdsRefCount[winid] >= ID_COUNTTOOLARGE-1)
+    {
+        if (gs_autoIdsRefCount[winid] == ID_COUNTTOOLARGE-1)
+        {
+            // we need to allocate a cell, and maybe the hash map itself
+            if (!gs_autoIdsLargeRefCount)
+                gs_autoIdsLargeRefCount = new wxLongToLongHashMap;
+            (*gs_autoIdsLargeRefCount)[winid] = ID_COUNTTOOLARGE-1;
+
+            gs_autoIdsRefCount[winid] = ID_COUNTTOOLARGE;
+        }
+        ++(*gs_autoIdsLargeRefCount)[winid];
+    }
     else
+    {
         gs_autoIdsRefCount[winid]++;
+    }
 
     wxLogTrace(wxTRACE_WINDOWID, wxT("Increasing ref count of ID %d to %d"),
-            winid + wxID_AUTO_LOWEST, gs_autoIdsRefCount[winid]);
+            winid + wxID_AUTO_LOWEST, GetIdRefCount(winid + wxID_AUTO_LOWEST));
 }
 
 // Decrease the count for an id
@@ -121,11 +153,24 @@ void DecIdRefCount(wxWindowID winid)
         wxFAIL_MSG(wxT("reserve id being decreased"));
         gs_autoIdsRefCount[winid] = ID_FREE;
     }
+    else if(gs_autoIdsRefCount[winid] == ID_COUNTTOOLARGE)
+    {
+        long &largeCount = (*gs_autoIdsLargeRefCount)[winid];
+        --largeCount;
+        if (largeCount == 0)
+        {
+            gs_autoIdsLargeRefCount->erase (winid);
+            gs_autoIdsRefCount[winid] = ID_FREE;
+
+            if (gs_autoIdsLargeRefCount->empty())
+                wxDELETE (gs_autoIdsLargeRefCount);
+        }
+    }
     else
         gs_autoIdsRefCount[winid]--;
 
     wxLogTrace(wxTRACE_WINDOWID, wxT("Decreasing ref count of ID %d to %d"),
-            winid + wxID_AUTO_LOWEST, gs_autoIdsRefCount[winid]);
+            winid + wxID_AUTO_LOWEST, GetIdRefCount(winid + wxID_AUTO_LOWEST));
 }
 
 #else // wxUSE_AUTOID_MANAGEMENT