Files
wxWidgets/src/common/windowid.cpp
Vadim Zeitlin 3f66f6a5b3 Remove all lines containing cvs/svn "$Id$" keyword.
This keyword is not expanded by Git which means it's not replaced with the
correct revision value in the releases made using git-based scripts and it's
confusing to have lines with unexpanded "$Id$" in the released files. As
expanding them with Git is not that simple (it could be done with git archive
and export-subst attribute) and there are not many benefits in having them in
the first place, just remove all these lines.

If nothing else, this will make an eventual transition to Git simpler.

Closes #14487.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2013-07-26 16:02:46 +00:00

301 lines
9.0 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/common/windowid.cpp
// Purpose: wxWindowID class - a class for managing window ids
// Author: Brian Vanderburg II
// Created: 2007-09-21
// Copyright: (c) 2007 Brian Vanderburg II
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// Needed headers
// ----------------------------------------------------------------------------
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/intl.h"
#endif //WX_PRECOMP
#include "wx/hashmap.h"
// Not needed, included in defs.h
// #include "wx/windowid.h"
#define wxTRACE_WINDOWID wxT("windowid")
namespace
{
#if wxUSE_AUTOID_MANAGEMENT
// initially no ids are in use and we allocate them consecutively, but after we
// exhaust the entire range, we wrap around and reuse the ids freed in the
// meanwhile
static const wxUint8 ID_FREE = 0;
static const wxUint8 ID_STARTCOUNT = 1;
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
wxWindowID gs_nextAutoId = wxID_AUTO_LOWEST;
// Reserve an ID
void ReserveIdRefCount(wxWindowID winid)
{
wxCHECK_RET(winid >= wxID_AUTO_LOWEST && winid <= wxID_AUTO_HIGHEST,
wxT("invalid id range"));
winid -= wxID_AUTO_LOWEST;
wxCHECK_RET(gs_autoIdsRefCount[winid] == ID_FREE,
wxT("id already in use or already reserved"));
gs_autoIdsRefCount[winid] = ID_RESERVED;
}
// Unreserve and id
void UnreserveIdRefCount(wxWindowID winid)
{
wxCHECK_RET(winid >= wxID_AUTO_LOWEST && winid <= wxID_AUTO_HIGHEST,
wxT("invalid id range"));
winid -= wxID_AUTO_LOWEST;
wxCHECK_RET(gs_autoIdsRefCount[winid] == ID_RESERVED,
wxT("id already in use or not reserved"));
gs_autoIdsRefCount[winid] = ID_FREE;
}
// Get the usage count of an id
int GetIdRefCount(wxWindowID winid)
{
wxCHECK_MSG(winid >= wxID_AUTO_LOWEST && winid <= wxID_AUTO_HIGHEST, 0,
wxT("invalid id range"));
winid -= wxID_AUTO_LOWEST;
int refCount = gs_autoIdsRefCount[winid];
if (refCount == ID_COUNTTOOLARGE)
refCount = (*gs_autoIdsLargeRefCount)[winid];
return refCount;
}
// Increase the count for an id
void IncIdRefCount(wxWindowID winid)
{
wxCHECK_RET(winid >= wxID_AUTO_LOWEST && winid <= wxID_AUTO_HIGHEST,
wxT("invalid id range"));
winid -= wxID_AUTO_LOWEST;
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, GetIdRefCount(winid + wxID_AUTO_LOWEST));
}
// Decrease the count for an id
void DecIdRefCount(wxWindowID winid)
{
wxCHECK_RET(winid >= wxID_AUTO_LOWEST && winid <= wxID_AUTO_HIGHEST,
wxT("invalid id range"));
winid -= wxID_AUTO_LOWEST;
wxCHECK_RET(gs_autoIdsRefCount[winid] != ID_FREE, wxT("id count already 0"));
// DecIdRefCount is only called on an ID that has been IncIdRefCount'ed'
// so it should never be reserved, but test anyway
if(gs_autoIdsRefCount[winid] == ID_RESERVED)
{
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, GetIdRefCount(winid + wxID_AUTO_LOWEST));
}
#else // wxUSE_AUTOID_MANAGEMENT
static wxWindowID gs_nextAutoId = wxID_AUTO_HIGHEST;
#endif
} // anonymous namespace
#if wxUSE_AUTOID_MANAGEMENT
void wxWindowIDRef::Assign(wxWindowID winid)
{
if ( winid != m_id )
{
// decrease count if it is in the managed range
if ( m_id >= wxID_AUTO_LOWEST && m_id <= wxID_AUTO_HIGHEST )
DecIdRefCount(m_id);
m_id = winid;
// increase count if it is in the managed range
if ( m_id >= wxID_AUTO_LOWEST && m_id <= wxID_AUTO_HIGHEST )
IncIdRefCount(m_id);
}
}
#endif // wxUSE_AUTOID_MANAGEMENT
wxWindowID wxIdManager::ReserveId(int count)
{
wxASSERT_MSG(count > 0, wxT("can't allocate less than 1 id"));
#if wxUSE_AUTOID_MANAGEMENT
if ( gs_nextAutoId + count - 1 <= wxID_AUTO_HIGHEST )
{
wxWindowID winid = gs_nextAutoId;
while(count--)
{
ReserveIdRefCount(gs_nextAutoId++);
}
return winid;
}
else
{
int found = 0;
for(wxWindowID winid = wxID_AUTO_LOWEST; winid <= wxID_AUTO_HIGHEST; winid++)
{
if(GetIdRefCount(winid) == 0)
{
found++;
if(found == count)
{
// Imagine this: 100 free IDs left. Then NewId(50) takes 50
// so 50 left. Then, the 25 before that last 50 are freed, but
// gs_nextAutoId does not decrement and stays where it is at
// with 50 free. Then NewId(75) gets called, and since there
// are only 50 left according to gs_nextAutoId, it does a
// search and finds the 75 at the end. Then NewId(10) gets
// called, and accorind to gs_nextAutoId, their are still
// 50 at the end so it returns them without testing the ref
// To fix this, the next ID is also updated here as needed
if(winid >= gs_nextAutoId)
gs_nextAutoId = winid + 1;
while(count--)
ReserveIdRefCount(winid--);
return winid + 1;
}
}
else
{
found = 0;
}
}
}
wxLogError(_("Out of window IDs. Recommend shutting down application."));
return wxID_NONE;
#else // !wxUSE_AUTOID_MANAGEMENT
// Make sure enough in the range
wxWindowID winid;
winid = gs_nextAutoId - count + 1;
if ( winid >= wxID_AUTO_LOWEST && winid <= wxID_AUTO_HIGHEST )
{
// There is enough, but it may be time to wrap
if(winid == wxID_AUTO_LOWEST)
gs_nextAutoId = wxID_AUTO_HIGHEST;
else
gs_nextAutoId = winid - 1;
return winid;
}
else
{
// There is not enough at the low end of the range or
// count was big enough to wrap around to the positive
// Surely 'count' is not so big to take up much of the range
gs_nextAutoId = wxID_AUTO_HIGHEST - count;
return gs_nextAutoId + 1;
}
#endif // wxUSE_AUTOID_MANAGEMENT/!wxUSE_AUTOID_MANAGEMENT
}
void wxIdManager::UnreserveId(wxWindowID winid, int count)
{
wxASSERT_MSG(count > 0, wxT("can't unreserve less than 1 id"));
#if wxUSE_AUTOID_MANAGEMENT
while (count--)
UnreserveIdRefCount(winid++);
#else
wxUnusedVar(winid);
wxUnusedVar(count);
#endif
}