00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef __GNUG__
00025 # pragma implementation "ChunkIterator.h"
00026 #endif
00027
00028 #include "StrMod/ChunkIterator.h"
00029 #include "StrMod/UseTrackingVisitor.h"
00030 #include <LCore/RefCounting.h>
00031 #include <vector>
00032 #include <algorithm>
00033
00034 namespace strmod {
00035 namespace strmod {
00036
00037
00038
00039
00040
00041 class StrChunk::__iterator::shared : public lcore::ReferenceCounting
00042 {
00043 public:
00044
00045
00046
00047 struct rawdata {
00048 const void *base_;
00049 unsigned int len_;
00050 };
00051 StrChunkPtr root_;
00052 rawdata *dataexts_;
00053 unsigned int numexts_;
00054 unsigned int length_;
00055
00056 inline shared(const StrChunkPtr &root);
00057
00058
00059
00060
00061 ~shared()
00062 {
00063 if (getStorage(*root_) == this)
00064 {
00065 setStorage(*root_, 0);
00066 }
00067 delete[] dataexts_;
00068 }
00069
00070
00071
00072
00073
00074 static shared *forStrChunk(const StrChunkPtr &chnk) {
00075 shared *tmp = static_cast<shared *>(getStorage(*chnk));
00076 if (!tmp)
00077 {
00078 tmp = new shared(chnk);
00079 }
00080 return(tmp);
00081 }
00082 };
00083
00084
00085
00086
00087 class StrChunk::__iterator::ExtVisitor : public UseTrackingVisitor {
00088 public:
00089
00090
00091
00092 ExtVisitor() : UseTrackingVisitor(true) { }
00093
00094 virtual ~ExtVisitor() { }
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109 void visit(const StrChunkPtr &root,
00110 shared::rawdata *&dataexts, unsigned int &numexts)
00111 {
00112 extvec_.clear();
00113 try {
00114 startVisit(root);
00115 numexts = extvec_.size();
00116 if (numexts > 0)
00117 {
00118 dataexts = new shared::rawdata[numexts];
00119 copy(extvec_.begin(), extvec_.end(), dataexts);
00120 }
00121 } catch (...) {
00122 extvec_.clear();
00123 throw;
00124 }
00125 extvec_.clear();
00126 }
00127
00128 protected:
00129
00130
00131
00132
00133 virtual void use_visitStrChunk(const StrChunkPtr &chunk,
00134 const LinearExtent &used)
00135 throw(halt_visitation) { }
00136
00137
00138
00139
00140 virtual void use_visitDataBlock(const void *start, size_t len,
00141 const void *realstart, size_t reallen)
00142 throw(halt_visitation)
00143 {
00144
00145
00146 if (len <= 0)
00147 {
00148 return;
00149 }
00150
00151 shared::rawdata data = {start, len};
00152
00153 extvec_.push_back(data);
00154 }
00155
00156 private:
00157 std::vector<shared::rawdata> extvec_;
00158 };
00159
00160
00161
00162
00163
00164
00165
00166 inline StrChunk::__iterator::shared::shared(const StrChunkPtr &root)
00167 : ReferenceCounting(0), root_(root), dataexts_(0), numexts_(0),
00168 length_(root->Length())
00169 {
00170 assert(root);
00171 ExtVisitor visitor;
00172 visitor.visit(root, dataexts_, numexts_);
00173 if (getStorage(*root) == 0)
00174 {
00175 setStorage(*root, this);
00176 }
00177 }
00178
00179
00180
00181 StrChunk::__iterator::__iterator()
00182 : shared_(0), abspos_(0), extpos_(0), extlast_(0), curext_(0), extbase_(0)
00183 {
00184 }
00185
00186 StrChunk::__iterator::__iterator(const StrChunkPtr &chnk)
00187 : shared_(0), abspos_(0), extpos_(0), extlast_(0), curext_(0), extbase_(0)
00188 {
00189 assert(chnk);
00190 shared_ = shared::forStrChunk(chnk);
00191 shared_->AddReference();
00192 moveToBegin();
00193 }
00194
00195 StrChunk::__iterator::__iterator(shared *sh)
00196 : shared_(sh), abspos_(0), extpos_(0), extlast_(0),
00197 curext_(0), extbase_(0)
00198 {
00199 if (shared_)
00200 {
00201 shared_->AddReference();
00202 moveToBegin();
00203 }
00204 }
00205
00206 StrChunk::__iterator::__iterator(const __iterator &other)
00207 : shared_(other.shared_), abspos_(other.abspos_), extpos_(other.extpos_),
00208 extlast_(other.extlast_), curext_(other.curext_),
00209 extbase_(other.extbase_)
00210 {
00211 if (shared_)
00212 {
00213 shared_->AddReference();
00214 }
00215 }
00216
00217 StrChunk::__iterator::~__iterator()
00218 {
00219 if (shared_)
00220 {
00221 if (shared_->NumReferences() <= 1)
00222 {
00223 delete shared_;
00224 }
00225 else
00226 {
00227 shared_->DelReference();
00228 }
00229 shared_ = 0;
00230 }
00231 }
00232
00233 inline bool StrChunk::__iterator::isFor(const StrChunkPtr &chnk) const
00234 {
00235 return shared_ && (shared_->root_.GetPtr() == chnk.GetPtr());
00236 }
00237
00238 const StrChunk::__iterator &
00239 StrChunk::__iterator::operator =(const __iterator &other)
00240 {
00241
00242 shared_->DelReference();
00243 other.shared_->AddReference();
00244 shared_->AddReference();
00245 if (shared_->NumReferences() <= 0)
00246 {
00247 delete shared_;
00248 }
00249 shared_ = other.shared_;
00250 abspos_ = other.abspos_;
00251 extpos_ = other.extpos_;
00252 extlast_ = other.extlast_;
00253 extbase_ = other.extbase_;
00254 curext_ = other.curext_;
00255 return(*this);
00256 };
00257
00258 bool StrChunk::__iterator::isEqual(const __iterator &other) const
00259 {
00260 if ((shared_ == other.shared_) ||
00261 (shared_ && other.shared_ &&
00262 (shared_->root_.GetPtr() == other.shared_->root_.GetPtr())))
00263 {
00264 return(abspos_ == other.abspos_);
00265 }
00266 return(false);
00267 }
00268
00269
00270
00271
00272
00273
00274
00275 bool StrChunk::__iterator::isLessThan(const __iterator &other) const
00276 {
00277 if ((shared_ == other.shared_) ||
00278 (shared_ && other.shared_ &&
00279 (shared_->root_.GetPtr() == other.shared_->root_.GetPtr())))
00280 {
00281 return(abspos_ < other.abspos_);
00282 }
00283 else
00284 {
00285 return(memcmp(&shared_, &(other.shared_), sizeof(shared_)) < 0);
00286 }
00287 }
00288
00289
00290
00291
00292
00293
00294
00295
00296 StrChunk::__iterator::difference_type
00297 StrChunk::__iterator::distance(const __iterator &other) const
00298 {
00299 if ((shared_ == other.shared_) ||
00300 (shared_ && other.shared_ &&
00301 (shared_->root_.GetPtr() == other.shared_->root_.GetPtr())))
00302 {
00303 return(abspos_ - other.abspos_);
00304 }
00305 else
00306 {
00307
00308
00309 return(0x10531053);
00310 }
00311 }
00312
00313 static const unsigned char junk = 'G';
00314
00315 void StrChunk::__iterator::moveToEnd()
00316 {
00317 if (!shared_)
00318 {
00319 return;
00320 }
00321 shared &shrd = *shared_;
00322 abspos_ = shrd.length_;
00323 curext_ = shrd.numexts_;
00324 extpos_ = 0;
00325 extbase_ = &junk;
00326 extlast_ = 0;
00327 }
00328
00329 void StrChunk::__iterator::moveToBegin()
00330 {
00331 if (!shared_)
00332 {
00333 return;
00334 }
00335 shared &shrd = *shared_;
00336 abspos_ = 0;
00337 curext_ = 0;
00338 extpos_ = 0;
00339 if (shrd.length_ > 0)
00340 {
00341 assert(shrd.numexts_ > 0);
00342 extbase_ = static_cast<const unsigned char *>(shrd.dataexts_[0].base_);
00343 extlast_ = shrd.dataexts_[0].len_ - 1;
00344 }
00345 else
00346 {
00347 extbase_ = &junk;
00348 extlast_ = 0;
00349 }
00350 }
00351
00352 void StrChunk::__iterator::move_forward_complex()
00353 {
00354 assert(extpos_ >= extlast_);
00355 if (extpos_ < extlast_)
00356 {
00357 ++extpos_;
00358 return;
00359 }
00360 if (shared_ == NULL)
00361 {
00362 return;
00363 }
00364 shared &shrd = *shared_;
00365 if ((shrd.length_ <= 0) || (abspos_ >= (shrd.length_ - 1)))
00366 {
00367 moveToEnd();
00368 return;
00369 }
00370 ++abspos_;
00371 assert(abspos_ < shrd.length_);
00372 ++curext_;
00373 assert(curext_ < shrd.numexts_);
00374 extpos_ = 0;
00375 extbase_ = static_cast<const unsigned char *>(shrd.dataexts_[curext_].base_);
00376 extlast_ = shrd.dataexts_[curext_].len_;
00377 assert(extlast_ > 0);
00378
00379
00380 --extlast_;
00381 }
00382
00383 void StrChunk::__iterator::move_backward_complex()
00384 {
00385 assert(extpos_ == 0);
00386 if (extpos_ != 0)
00387 {
00388 --extpos_;
00389 return;
00390 }
00391 if (shared_ == NULL)
00392 {
00393 return;
00394 }
00395 shared &shrd = *shared_;
00396 if (abspos_ <= 1)
00397 {
00398 moveToBegin();
00399 }
00400 else
00401 {
00402 assert(curext_ > 0);
00403 --abspos_;
00404 --curext_;
00405 extbase_ = static_cast<const unsigned char *>(shrd.dataexts_[curext_].base_);
00406 extlast_ = shrd.dataexts_[curext_].len_;
00407 assert(extlast_ > 0);
00408
00409
00410 --extlast_;
00411 extpos_ = extlast_;
00412 }
00413 }
00414
00415
00416
00417 StrChunk::__iterator StrChunk::begin()
00418 {
00419 return __iterator(this);
00420 }
00421
00422
00423 StrChunk::__iterator StrChunk::end()
00424
00425
00426
00427 {
00428
00429 __iterator tmp(this);
00430
00431 tmp.moveToEnd();
00432 return tmp;
00433 }
00434
00435 };
00436 };