00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifndef CONVENIENTFREELIST_H
00020 #define CONVENIENTFREELIST_H
00021
00022 #include <QtCore/QVector>
00023 #include <QtCore/QPair>
00024
00025 #include <KDE/KDebug>
00026
00027 #include "embeddedfreetree.h"
00028 #include "kdevvarlengtharray.h"
00029
00030 namespace KDevelop {
00031
00032 template<class Data, class Handler>
00033 class ConvenientEmbeddedSetIterator;
00034 template<class Data, class Handler, class Data2, class Handler2, class KeyExtractor>
00035 class ConvenientEmbeddedSetFilterIterator;
00036
00038 template<class Data, class Handler>
00039 class ConstantConvenientEmbeddedSet {
00040 public:
00041 ConstantConvenientEmbeddedSet() : m_data(0), m_dataSize(0), m_centralFreeItem(-1) {
00042 }
00043 ConstantConvenientEmbeddedSet(const Data* data, uint count, int centralFreeItem) : m_data(data), m_dataSize(count), m_centralFreeItem(centralFreeItem) {
00044 }
00045
00047 bool contains(const Data& data) const {
00048 return indexOf(data) != -1;
00049 }
00050
00052 int indexOf(const Data& data) const {
00053 EmbeddedTreeAlgorithms<Data, Handler> alg(m_data, m_dataSize, m_centralFreeItem);
00054 return alg.indexOf(data);
00055 }
00056
00058 uint dataSize() const {
00059 return m_dataSize;
00060 }
00061
00062 uint countFreeItems() {
00063 EmbeddedTreeAlgorithms<Data, Handler> alg(m_data, m_dataSize, m_centralFreeItem);
00064 return alg.countFreeItems();
00065 }
00066
00067 void verify() {
00068 EmbeddedTreeAlgorithms<Data, Handler> alg(m_data, m_dataSize, m_centralFreeItem);
00069 alg.verifyTreeConsistent();
00070 alg.verifyOrder();
00071 }
00072
00074 const Data* data() const {
00075 return m_data;
00076 }
00077
00080 int lowerBound(const Data& data) const {
00081 EmbeddedTreeAlgorithms<Data, Handler> alg(m_data, m_dataSize, m_centralFreeItem);
00082 return alg.lowerBound(data, 0, m_dataSize);
00083 }
00084
00088 int lowerBound(const Data& data, uint start, uint end) const {
00089 EmbeddedTreeAlgorithms<Data, Handler> alg(m_data, m_dataSize, m_centralFreeItem);
00090 return alg.lowerBound(data, start, end);
00091 }
00092
00095 int validMiddle(uint start, uint end) {
00096 if(end <= start)
00097 return -1;
00098
00099 int firstTry = ((end-start)/2) + start;
00100
00101 int thisTry = firstTry;
00102 while(thisTry < (int)end && Handler::isFree(m_data[thisTry]))
00103 ++thisTry;
00104
00105 if(thisTry != (int)end)
00106 return thisTry;
00107
00108
00109 thisTry = firstTry-1;
00110 while(thisTry >= (int)start && Handler::isFree(m_data[thisTry]))
00111 --thisTry;
00112
00113 if(thisTry >= (int)start)
00114 return thisTry;
00115 else
00116 return -1;
00117 }
00118
00120 int firstValidItem(int start, int end = -1) const {
00121 if(end == -1)
00122 end = (int)m_dataSize;
00123 for(; start < end; ++start)
00124 if(!Handler::isFree(m_data[start]))
00125 return start;
00126
00127 return -1;
00128 }
00129
00131 int lastValidItem(int start = 0, int end = -1) const {
00132 if(end == -1)
00133 end = (int)m_dataSize;
00134 --end;
00135 for(; end >= start; --end)
00136 if(!Handler::isFree(m_data[end]))
00137 return end;
00138
00139 return -1;
00140 }
00141
00142 typedef ConvenientEmbeddedSetIterator<Data, Handler> Iterator;
00143
00144 ConvenientEmbeddedSetIterator<Data, Handler> iterator() const;
00145
00146
00147 const Data* m_data;
00148 uint m_dataSize;
00149 int m_centralFreeItem;
00150 };
00151
00153 template<class Data, class Handler>
00154 class ConvenientEmbeddedSetIterator : public ConstantConvenientEmbeddedSet<Data, Handler> {
00155 public:
00156 ConvenientEmbeddedSetIterator(const Data* data = 0, uint count = 0, int centralFreeItem = -1) : ConstantConvenientEmbeddedSet<Data, Handler>(data, count, centralFreeItem), m_pos(0) {
00157
00158 moveToValid();
00159 }
00160
00162 operator bool() const {
00163 return m_pos != this->m_dataSize;
00164 }
00165
00166 const Data* operator->() const {
00167 return &this->m_data[m_pos];
00168 }
00169
00170 const Data& operator*() const {
00171 return this->m_data[m_pos];
00172 }
00173
00174 ConvenientEmbeddedSetIterator& operator++() {
00175 ++m_pos;
00176 moveToValid();
00177 return *this;
00178 }
00179
00180 protected:
00181 inline void moveToValid() {
00182 while(this->m_pos < this->m_dataSize && (Handler::isFree(this->m_data[this->m_pos])))
00183 ++this->m_pos;
00184 }
00185 uint m_pos;
00186 };
00187
00188
00195 template<class Data, class Handler, class Data2, class Handler2, class KeyExtractor>
00196 class ConvenientEmbeddedSetFilterIterator : public ConvenientEmbeddedSetIterator<Data, Handler> {
00197 public:
00198 ConvenientEmbeddedSetFilterIterator() : m_match(-1) {
00199 }
00200 ConvenientEmbeddedSetFilterIterator(const ConvenientEmbeddedSetIterator<Data, Handler>& base, const ConvenientEmbeddedSetIterator<Data2, Handler2>& rhs) : ConvenientEmbeddedSetIterator<Data, Handler>(base), m_rhs(rhs), m_match(-1) {
00201 boundStack.append( qMakePair( qMakePair(0u, this->m_dataSize), qMakePair(0u, rhs.m_dataSize) ) );
00202 go();
00203 }
00204
00205 operator bool() const {
00206 return m_match != -1;
00207 }
00208
00209 const Data* operator->() const {
00210 Q_ASSERT(m_match != -1);
00211 return &this->m_data[m_match];
00212 }
00213
00214 const Data& operator*() const {
00215 Q_ASSERT(m_match != -1);
00216 return this->m_data[m_match];
00217 }
00218
00219 ConvenientEmbeddedSetFilterIterator& operator++() {
00220 Q_ASSERT(m_match != -1);
00221 go();
00222 return *this;
00223 }
00224 #define CHECK_BOUNDS Q_ASSERT(boundStack.back().first.first < 100000 && boundStack.back().first.second < 10000 && boundStack.back().second.first < 100000 && boundStack.back().second.second < 10000 );
00225
00226 private:
00227 void go() {
00228 m_match = -1;
00229
00230 boundsUp:
00231 if(boundStack.isEmpty())
00232 return;
00233 CHECK_BOUNDS
00234 QPair<QPair<uint, uint>, QPair<uint, uint> > currentBounds = boundStack.back();
00235 boundStack.pop_back();
00236
00237 uint ownStart = currentBounds.first.first, ownEnd = currentBounds.first.second;
00238 uint rhsStart = currentBounds.second.first, rhsEnd = currentBounds.second.second;
00239 #if 0
00240
00241 int ownFirstValid = this->firstValidItem(ownStart, ownEnd), ownLastValid = this->lastValidItem(ownStart, ownEnd);
00242 int rhsFirstValid = m_rhs.firstValidItem(rhsStart, rhsEnd), rhsLastValid = m_rhs.lastValidItem(rhsStart, rhsEnd);
00243
00244 if(ownFirstValid == -1 || rhsFirstValid == -1)
00245 goto boundsUp;
00246
00247
00248 Data2 ownFirstValidData = KeyExtractor::extract(this->m_data[ownFirstValid]);
00249 Data2 ownLastValidData = KeyExtractor::extract(this->m_data[ownLastValid]);
00250
00251 Data2 commonStart = ownFirstValidData;
00252 Data2 commonLast = ownLastValidData;
00253
00254 if(commonStart < m_rhs.m_data[rhsFirstValid])
00255 commonStart = m_rhs.m_data[rhsFirstValid];
00256
00257 if(m_rhs.m_data[rhsLastValid] < commonLast)
00258 commonLast = m_rhs.m_data[rhsLastValid];
00259
00260 if(commonLast < commonStart)
00261 goto boundsUp;
00262 #endif
00263
00264 while(true) {
00265 if(ownStart == ownEnd)
00266 goto boundsUp;
00267
00268 int ownMiddle = this->validMiddle(ownStart, ownEnd);
00269 Q_ASSERT(ownMiddle < 100000);
00270 if(ownMiddle == -1)
00271 goto boundsUp;
00272
00273 Data2 currentData2 = KeyExtractor::extract(this->m_data[ownMiddle]);
00274 Q_ASSERT(!Handler2::isFree(currentData2));
00275
00276 int bound = m_rhs.lowerBound(currentData2, rhsStart, rhsEnd);
00277 if(bound == -1) {
00278
00279
00280 ownEnd = ownMiddle;
00281 continue;
00282 }
00283
00284 if(currentData2 == m_rhs.m_data[bound]) {
00285
00286 this->m_match = ownMiddle;
00287
00288 boundStack.append( qMakePair( qMakePair( (uint)ownMiddle+1, ownEnd ), qMakePair((uint)bound, rhsEnd)) );
00289 if(ownMiddle)
00290 boundStack.append( qMakePair( qMakePair( ownStart, (uint)ownMiddle ), qMakePair(rhsStart, (uint)bound+1)) );
00291 return;
00292 }
00293
00294 if(bound == m_rhs.firstValidItem(rhsStart)) {
00295
00296
00297
00298 ownStart = ownMiddle+1;
00299 rhsStart = bound;
00300 continue;
00301 }
00302
00303
00304 boundStack.append( qMakePair( qMakePair( (uint)ownMiddle+1, ownEnd ), qMakePair((uint)bound, rhsEnd)) );
00305
00306 ownEnd = ownMiddle;
00307 rhsEnd = bound+1;
00308 }
00309 }
00310
00311
00312 KDevVarLengthArray<QPair<QPair<uint, uint>, QPair<uint, uint> > > boundStack;
00313 ConvenientEmbeddedSetIterator<Data2, Handler2> m_rhs;
00314 int m_match;
00315 };
00316
00318 template<class Data, class Handler, class Data2, class TreeSet, class KeyExtractor>
00319 class ConvenientEmbeddedSetTreeFilterIterator : public ConvenientEmbeddedSetIterator<Data, Handler> {
00320 public:
00321 ConvenientEmbeddedSetTreeFilterIterator() : m_match(-1) {
00322 }
00324 ConvenientEmbeddedSetTreeFilterIterator(const ConvenientEmbeddedSetIterator<Data, Handler>& base, const TreeSet& rhs, bool noFiltering = false) : ConvenientEmbeddedSetIterator<Data, Handler>(base), m_rhs(rhs), m_match(-1), m_noFiltering(noFiltering) {
00325 if(rhs.node().isValid()) {
00326
00327 int ownStart = lowerBound(rhs.node().firstItem(), 0, this->m_dataSize);
00328 if(ownStart == -1)
00329 return;
00330 int ownEnd = lowerBound(rhs.node().lastItem(), ownStart, this->m_dataSize);
00331 if(ownEnd == -1)
00332 ownEnd = this->m_dataSize;
00333 else
00334 ownEnd += 1;
00335 boundStack.append( qMakePair( qMakePair((uint)ownStart, (uint)ownEnd), rhs.node() ) );
00336 }
00337 go();
00338 }
00339
00340 operator bool() const {
00341 return m_match != -1;
00342 }
00343
00344 const Data* operator->() const {
00345 Q_ASSERT(m_match != -1);
00346 return &this->m_data[m_match];
00347 }
00348
00349 const Data& operator*() const {
00350 Q_ASSERT(m_match != -1);
00351 return this->m_data[m_match];
00352 }
00353
00354 ConvenientEmbeddedSetTreeFilterIterator& operator++() {
00355 Q_ASSERT(m_match != -1);
00356 go();
00357 return *this;
00358 }
00359 #define CHECK_BOUNDS Q_ASSERT(boundStack.back().first.first < 100000 && boundStack.back().first.second < 10000 && boundStack.back().second.first < 100000 && boundStack.back().second.second < 10000 );
00360
00361 private:
00362 void go() {
00363 if(m_noFiltering) {
00364 ++m_match;
00365 if((uint)m_match >= this->m_dataSize)
00366 m_match = -1;
00367 return;
00368 }
00369
00370 if(m_match != -1) {
00371
00372 m_match = this->firstValidItem(m_match+1, this->m_dataSize);
00373 if(m_match != -1 && KeyExtractor::extract(this->m_data[m_match]) == m_matchingTo)
00374 return;
00375 }
00376 m_match = -1;
00377
00378 boundsUp:
00379 if(boundStack.isEmpty())
00380 return;
00381 QPair<QPair<uint, uint>, typename TreeSet::Node > currentBounds = boundStack.back();
00382 boundStack.pop_back();
00383
00384 uint ownStart = currentBounds.first.first, ownEnd = currentBounds.first.second;
00385 typename TreeSet::Node currentNode = currentBounds.second;
00386
00387 if(ownStart >= ownEnd)
00388 goto boundsUp;
00389 if(!currentNode.isValid())
00390 goto boundsUp;
00391
00392 while(true) {
00393 if(ownStart == ownEnd)
00394 goto boundsUp;
00395
00396 if(currentNode.isFinalNode()) {
00397
00398
00399 int bound = lowerBound(*currentNode, ownStart, ownEnd);
00400
00401 if(bound != -1 && KeyExtractor::extract(this->m_data[bound]) == *currentNode) {
00402
00403 m_match = bound;
00404 m_matchingTo = *currentNode;
00405 m_matchBound = ownEnd;
00406 return;
00407 }else{
00408
00409 goto boundsUp;
00410 }
00411 }else{
00412
00413
00414 typename TreeSet::Node leftNode = currentNode.leftChild();
00415 typename TreeSet::Node rightNode = currentNode.rightChild();
00416 Q_ASSERT(leftNode.isValid());
00417 Q_ASSERT(rightNode.isValid());
00418
00419
00420 Data2 leftLastItem = leftNode.lastItem();
00421
00422 int rightSearchStart = lowerBound(rightNode.firstItem(), ownStart, ownEnd);
00423 if(rightSearchStart == -1)
00424 rightSearchStart = ownEnd;
00425 int leftSearchLast = lowerBound(leftLastItem, ownStart, rightSearchStart != -1 ? rightSearchStart : ownEnd);
00426 if(leftSearchLast == -1)
00427 leftSearchLast = rightSearchStart-1;
00428
00429 bool recurseLeft = false;
00430 if(leftSearchLast > (int)ownStart) {
00431 recurseLeft = true;
00432 }else if((int)ownStart == leftSearchLast) {
00433
00434 Data2 leftFoundStartData = KeyExtractor::extract(this->m_data[ownStart]);
00435 recurseLeft = leftFoundStartData < leftLastItem || leftFoundStartData == leftLastItem;
00436 }
00437
00438 bool recurseRight = false;
00439 if(rightSearchStart < (int)ownEnd)
00440 recurseRight = true;
00441
00442 if(recurseLeft && recurseRight) {
00443
00444 boundStack.append( qMakePair( qMakePair( (uint)rightSearchStart, ownEnd ), rightNode) );
00445 }
00446
00447 if(recurseLeft) {
00448 currentNode = leftNode;
00449 if(leftSearchLast != -1)
00450 ownEnd = leftSearchLast+1;
00451 }else if(recurseRight) {
00452 currentNode = rightNode;
00453 ownStart = rightSearchStart;
00454 }else{
00455 goto boundsUp;
00456 }
00457 }
00458 }
00459 }
00460
00463 int lowerBound(const Data2& data, int start, int end) {
00464 int currentBound = -1;
00465 while(1) {
00466 if(start >= end)
00467 return currentBound;
00468
00469 int center = (start + end)/2;
00470
00471
00472 for(; center < end; ) {
00473 if(!Handler::isFree(this->m_data[center]))
00474 break;
00475 ++center;
00476 }
00477
00478 if(center == end) {
00479 end = (start + end)/2;
00480 }else{
00481 Data2 centerData = KeyExtractor::extract(this->m_data[center]);
00482
00483 if(data == centerData || data < centerData) {
00484 currentBound = center;
00485 end = (start + end)/2;
00486 }else{
00487
00488 start = center+1;
00489 }
00490 }
00491 }
00492 }
00493
00494
00495 KDevVarLengthArray<QPair<QPair<uint, uint>, typename TreeSet::Node > > boundStack;
00496 TreeSet m_rhs;
00497 int m_match, m_matchBound;
00498 Data2 m_matchingTo;
00499 bool m_noFiltering;
00500 };
00501
00504 template<class Data, class Handler, class Data2, class TreeSet, class KeyExtractor, class Visitor>
00505 class ConvenientEmbeddedSetTreeFilterVisitor : public ConvenientEmbeddedSetIterator<Data, Handler> {
00506 public:
00507 ConvenientEmbeddedSetTreeFilterVisitor() {
00508 }
00509
00510 typedef QPair<QPair<uint, uint>, typename TreeSet::Node > Bounds;
00511
00512 struct Bound {
00513 inline Bound(uint s, uint e, const typename TreeSet::Node& n) : start(s), end(e), node(n) {
00514 }
00515 Bound() {
00516 }
00517 uint start;
00518 uint end;
00519 typename TreeSet::Node node;
00520 };
00521
00523 ConvenientEmbeddedSetTreeFilterVisitor(Visitor& visitor, const ConvenientEmbeddedSetIterator<Data, Handler>& base, const TreeSet& rhs, bool noFiltering = false) : ConvenientEmbeddedSetIterator<Data, Handler>(base), m_visitor(visitor), m_rhs(rhs), m_noFiltering(noFiltering) {
00524
00525 if(m_noFiltering) {
00526 for(uint a = 0; a < this->m_dataSize; ++a)
00527 visitor(this->m_data[a]);
00528 return;
00529 }
00530
00531 if(rhs.node().isValid()) {
00532
00533 int ownStart = lowerBound(rhs.node().firstItem(), 0, this->m_dataSize);
00534 if(ownStart == -1)
00535 return;
00536 int ownEnd = lowerBound(rhs.node().lastItem(), ownStart, this->m_dataSize);
00537 if(ownEnd == -1)
00538 ownEnd = this->m_dataSize;
00539 else
00540 ownEnd += 1;
00541
00542 go( Bound((uint)ownStart, (uint)ownEnd, rhs.node()) );
00543 }
00544 }
00545
00546 private:
00547 void go( Bound bound ) {
00548
00549 KDevVarLengthArray<Bound> bounds;
00550
00551 while(true) {
00552 if(bound.start >= bound.end)
00553 goto nextBound;
00554
00555 if(bound.node.isFinalNode()) {
00556
00557 int b = lowerBound(*bound.node, bound.start, bound.end);
00558 if(b != -1) {
00559 const Data2& matchTo(*bound.node);
00560
00561 if(KeyExtractor::extract(this->m_data[b]) == matchTo) {
00562 while(1) {
00563 m_visitor(this->m_data[b]);
00564 b = this->firstValidItem(b+1, this->m_dataSize);
00565 if(b < (int)this->m_dataSize && b != -1 && KeyExtractor::extract(this->m_data[b]) == matchTo)
00566 continue;
00567 else
00568 break;
00569 }
00570 }
00571 }
00572 goto nextBound;
00573 }else{
00574
00575 typename TreeSet::Node leftNode = bound.node.leftChild();
00576 typename TreeSet::Node rightNode = bound.node.rightChild();
00577 Q_ASSERT(leftNode.isValid());
00578 Q_ASSERT(rightNode.isValid());
00579
00580
00581 Data2 leftLastItem = leftNode.lastItem();
00582
00583 int rightSearchStart = lowerBound(rightNode.firstItem(), bound.start, bound.end);
00584 if(rightSearchStart == -1)
00585 rightSearchStart = bound.end;
00586 int leftSearchLast = lowerBound(leftLastItem, bound.start, rightSearchStart != -1 ? rightSearchStart : bound.end);
00587 if(leftSearchLast == -1)
00588 leftSearchLast = rightSearchStart-1;
00589
00590 bool recurseLeft = false;
00591 if(leftSearchLast > (int)bound.start) {
00592 recurseLeft = true;
00593 }else if((int)bound.start == leftSearchLast) {
00594
00595 Data2 leftFoundStartData = KeyExtractor::extract(this->m_data[bound.start]);
00596 recurseLeft = leftFoundStartData < leftLastItem || leftFoundStartData == leftLastItem;
00597 }
00598
00599 bool recurseRight = false;
00600 if(rightSearchStart < (int)bound.end)
00601 recurseRight = true;
00602
00603 if(recurseLeft && recurseRight)
00604 bounds.append( Bound(rightSearchStart, bound.end, rightNode) );
00605
00606 if(recurseLeft) {
00607 bound.node = leftNode;
00608 if(leftSearchLast != -1)
00609 bound.end = leftSearchLast+1;
00610 }else if(recurseRight) {
00611 bound.node = rightNode;
00612 bound.start = rightSearchStart;
00613 }else{
00614 goto nextBound;
00615 }
00616 continue;
00617 }
00618 nextBound:
00619 if(bounds.isEmpty()) {
00620 return;
00621 }else{
00622 bound = bounds.back();
00623 bounds.pop_back();
00624 }
00625 }
00626 }
00627
00630 int lowerBound(const Data2& data, int start, int end) {
00631 int currentBound = -1;
00632 while(1) {
00633 if(start >= end)
00634 return currentBound;
00635
00636 int center = (start + end)/2;
00637
00638
00639 for(; center < end; ) {
00640 if(!Handler::isFree(this->m_data[center]))
00641 break;
00642 ++center;
00643 }
00644
00645 if(center == end) {
00646 end = (start + end)/2;
00647 }else{
00648 Data2 centerData = KeyExtractor::extract(this->m_data[center]);
00649
00650 if(data == centerData || data < centerData) {
00651 currentBound = center;
00652 end = (start + end)/2;
00653 }else{
00654
00655 start = center+1;
00656 }
00657 }
00658 }
00659 }
00660
00661
00662 Visitor& m_visitor;
00663 TreeSet m_rhs;
00664 bool m_noFiltering;
00665 };
00666
00667 template<class Data, class Handler>
00668 ConvenientEmbeddedSetIterator<Data, Handler> ConstantConvenientEmbeddedSet<Data, Handler>::iterator() const {
00669 return ConvenientEmbeddedSetIterator<Data, Handler>(m_data, m_dataSize, m_centralFreeItem);
00670 }
00671
00683
00684 template<class Data, class Handler>
00685 class ConvenientFreeListSet {
00686 public:
00687
00688 typedef ConvenientEmbeddedSetIterator<Data, Handler> Iterator;
00689
00690 ConvenientFreeListSet() : m_centralFree(-1) {
00691 }
00692
00694 ConvenientFreeListSet(int centralFreeItem, QVector<Data> data) : m_data(data), m_centralFree(centralFreeItem) {
00695 }
00696
00698 int centralFreeItem() const {
00699 return m_centralFree;
00700 }
00701
00702 const QVector<Data>& data() const {
00703 return m_data;
00704 }
00705
00706 void insert(const Data& item) {
00707 if(contains(item))
00708 return;
00709 KDevelop::EmbeddedTreeAddItem<Data, Handler> add(m_data.data(), m_data.size(), m_centralFree, item);
00710
00711 if((int)add.newItemCount() != (int)m_data.size()) {
00712 QVector<Data> newData;
00713 newData.resize(add.newItemCount());
00714 add.transferData(newData.data(), newData.size());
00715 m_data = newData;
00716 }
00717 }
00718
00719 Iterator iterator() const {
00720 return Iterator(m_data.data(), m_data.size(), m_centralFree);
00721 }
00722
00723 bool contains(const Data& item) const {
00724 KDevelop::EmbeddedTreeAlgorithms<Data, Handler> alg(m_data.data(), m_data.size(), m_centralFree);
00725 return alg.indexOf(Data(item)) != -1;
00726 }
00727
00728 void remove(const Data& item) {
00729 KDevelop::EmbeddedTreeRemoveItem<Data, Handler> remove(m_data.data(), m_data.size(), m_centralFree, item);
00730
00731 if((int)remove.newItemCount() != (int)m_data.size()) {
00732 QVector<Data> newData;
00733 newData.resize(remove.newItemCount());
00734 remove.transferData(newData.data(), newData.size());
00735 m_data = newData;
00736 }
00737 }
00738
00739 private:
00740 int m_centralFree;
00741 QVector<Data> m_data;
00742 };
00743 }
00744
00745 #endif