2 Description: Support for recursive C++ exception handling
3 compatible with Qt qApp->processEvents()
5 See exception_manager.txt for details.
7 Author: Marco Costalba (C) 2005-2007
9 Copyright: See COPYING file that comes with this distribution
13 #include "exceptionmanager.h"
15 ExceptionManager::ExceptionManager() {
17 excpId
= regionId
= currentRegionId
= 1;
18 descriptions
.append("we start from 1");
21 void ExceptionManager::init(int* excp
, const QString
& desc
) {
24 descriptions
.append(desc
);
27 const QString
ExceptionManager::desc(int excpId
) {
29 return descriptions
[excpId
];
32 bool ExceptionManager::isMatch(int value
, int excp
, const QString
& context
) {
34 bool match
= (value
== excp
);
36 QString
info("Caught exception \'" + descriptions
[excp
] +
37 "\' while in " + context
);
38 qDebug("%s", info
.toLatin1().constData());
43 void ExceptionManager::add(int excpId
, bool verbose
) {
44 // add a new exception in currentThrowableSet
46 // are prepended so to use a for loop starting
47 // from begin to find the latest. Exceptions are
48 // always added/removed from both totalThrowableSet
49 // and regionThrowableSet
50 totalThrowableSet
.prepend(Exception(excpId
, verbose
));
51 regionThrowableSet
.prepend(Exception(excpId
, verbose
));
54 void ExceptionManager::remove(int excpId
) {
55 // removes ONE exception in totalThrowableSet and ONE in regionThrowableSet.
56 // if add and remove calls are correctly nested the removed
57 // excp should be the first in both throwable sets
59 if (totalThrowableSet
.isEmpty() || regionThrowableSet
.isEmpty()) {
60 qDebug("ASSERT in remove: removing %i from an empty set", excpId
);
63 // remove from region.
64 SetIt
itReg(regionThrowableSet
.begin());
65 if ((*itReg
).excpId
!= excpId
) {
66 qDebug("ASSERT in remove: %i is not the first in list", excpId
);
69 regionThrowableSet
.erase(itReg
);
72 SetIt
itTot(totalThrowableSet
.begin());
73 if ((*itTot
).excpId
!= excpId
) {
74 qDebug("ASSERT in remove: %i is not the first in list", excpId
);
77 totalThrowableSet
.erase(itTot
);
80 ExceptionManager::SetIt
ExceptionManager::findExcp(ThrowableSet
& ts
,
81 const SetIt
& startIt
, int excpId
) {
84 for ( ; it
!= ts
.end(); ++it
)
85 if ((*it
).excpId
== excpId
)
90 void ExceptionManager::setRaisedFlag(ThrowableSet
& ts
, int excpId
) {
92 SetIt
it(findExcp(ts
, ts
.begin(), excpId
));
93 while (it
!= ts
.end()) {
94 (*it
).isRaised
= true;
95 it
= findExcp(ts
, ++it
, excpId
);
99 void ExceptionManager::raise(int excpId
) {
101 if (totalThrowableSet
.isEmpty())
104 // check totalThrowableSet to find if excpId is throwable
105 SetIt it
= findExcp(totalThrowableSet
, totalThrowableSet
.begin(), excpId
);
106 if (it
== totalThrowableSet
.end())
109 // we have found an exception. Set raised flag in regionThrowableSet
110 setRaisedFlag(regionThrowableSet
, excpId
);
112 // then set the flag in all regions throwableSetList
113 QMap
<int, ThrowableSet
>::iterator
itList(throwableSetMap
.begin());
114 while (itList
!= throwableSetMap
.end()) {
115 setRaisedFlag(*itList
, excpId
);
120 int ExceptionManager::saveThrowableSet() {
121 // here we save regionThrowableSet _and_ update the region.
122 // regionThrowableSet is saved with the current region index.
123 // then current region is changed to a new and never used index
125 int oldCurrentRegionId
= currentRegionId
;
126 throwableSetMap
.insert(currentRegionId
, regionThrowableSet
);
127 currentRegionId
= ++regionId
;
129 // we use this call to trigger a region boundary crossing
130 // so we have to clear the new region throwables. We still
131 // have totalThrowableSet to catch any request.
132 regionThrowableSet
.clear();
134 return oldCurrentRegionId
;
137 void ExceptionManager::restoreThrowableSet(int regionId
) {
139 if (!throwableSetMap
.contains(regionId
)) {
140 qDebug("ASSERT in restoreThrowableSet: region %i not found", regionId
);
143 regionThrowableSet
= throwableSetMap
[regionId
];
144 throwableSetMap
.remove(regionId
);
147 bool ExceptionManager::isPending(int excpId
) {
149 // check in ALL regions if an exception request is pending
150 QMap
<int, ThrowableSet
>::const_iterator
itList(throwableSetMap
.constBegin());
151 while (itList
!= throwableSetMap
.constEnd()) {
153 ThrowableSet::const_iterator
it((*itList
).constBegin());
154 for ( ; it
!= (*itList
).constEnd(); ++it
)
155 if ((*it
).isRaised
&& (*it
).excpId
== excpId
)
162 void ExceptionManager::throwPending() {
164 if (regionThrowableSet
.isEmpty())
167 ThrowableSet::const_iterator
it(regionThrowableSet
.constBegin());
168 for ( ; it
!= regionThrowableSet
.constEnd(); ++it
)
172 if (it
== regionThrowableSet
.constEnd())
175 int excpToThrow
= (*it
).excpId
;
177 qDebug("Thrown exception \'%s\'", desc(excpToThrow
).toLatin1().constData());