Version 2.6
[qgit4/redivivus.git] / src / exceptionmanager.cpp
blob7c830b11bab95fa70263f627c1723ee581b8234e
1 /*
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
12 #include <QList>
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) {
23 *excp = excpId++;
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);
35 if (match) {
36 QString info("Caught exception \'" + descriptions[excp] +
37 "\' while in " + context);
38 qDebug("%s", info.toLatin1().constData());
40 return match;
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);
61 return;
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);
67 return;
69 regionThrowableSet.erase(itReg);
71 // remove from total.
72 SetIt itTot(totalThrowableSet.begin());
73 if ((*itTot).excpId != excpId) {
74 qDebug("ASSERT in remove: %i is not the first in list", excpId);
75 return;
77 totalThrowableSet.erase(itTot);
80 ExceptionManager::SetIt ExceptionManager::findExcp(ThrowableSet& ts,
81 const SetIt& startIt, int excpId) {
83 SetIt it(startIt);
84 for ( ; it != ts.end(); ++it)
85 if ((*it).excpId == excpId)
86 break;
87 return it;
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())
102 return;
104 // check totalThrowableSet to find if excpId is throwable
105 SetIt it = findExcp(totalThrowableSet, totalThrowableSet.begin(), excpId);
106 if (it == totalThrowableSet.end())
107 return;
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);
116 ++itList;
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);
141 return;
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)
156 return true;
157 ++itList;
159 return false;
162 void ExceptionManager::throwPending() {
164 if (regionThrowableSet.isEmpty())
165 return;
167 ThrowableSet::const_iterator it(regionThrowableSet.constBegin());
168 for ( ; it != regionThrowableSet.constEnd(); ++it)
169 if ((*it).isRaised)
170 break;
172 if (it == regionThrowableSet.constEnd())
173 return;
175 int excpToThrow = (*it).excpId;
176 if ((*it).verbose)
177 qDebug("Thrown exception \'%s\'", desc(excpToThrow).toLatin1().constData());
179 throw excpToThrow;