Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

interfaces_impl.h

Go to the documentation of this file.
00001 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU Lesser General Public            *
00013  *   License as published by the Free Software Foundation; either          *
00014  *   version 2.1 of the License, or (at your option) any later version.    *
00015  *                                                                         *
00016  *   This library is distributed in the hope that it will be useful,       *
00017  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00018  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00019  *   Lesser General Public License for more details.                       *
00020  *                                                                         *
00021  *   You should have received a copy of the GNU Lesser General Public      *
00022  *   License along with this library; if not, write to the Free Software   *
00023  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
00024  *   MA  02111-1307  USA                                                   *
00025  *                                                                         *
00026  ***************************************************************************/
00027 
00028 
00043 #ifndef INTERFACES_IMPL_H
00044 #define INTERFACES_IMPL_H
00045 
00046 
00047 #include <cassert>
00048 #include <iostream>
00049 
00050 #include <simthetic/interfaces.h>
00051 #include <simthetic/basicdevice.h>
00052 #include <simthetic/phbib.h>
00053 
00054 namespace simth
00055 {
00056 
00057 template<class T>
00058 InputInterfaceT<T>::InputInterfaceT(Device* const dev, 
00059                     int ID, size_t sequenceLength,
00060                     const typename T::value_type& default_val)
00061    : InputInterface(dev,ID)
00062    , seqBuffer(new buffer_type(0,default_val))
00063    , inputSubSeq(new access_type(seqBuffer->begin(),
00064                  seqBuffer->begin(),
00065                  *seqBuffer))
00066    , outputSubSeq(new access_type(seqBuffer->begin(),
00067                   seqBuffer->begin(),
00068                   *seqBuffer))
00069    , storedElements_(0)
00070    , sequenceLength_(sequenceLength)
00071    , refCount(0)
00072    , waitingForProcess(false)
00073 {
00074    invariante();
00075 }
00076 
00077 template<class T>
00078 InputInterfaceT<T>::InputInterfaceT(Device* const dev,
00079                                     int ID,
00080                                     const typename T::value_type&
00081                                     default_val)
00082    : InputInterface(dev,ID)
00083    , seqBuffer(new buffer_type(0, default_val))
00084    , inputSubSeq(new access_type(seqBuffer->begin(),
00085                  seqBuffer->begin(),
00086                  *seqBuffer))
00087    , outputSubSeq(new access_type(seqBuffer->begin(),
00088                   seqBuffer->begin(),
00089                   *seqBuffer))
00090    , storedElements_(0)
00091    , sequenceLength_(undefinedLength)
00092    , refCount(0)
00093    , waitingForProcess(false)
00094 {
00095    invariante();
00096 }
00097 
00098 template<class T>
00099 InputInterfaceT<T>::~InputInterfaceT()
00100 {
00101    if (std::uncaught_exception()) { //destructor is called while catching an exception.
00102       //In this case no exception should be thrown, otherwise
00103       //the program will be terminated (see Stroustrup S.398)
00104       try {
00105      delete seqBuffer;
00106      delete inputSubSeq;
00107      delete outputSubSeq;
00108       }
00109       catch(...) {
00110      std::cerr<<("InputInterface::~InputInterface() : error 1");
00111       }
00112    }
00113    else {
00114       try {
00115      delete seqBuffer;
00116      delete inputSubSeq;
00117      delete outputSubSeq;
00118       }
00119       catch(...) {
00120      throw std::logic_error("InputInterface::~InputInterface() : error 2");
00121       }
00122    }
00123 }
00124 
00125 
00126 template<class T>
00127 T* InputInterfaceT<T>::internSequence( )
00128 {
00129    if (storedElements() < sequenceLength_) {
00130       throw std::runtime_error(
00131      "InputInterface::internSequence: "
00132      "Sequence was not filled completely"
00133      ", in input iface "+simth::i2string(ID())
00134      +" of device nr. "+simth::i2string(device()->ID())
00135      +" (storedElements()== "+simth::i2string(storedElements())
00136      +" < sequenceLength()== "+simth::i2string(sequenceLength_)+"). "
00137      "You will most likely encounter this message if you try "
00138      "to call getInputSequence() without checking first that the "
00139      "sequence has been filled completely "
00140      "(by Interface::isFilled() or Device::isInputSequence()).");
00141    }
00142    if (refCount != 0) {
00143       throw std::runtime_error
00144      ("InputInterface::internSequence: "
00145       "At least one reference copy exists"
00146       ", in input iface "+simth::i2string(ID())
00147       +" of device +"+simth::i2string(device()->ID())+". "
00148       "You will most likely encounter this message if you try "
00149       "to call this function (e.g. via Device::getInputSequence()) " 
00150       "two times consecutively without flushing the interface "
00151       "(e.g. via Device::flushProcessedSequences()) in between.");
00152    }
00153    if (sequenceLength_ == undefinedLength) {
00154       throw std::runtime_error
00155      ("InputInterfaceT<T>::internSequence( ) : "
00156       "sequence length is undefined -> "
00157       "shouldn't happen since it should already been "
00158       "set in the function acceptNewData(..)"
00159       ", in input iface "+simth::i2string(ID())
00160       +" of device "+simth::i2string(device()->ID()));
00161    }
00162 
00163    if (sequenceLength_ == 0) {
00164       // in that case set the sequence length to the number of
00165       // received and so far not processed elements:
00166       device()->setInputLength(storedElements(),ID());
00167    }
00168 
00169    // Take the number of elements specified by sequenceLength():
00170    outputSubSeq->seek(seqBuffer->begin(),
00171               seqBuffer->begin() + sequenceLength_);
00172    incrementRefCount();
00173 
00174    return outputSubSeq;
00175 }
00176 
00177 
00178 
00179 template<class T>
00180 void InputInterfaceT<T>::reset()
00181 {
00182    seqBuffer->resize(0);
00183    inputSubSeq->seek(seqBuffer->begin(),seqBuffer->begin());
00184    outputSubSeq->seek(seqBuffer->begin(),seqBuffer->begin());
00185    storedElements_ = 0;
00186    waitingForProcess = false;
00187    refCount = 0;
00188 }
00189 
00190 template<class T>
00191 void InputInterfaceT<T>::acceptNewData(size_t size)
00192 {
00193    assert(refCount == 1);
00194 
00195    storedElements_ += size;
00196    invariante();
00197 
00198    decrementRefCount();
00199 
00200    if (!waitingForProcess)
00201    {
00202      
00203       // Sequencelength is so far either undefined or zero.
00204       if (sequenceLength_ == undefinedLength || sequenceLength_ == 0)
00205       {
00206      // Update the sequence length immediately;
00207      // Device::setInputLength will call setSequenceLength
00208      // anyway!
00209      device()->setInputLength(storedElements(), ID());
00210       }
00211 
00212       // Enough elements have been written into this input
00213       // interface, so let the device be queued for process.
00214       if (storedElements() >= sequenceLength_)
00215       {
00216      waitingForProcess = true;
00217      device()->acceptNewData(ID());
00218       }
00219 
00220    }
00221 }
00222 
00223 
00224 template<class T>
00225 void InputInterfaceT<T>::invariante() const
00226 {
00227    if (DEBUG) {
00228       if (unsigned(storedElements()) > seqBuffer->size()) {
00229      throw std::logic_error(
00230         "InputInterfaceT<T>::invariante(): "
00231         "storedElements() > seqBuffer->size()");
00232       }
00233    }
00234 }
00235 
00236 template<class T>
00237 void InputInterfaceT<T>::incrementRefCount()
00238 {
00239    invariante();
00240    ++refCount;
00241 }
00242 
00243 template<class T>
00244 void InputInterfaceT<T>::decrementRefCount()
00245 {
00246    invariante();
00247    if (refCount==0) {
00248       throw simth::connection_error(
00249      "InputInterfaceT::decrementRefCount(): refcount == 0"
00250      ", in input iface "+simth::i2string(ID())
00251      +" of device "
00252      +simth::i2string(device()->ID()));
00253    }
00254    --refCount;
00255 }
00256 
00257 template<class T>
00258 inline size_t InputInterfaceT<T>::sequenceLength() const
00259 {
00260    return sequenceLength_;
00261 }
00262 
00263 template<class T>
00264 T* InputInterfaceT<T>::externSequence(size_t subSeqSize, size_t subSeqCapacity)
00265 {
00266    invariante();
00267 
00268    if (refCount>0) {
00269       throw std::runtime_error
00270      ("InputInterface: At least one reference copy exists when "
00271       "calling externSequence( ) in input iface "+simth::i2string(ID())
00272       +" of device "+simth::i2string(device()->ID())+". "
00273       "You will most likely encounter this message if you try "
00274       "to call this function (e.g. via the function call "
00275       "Device::getOutputSequence() of the device that is connected "
00276       "with this input interface) two times consecutively without "
00277       "flushing the interface (e.g. via the function call "
00278       "Device::flushProcessedSequences() of the connected "
00279       "device) in between.");
00280       /* Until now just one reference copy per time is allowed:
00281      if (seqBuffer->capacity()-oldSize < newCapacity) {
00282      throw std::runtime_error("T* InputInterfaceT::buffer(size_t numBits) : resize() not "
00283      "possible while shallow copies of the buffer exist");
00284      }
00285       */
00286    }
00287    incrementRefCount();
00288 
00289    // The number of elements that have not yet been processed
00290    size_t unprocessedSize = storedElements();
00291 
00292    if (unprocessedSize > 0) {
00293       // If the seqBuffer contains elements that have not yet been
00294       // processed, lock the attributes
00295       seqBuffer->lock();
00296    }
00297    else {
00298       // The seqBuffer didn't contain any unprocessed elements, so
00299       // unlock the attributes.
00300       seqBuffer->unlock();
00301    }
00302 
00303    // Resize the storage buffer for the required size.
00304    // We couldn't call inputSubSeq->resize() here
00305    // directly, since we could not enlarge a sequence storage via
00306    // a sequence access class.
00307    seqBuffer->resize(unprocessedSize + subSeqCapacity);
00308 
00309    // Set the shallow copy to point to the to-be-overwritten part of
00310    // the storage buffer. It is *vital* to do this here because after a
00311    // resizing to a bigger size, the inputSubSeq will still point to
00312    // the old location of the seqBuffer, i.e. memory garbage.
00313    inputSubSeq->seek(seqBuffer->begin() + unprocessedSize, seqBuffer->end());
00314    inputSubSeq->resize(subSeqSize);
00315 
00316    return inputSubSeq;
00317 }
00318 
00319 template<class T>
00320 void InputInterfaceT<T>::setSequenceLength(size_t newLength)
00321 {
00322    assert(newLength != undefinedLength);
00323 
00324    sequenceLength_ = newLength;
00325 }
00326 
00327 
00328 
00329 template<class T>
00330 bool InputInterfaceT<T>::isFilled() const
00331 {
00332    if ( ! isConnected() ) {
00333       return true;
00334    }
00335    if (sequenceLength_ == undefinedLength) {
00336       return false;
00337    }
00338    return (storedElements() >= sequenceLength_);
00339 }
00340 
00341 template<class T>
00342 void InputInterfaceT<T>::releaseProcessedSequence()
00343 {
00344    if (!isConnected())
00345       return;
00346 
00347    if (refCount>1) {
00348       // Until now this should happen not at any time, since the
00349       // input interface class does only allow one shallow copy of
00350       // the internal buffer per time. If this should be changed
00351       // somewhere in future, this inquiry could(!) be still useful.
00352       throw std::runtime_error
00353      ("InputInterfaceT<T>::releaseProcessedSequence() : "
00354       "Shallow copies of the buffer exist while calling this function. "
00355       "Until now Simthetic allows only one shallow copy. This ensures "
00356       "that the sequence that is accessed by a shallow copy is not "
00357       "simultaneously modified by another shallow copy.");
00358    }
00359    if (refCount==1){
00360       // one shallow copy (that invokes, at least indirectly, this
00361       // function) exists
00362       decrementRefCount();
00363    }
00364 }
00365 
00366 template<class T>
00367 void InputInterfaceT<T>::flushProcessedSequence()
00368 {
00369    if (!isConnected())
00370       return;
00371 
00372    // Sanity checking is done in releaseProcessedSequence(), as
00373    // well as decrementRefCount().
00374    releaseProcessedSequence();
00375 
00376    assert(refCount == 0);
00377    if (storedElements() < sequenceLength_) {
00378       throw std::runtime_error(
00379      "InputInterfaceT<T>::flushProcessedSequence(): "
00380      "error 2");
00381    }
00382 
00383    // Advance the sequence buffer:
00384    typename T::iterator newBeginIter = seqBuffer->begin()+sequenceLength_;
00385    std::rotate(seqBuffer->begin(), newBeginIter , seqBuffer->end());
00386    storedElements_ -= sequenceLength_;
00387 }
00388 
00389 
00390 template<class T>
00391 void InputInterfaceT<T>::processFinished()
00392 {
00393    if (!isConnected())
00394       //do nothing:
00395       return;
00396 
00397    if (storedElements() >= sequenceLength_) {
00398       // This could happen if the device has more than two input
00399       // interfaces and the other input interface has not had enough
00400       // elements to proceed processing.
00401       device()->acceptNewData(ID());
00402    }
00403    else {
00404       waitingForProcess = false;
00405    }
00406 }
00407 
00408 
00409 // ////////////////////////////////////////////////////////////
00410 
00411 template<class T>
00412 OutputInterfaceT<T>::OutputInterfaceT(Device* const dev, int ID)
00413    : OutputInterface(dev,ID),
00414      sequenceCapacity_(0),
00415      sequenceLength_(undefinedLength),
00416      connectedInterface(NULL),
00417      currentOutputSequence(NULL),
00418      multipleConnectedInterfaces(simth::checkedVector<interf_type*>(0))
00419    , isMultipleConnected_(false) 
00420 {
00421 }
00422 
00423 
00424 template<class T>
00425 T* const OutputInterfaceT<T>::internSequence()
00426 {
00427    if (!isConnected()) {
00428       throw simth::no_connection_error(
00429      "OutputInterface::internSequence(): "
00430      "no connection"
00431      ", in output iface "+simth::i2string(ID())
00432      +" of device "
00433      +simth::i2string(device()->ID()));
00434    }
00435    if (sequenceLength_ == undefinedLength){
00436       throw std::runtime_error
00437      ("OutputInterface::internSequence(): The output length of the "
00438       "output interface "+simth::i2string(ID())+
00439       " of device "+simth::i2string(device()->ID())+
00440       " was not set before calling the function internSequence(). "
00441       "You will most likely encounter this error messages "
00442       "if you did not set the output length of that "
00443       "interface (using the function setOutputLength(length,interfaceNr)) "
00444       "before accessing the output sequence (using the function "
00445       "getOutputSequence<T>(interfaceNr)).");
00446    }
00447 
00448    currentOutputSequence = 
00449       connectedInterface->externSequence(sequenceLength_,
00450                      sequenceCapacity_);
00451    return currentOutputSequence;
00452 }
00453 
00454 
00455 template<class T>
00456 void OutputInterfaceT<T>::setSequenceCapacity(size_t capacity)
00457 {
00458    if (sequenceLength_ == undefinedLength) {
00459       throw std::runtime_error(
00460      "OutputInterfaceT<T>::setSequenceCapacity: "
00461      "sequence length is undefined");
00462    }
00463    if (capacity <= sequenceLength_) {
00464       // Nothing happens since the requiredBuffer size is at least
00465       // the sequence length
00466       return;
00467    }
00468    sequenceCapacity_ = capacity;
00469 }
00470 
00471 
00472 template<class T>
00473 void OutputInterfaceT<T>::setSequenceLength(size_t newLength)
00474 {
00475    assert(newLength != undefinedLength);
00476 
00477    // Reset also the sequenceCapacity_ (capacity)
00478    sequenceCapacity_ = sequenceLength_ = newLength;
00479 }
00480 
00481 
00482 
00483 template<class T>
00484 void OutputInterfaceT<T>::reset()
00485 {
00486    // Release the pointer. It is up to someone else to inform the
00487    // input interface, i.e. this is done by the system calling
00488    // reset for all input and output interfaces.
00489    currentOutputSequence = NULL;
00490 }
00491 
00492 
00493 template<class T>
00494 void OutputInterfaceT<T>::flushProcessedSequences()
00495 {
00496    if (!isConnected())
00497       return;
00498    if (currentOutputSequence == NULL) { //device did not use the output
00499       throw std::runtime_error(
00500      "OutputInterface::flushProcessedSequences() : "
00501      "It seems that the function  'flushProcessedSequences()' "
00502      "in output iface "+simth::i2string(ID())+
00503      " of device "+simth::i2string(device()->ID())+" has been called "
00504      "without requesting a sequences from that interface "
00505      "before. Make sure that getOutputSequence is called "
00506      "before calling this function.");
00507    }
00508 
00509    const size_t processedSize = currentOutputSequence->size();
00510 
00511    if (processedSize > sequenceLength_){
00512       // This is possible if the capacity is set explicitly by
00513       // setSequenceCapacity()
00514       if (processedSize > sequenceCapacity()){
00515      throw std::logic_error
00516         ("OutputInterfaceT<T>::flushProcessedSequences() : "
00517          "internal simthetic error: processed size "
00518          "is larger than the sequence capacity, this should not happen");
00519       }
00520 
00521       throw std::logic_error
00522      ("OutputInterfaceT<T>::flushProcessedSequences(): "
00523       "The output sequence to be flushed is larger than the "
00524       "set sequence length of that interface. This occurs most "
00525       "likely if you set a larger output capacity using the "
00526       "function reserveOutputLength() of the device class, "
00527       "enlarge the sequence to a size that exceeds the set "
00528       "output length of that device and then you do not resize "
00529       "the sequence to the output length before flushing the "
00530       "sequence. Note: the capacity feature should only be used "
00531       "to enlarge the output sequence intermediately. If you have "
00532       "in mind to to get a larger output sequence set the output "
00533       "sequence to that length rather than enlarging the "
00534       "sequence capacity.");
00535    }
00536 
00537 
00538    // If the output interface is multiple connected, copy the
00539    // sequence to the other connected interfaces. This is not
00540    // really efficient for now, but at least it works correctly.
00541    if (isMultipleConnected()) {
00542       assert(!multipleConnectedInterfaces.empty());
00543 
00544       for (size_t i=0; i < multipleConnectedInterfaces.size(); ++i)
00545       {
00546      T* helpPtr =  multipleConnectedInterfaces[i]->externSequence(processedSize,processedSize);
00547      assert(processedSize == helpPtr->size());
00548      
00549      for (size_t i = 0; i < processedSize; ++i) {
00550         (*helpPtr)[i] = (*currentOutputSequence)[i];
00551      }
00552       }
00553    }
00554 
00555    // Signal the arrival of the new data to the connected input
00556    // interfaces.
00557    connectedInterface->acceptNewData(processedSize);
00558 
00559    for (size_t i=0; i < multipleConnectedInterfaces.size(); ++i) {
00560       multipleConnectedInterfaces[i]->acceptNewData(processedSize);
00561    }
00562 
00563    currentOutputSequence->resize(0);
00564 }
00565 
00566 template<class T>
00567 void OutputInterfaceT<T>::processFinished()
00568 {
00569    if (!isConnected())
00570       return;
00571 
00572    if (currentOutputSequence != NULL) {
00573       // Are there still bits which are not flushed?
00574       size_t processedSize = currentOutputSequence->size();
00575       if (processedSize != 0) {
00576      //until now this should not happen:
00577      throw std::runtime_error
00578         ("void OutputInterfaceT<T>::processFinished() : "
00579          "unflushed elements remain in the output "
00580          "interface "+simth::i2string(ID())+
00581          " of device "+simth::i2string(device()->ID())+". "
00582          "Call flushProcessedSequences() in the "
00583          "process function of that device.");
00584      //alternative: flushProcessedSequences();
00585       }
00586    }
00587    //else{ //no data was requested from that output interface before -> do nothing!}
00588 }
00589 
00590 template<class T>
00591 void OutputInterfaceT<T>::connect(InputInterface* interfacePtr)
00592 {
00593    assert(interfacePtr);
00594    if (connectedInterface == NULL) {
00595       connectedInterface = dynamic_cast<InputInterfaceT<T>* const>(interfacePtr);
00596       if (connectedInterface == NULL) {
00597      throw simth::type_mismatch_connection(
00598         wrongConnectionMsg(typeid(InputInterfaceT<T>),
00599                    typeid(*interfacePtr)));
00600       }
00601    }
00602    else {
00603       isMultipleConnected_ = true;
00604       interf_type* helpPtr = NULL;
00605       helpPtr = dynamic_cast<InputInterfaceT<T>* const>(interfacePtr);
00606       if (helpPtr == NULL) {
00607      throw simth::type_mismatch_connection(
00608         wrongConnectionMsg(typeid(InputInterfaceT<T>),
00609                    typeid(*interfacePtr)));
00610       }
00611       multipleConnectedInterfaces.insert(multipleConnectedInterfaces.end(), helpPtr);
00612    }
00613 }
00614 
00615 } // namespace simth
00616 
00617 #endif // #ifdef INTERFACES_IMPL_H
00618 

Generated on Mon Apr 24 21:19:19 2006 for simthetic by  doxygen 1.4.1