00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #ifdef __GNUG__
00032 # pragma implementation "SimpleMulti.h"
00033 #endif
00034
00035 #include "StrMod/SimpleMulti.h"
00036 #include "StrMod/StrChunk.h"
00037 #include <UniEvent/Dispatcher.h>
00038 #include <UniEvent/Event.h>
00039 #include <UniEvent/EventPtr.h>
00040 #include <algorithm>
00041 #include <cassert>
00042
00043 namespace strmod {
00044 namespace strmod {
00045
00046
00047
00048 class SimpleMultiplexer::MultiPlug : public StreamModule::Plug
00049 {
00050 friend class SimpleMultiplexer;
00051 friend class SinglePlug;
00052 public:
00053 static const STR_ClassIdent identifier;
00054
00055 inline virtual int AreYouA(const lcore::ClassIdent &cid) const;
00056
00057 inline SimpleMultiplexer &getParent() const;
00058
00059 virtual int side() const { return(MultiSide); }
00060
00061
00062 bool getHasWritten() const { return(has_written_); }
00063
00064
00065 void setHasWritten(bool nval) { has_written_ = nval; }
00066
00067 protected:
00068
00069 inline MultiPlug(SimpleMultiplexer &parent);
00070
00071 inline virtual ~MultiPlug();
00072
00073 virtual const lcore::ClassIdent *i_GetIdent() const { return &identifier; }
00074
00075 virtual const StrChunkPtr i_Read();
00076
00077 virtual void i_Write(const StrChunkPtr &ptr);
00078
00079 virtual bool needsNotifyWriteable() const { return(true); }
00080 virtual bool needsNotifyReadable() const { return(true); }
00081
00082 virtual void otherIsReadable();
00083
00084 virtual void otherIsWriteable();
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095 void setListPos(const MPlugList::iterator &newpos) { listpos_ = newpos; }
00096
00097
00098 const MPlugList::iterator &getListPos() const { return(listpos_); }
00099
00100 private:
00101 MPlugList::iterator listpos_;
00102 bool has_written_;
00103 bool other_iswriteable_;
00104 bool other_isreadable_;
00105 };
00106
00107
00108
00109 class SimpleMultiplexer::ScanEvent : public unievent::Event {
00110 private:
00111 typedef unievent::Dispatcher Dispatcher;
00112 public:
00113 static const STR_ClassIdent identifier;
00114
00115
00116 ScanEvent(SimpleMultiplexer &parent) : parent_(&parent) { }
00117
00118 inline virtual void triggerEvent(Dispatcher *dispatcher = 0);
00119
00120 void parentGone() { parent_ = 0; }
00121
00122 protected:
00123 virtual const lcore::ClassIdent *i_GetIdent() { return &identifier; }
00124
00125 private:
00126 SimpleMultiplexer *parent_;
00127 };
00128
00129 int SimpleMultiplexer::MultiPlug::AreYouA(const lcore::ClassIdent &cid) const
00130 {
00131 return((identifier == cid) || Plug::AreYouA(cid));
00132 }
00133
00134 SimpleMultiplexer &SimpleMultiplexer::MultiPlug::getParent() const
00135 {
00136 return(static_cast<SimpleMultiplexer &>(Plug::getParent()));
00137 }
00138
00139 const STR_ClassIdent SimpleMultiplexer::identifier(21UL);
00140 const STR_ClassIdent SimpleMultiplexer::MultiPlug::identifier(22UL);
00141 const STR_ClassIdent SimpleMultiplexer::SinglePlug::identifier(23UL);
00142 const STR_ClassIdent SimpleMultiplexer::ScanEvent::identifier(32UL);
00143
00144 SimpleMultiplexer::MultiPlug::MultiPlug(SimpleMultiplexer &parent)
00145 : Plug(parent), has_written_(false),
00146 other_iswriteable_(false), other_isreadable_(false)
00147 {
00148 }
00149
00150 SimpleMultiplexer::MultiPlug::~MultiPlug()
00151 {
00152 unPlug();
00153 }
00154
00155 const StrChunkPtr SimpleMultiplexer::MultiPlug::i_Read()
00156 {
00157
00158 SimpleMultiplexer &parent = getParent();
00159
00160 assert(parent.mchunk_ && (parent.readable_multis_ > 0));
00161
00162 StrChunkPtr retval = parent.mchunk_;
00163
00164 parent.multiDidRead(*this);
00165
00166 return(retval);
00167 }
00168
00169 void SimpleMultiplexer::MultiPlug::i_Write(const StrChunkPtr &ptr)
00170 {
00171
00172
00173 assert(!has_written_);
00174 assert(getFlagsFrom(*this).canwrite_);
00175
00176 assert(getFlagsFrom(*this).iswriting_);
00177
00178
00179 SimpleMultiplexer &parent = getParent();
00180
00181
00182 assert((parent.splug_.pluggedInto() != 0)
00183 && (parent.splug_.pluggedInto()->isWriteable()));
00184
00185
00186 has_written_ = true;
00187 setWriteable(false);
00188
00189
00190
00191 if (other_isreadable_)
00192 {
00193 parent.adjustMultiReadables(ADJ_Down);
00194 }
00195
00196
00197
00198 assert((parent.splug_.pluggedInto() != 0)
00199 && (parent.splug_.pluggedInto()->isWriteable()));
00200
00201
00202 Plug &other = *parent.splug_.pluggedInto();
00203
00204 setIsWriting(other, true);
00205
00206
00207
00208
00209
00210 bool oldisread = getFlagsFrom(parent.splug_).isreading_;
00211 setIsReading(parent.splug_, true);
00212
00213 parent.splug_.writeOther(ptr);
00214
00215 setIsWriting(other, false);
00216 setIsReading(parent.splug_, oldisread);
00217
00218
00219 parent.postScan(*this);
00220 }
00221
00222 void SimpleMultiplexer::MultiPlug::otherIsReadable()
00223 {
00224
00225
00226 bool newreadable = false;
00227
00228 if (pluggedInto() == 0)
00229 {
00230 newreadable = false;
00231 }
00232 else
00233 {
00234 newreadable = getFlagsFrom(*(pluggedInto())).canread_;
00235 }
00236 if (newreadable != other_isreadable_)
00237 {
00238 other_isreadable_ = newreadable;
00239
00240
00241 if (!has_written_)
00242 {
00243 getParent().adjustMultiReadables(newreadable ? ADJ_Up : ADJ_Down);
00244 }
00245 }
00246 }
00247
00248 void SimpleMultiplexer::MultiPlug::otherIsWriteable()
00249 {
00250
00251
00252 bool newwriteable = false;
00253
00254 if (pluggedInto() == 0)
00255 {
00256 newwriteable = false;
00257 }
00258 else
00259 {
00260 newwriteable = getFlagsFrom(*(pluggedInto())).canwrite_;
00261 }
00262 if (newwriteable != other_iswriteable_)
00263 {
00264 other_iswriteable_ = newwriteable;
00265 getParent().adjustMultiWriteables(newwriteable ? ADJ_Up : ADJ_Down);
00266 }
00267 }
00268
00269 void SimpleMultiplexer::ScanEvent::triggerEvent(Dispatcher *dispatcher)
00270 {
00271 if (parent_ != 0)
00272 {
00273 parent_->doScan();
00274 }
00275 }
00276
00277
00278 class SimpleMultiplexer::mpother_readable_p {
00279 public:
00280 bool operator ()(MultiPlug *p) {
00281 return(!p->getHasWritten() && (p->pluggedInto() != 0)
00282 && p->pluggedInto()->isReadable());
00283 }
00284 };
00285
00286 const StrChunkPtr SimpleMultiplexer::SinglePlug::i_Read()
00287 {
00288
00289 SimpleMultiplexer &parent = getParent();
00290 MPlugList::iterator pptr;
00291 {
00292 MPlugList::iterator end = parent.mplugs_.end();
00293 pptr = find_if(parent.mplugs_.begin(), end,
00294 mpother_readable_p());
00295 assert(pptr != end);
00296 }
00297 MultiPlug &sibling = *(*pptr);
00298 assert(sibling.pluggedInto() != 0);
00299 assert(sibling.getHasWritten() == false);
00300 Plug &other = *(sibling.pluggedInto());
00301 assert(other.isReadable());
00302
00303 parent.setWriteableFlagFor(&sibling, false);
00304 sibling.setHasWritten(true);
00305 parent.postScan(sibling);
00306 parent.adjustMultiReadables(ADJ_Down);
00307 assert(other.isReadable());
00308
00309 setIsReading(other, true);
00310 StrChunkPtr retval = sibling.readOther();
00311 setIsReading(other, false);
00312
00313 return(retval);
00314 }
00315
00316
00317 class SimpleMultiplexer::auto_mpptr
00318 {
00319 public:
00320 auto_mpptr(MultiPlug **p) : p_(p) { }
00321 ~auto_mpptr() { delete[] p_; }
00322
00323 private:
00324 MultiPlug **p_;
00325 };
00326
00327
00328 class SimpleMultiplexer::mp_notpluggedin_p {
00329 public:
00330 bool operator ()(Plug *p) {
00331 return(p->pluggedInto() == 0);
00332 }
00333 };
00334
00335 void SimpleMultiplexer::SinglePlug::i_Write(const StrChunkPtr &chnk)
00336 {
00337
00338 SimpleMultiplexer &parent = getParent();
00339 assert(!parent.mchunk_);
00340 MultiPlug **scanplugs = new MultiPlug *[parent.mplugs_.size()];
00341 auto_mpptr delary(scanplugs);
00342
00343 MultiPlug **endscan = remove_copy_if(parent.mplugs_.begin(),
00344 parent.mplugs_.end(),
00345 scanplugs,
00346 mp_notpluggedin_p());
00347 parent.mchunk_ = chnk;
00348 parent.readable_multis_ = endscan - scanplugs;
00349 setWriteable(false);
00350 for (MultiPlug **curppp = scanplugs; curppp != endscan; ++curppp)
00351 {
00352 MultiPlug &curp = **curppp;
00353 assert(getFlagsFrom(curp).canread_ == false);
00354 if (curp.pluggedInto() != 0)
00355 {
00356
00357 curp.setReadable(true);
00358 }
00359 else
00360 {
00361 parent.multiDidRead(curp);
00362 }
00363 }
00364 }
00365
00366
00367 class SimpleMultiplexer::mp_written_p {
00368 public:
00369 bool operator ()(MultiPlug *p) {
00370 return(p->getHasWritten());
00371 }
00372 };
00373
00374 void SimpleMultiplexer::SinglePlug::otherIsWriteable()
00375 {
00376
00377 SimpleMultiplexer &parent = getParent();
00378 MultiPlug **scanplugs = new MultiPlug *[parent.mplugs_.size()];
00379 auto_mpptr delary(scanplugs);
00380
00381 MultiPlug **endscan = remove_copy_if(parent.mplugs_.begin(),
00382 parent.mplugs_.end(),
00383 scanplugs,
00384 mp_written_p());
00385
00386 for (MultiPlug **curppp = scanplugs; curppp != endscan; ++curppp)
00387 {
00388 MultiPlug &curp = **curppp;
00389 assert(curp.getHasWritten() == false);
00390 curp.setWriteable(pluggedInto()
00391 && getFlagsFrom(*pluggedInto()).canwrite_);
00392 }
00393 }
00394
00395 SimpleMultiplexer::SimpleMultiplexer(unievent::Dispatcher &disp)
00396 : splug_(*this), splug_created_(false), scan_posted_(false),
00397 scan_(new ScanEvent(*this)), dispatcher_(disp),
00398 readable_multis_(0), readable_multiothers_(0), writeable_multiothers_(0)
00399 {
00400 scan_->AddReference();
00401 }
00402
00403 SimpleMultiplexer::~SimpleMultiplexer()
00404 {
00405 scan_->parentGone();
00406 splug_.unPlug();
00407 while (mplugs_.size() > 0) {
00408 MultiPlug *mplug = mplugs_.front();
00409
00410 mplug->setListPos(mplugs_.end());
00411 mplugs_.pop_front();
00412 mplug->unPlug();
00413 delete mplug;
00414 }
00415 scan_->DelReference();
00416 if (scan_->NumReferences() <= 0)
00417 {
00418 delete scan_;
00419 }
00420 }
00421
00422 bool SimpleMultiplexer::ownsPlug(const Plug *plug) const
00423 {
00424 const StreamModule::Plug * const p = plug;
00425 if ((p == &splug_) && splug_created_) {
00426 return(true);
00427 } else {
00428 MPlugList::const_iterator end = mplugs_.end();
00429 return(find(mplugs_.begin(), end, plug) != end);
00430 }
00431 }
00432
00433 void SimpleMultiplexer::doPost()
00434 {
00435 dispatcher_.addEvent(scan_);
00436 }
00437
00438 void SimpleMultiplexer::moveToEnd(MultiPlug &toend)
00439 {
00440
00441 MPlugList::iterator oldpos = toend.getListPos();
00442 toend.setListPos(mplugs_.insert(mplugs_.end(), &toend));
00443 mplugs_.erase(oldpos);
00444 }
00445
00446 void SimpleMultiplexer::multiDidRead(MultiPlug &mplug)
00447 {
00448
00449
00450 assert(readable_multis_ > 0);
00451 setReadableFlagFor(&mplug, false);
00452
00453 if (--readable_multis_ == 0)
00454 {
00455
00456
00457 mchunk_.ReleasePtr();
00458 if (writeable_multiothers_ > 0)
00459 {
00460 setWriteableFlagFor(&splug_, true);
00461 }
00462 else
00463 {
00464 setWriteableFlagFor(&splug_, false);
00465 }
00466 }
00467 }
00468
00469 void SimpleMultiplexer::adjustMultiReadables(AdjDir dir)
00470 {
00471 assert((dir == ADJ_Down) || (dir == ADJ_Up));
00472 if (dir == ADJ_Down)
00473 {
00474 assert(readable_multiothers_ > 0);
00475 if (--readable_multiothers_ == 0)
00476 {
00477 setReadableFlagFor(&splug_, false);
00478 }
00479 }
00480 else
00481 {
00482 assert(readable_multiothers_ < mplugs_.size());
00483 ++readable_multiothers_;
00484 setReadableFlagFor(&splug_, true);
00485 }
00486 }
00487
00488 void SimpleMultiplexer::adjustMultiWriteables(AdjDir dir)
00489 {
00490 assert((dir == ADJ_Down) || (dir == ADJ_Up));
00491 if (dir == ADJ_Down)
00492 {
00493 assert(writeable_multiothers_ > 0);
00494 if (--writeable_multiothers_ == 0)
00495 {
00496 setWriteableFlagFor(&splug_, false);
00497 }
00498 }
00499 else
00500 {
00501 assert(writeable_multiothers_ < mplugs_.size());
00502 ++writeable_multiothers_;
00503 if (!mchunk_)
00504 {
00505 setWriteableFlagFor(&splug_, true);
00506 }
00507 }
00508 }
00509
00510 inline void SimpleMultiplexer::plugDisconnected(Plug *plug)
00511 {
00512 if (plug->side() == MultiSide)
00513 {
00514 MultiPlug * const mp = static_cast<MultiPlug *>(plug);
00515
00516 if (mp->getFlagsFrom(*mp).canread_)
00517 {
00518 multiDidRead(*mp);
00519 }
00520 mp->otherIsReadable();
00521 mp->otherIsWriteable();
00522 }
00523 else
00524 {
00525 splug_.otherIsWriteable();
00526 }
00527 }
00528
00529 StreamModule::Plug *SimpleMultiplexer::i_MakePlug(int side)
00530 {
00531 if ((side == SingleSide) && !splug_created_)
00532 {
00533 splug_created_ = true;
00534 return(&splug_);
00535 }
00536 else if (side == MultiSide)
00537 {
00538 MultiPlug *mp = new MultiPlug(*this);
00539 mplugs_.push_front(mp);
00540 mp->setListPos(mplugs_.begin());
00541 if (splug_.pluggedInto() != 0)
00542 {
00543 bool writeflag = splug_.getFlagsFrom(*splug_.pluggedInto()).canread_;
00544 setWriteableFlagFor(mp, writeflag);
00545 }
00546 return(mp);
00547 }
00548 else
00549 {
00550 assert(false);
00551 return(0);
00552 }
00553 }
00554
00555 void SimpleMultiplexer::doScan()
00556 {
00557
00558
00559 while (delplugs_.size() > 0)
00560 {
00561 MultiPlug * const mp = delplugs_.front();
00562 assert(mp->pluggedInto() == 0);
00563 MPlugList::iterator pos = mp->getListPos();
00564 mp->setListPos(mplugs_.end());
00565 mplugs_.erase(pos);
00566 delplugs_.pop_front();
00567 delete mp;
00568 }
00569
00570 scan_posted_ = false;
00571 MultiPlug **scanplugs = new MultiPlug *[mplugs_.size()];
00572 auto_mpptr delary(scanplugs);
00573
00574 MultiPlug **endscan = copy(mplugs_.begin(), mplugs_.end(), scanplugs);
00575 for (MultiPlug **curppp = scanplugs; curppp != endscan; ++curppp)
00576 {
00577 MultiPlug &curp = **curppp;
00578 if (curp.getHasWritten())
00579 {
00580
00581 assert(splug_.getFlagsFrom(curp).canwrite_ == false);
00582 curp.setHasWritten(false);
00583 if (curp.pluggedInto()
00584 && curp.getFlagsFrom(*curp.pluggedInto()).canread_)
00585 {
00586 adjustMultiReadables(ADJ_Up);
00587 }
00588 }
00589 if (!curp.getHasWritten())
00590 {
00591 const bool writeflag = splug_.pluggedInto()
00592 && splug_.getFlagsFrom(*splug_.pluggedInto()).canwrite_;
00593
00594
00595
00596
00597 curp.setWriteable(writeflag);
00598 }
00599 }
00600
00601 }
00602
00603 bool SimpleMultiplexer::deletePlug(Plug *plug)
00604 {
00605 if ((&splug_ == plug) && splug_created_)
00606 {
00607 splug_.unPlug();
00608 splug_created_ = false;
00609 return(true);
00610 }
00611 else
00612 {
00613 MPlugList::iterator end = mplugs_.end();
00614 MPlugList::iterator search = find(mplugs_.begin(), end, plug);
00615 if (search != end)
00616 {
00617 MultiPlug * const mp = *search;
00618 assert(mp == plug);
00619 mp->unPlug();
00620 delplugs_.push_front(mp);
00621 postScan(*mp);
00622 return(true);
00623 }
00624 }
00625 return false;
00626 }
00627
00628 }
00629 }