00001
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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()) {
00102
00103
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
00165
00166 device()->setInputLength(storedElements(),ID());
00167 }
00168
00169
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
00204 if (sequenceLength_ == undefinedLength || sequenceLength_ == 0)
00205 {
00206
00207
00208
00209 device()->setInputLength(storedElements(), ID());
00210 }
00211
00212
00213
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
00281
00282
00283
00284
00285
00286 }
00287 incrementRefCount();
00288
00289
00290 size_t unprocessedSize = storedElements();
00291
00292 if (unprocessedSize > 0) {
00293
00294
00295 seqBuffer->lock();
00296 }
00297 else {
00298
00299
00300 seqBuffer->unlock();
00301 }
00302
00303
00304
00305
00306
00307 seqBuffer->resize(unprocessedSize + subSeqCapacity);
00308
00309
00310
00311
00312
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
00349
00350
00351
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
00361
00362 decrementRefCount();
00363 }
00364 }
00365
00366 template<class T>
00367 void InputInterfaceT<T>::flushProcessedSequence()
00368 {
00369 if (!isConnected())
00370 return;
00371
00372
00373
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
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
00395 return;
00396
00397 if (storedElements() >= sequenceLength_) {
00398
00399
00400
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
00465
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
00478 sequenceCapacity_ = sequenceLength_ = newLength;
00479 }
00480
00481
00482
00483 template<class T>
00484 void OutputInterfaceT<T>::reset()
00485 {
00486
00487
00488
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) {
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
00513
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
00539
00540
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
00556
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
00574 size_t processedSize = currentOutputSequence->size();
00575 if (processedSize != 0) {
00576
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
00585 }
00586 }
00587
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 }
00616
00617 #endif // #ifdef INTERFACES_IMPL_H
00618