dataexchange.h
Go to the documentation of this file.
1 /********************************************************************************
2  * FARSA *
3  * Copyright (C) 2007-2012 *
4  * Gianluca Massera <emmegian@yahoo.it> *
5  * Stefano Nolfi <stefano.nolfi@istc.cnr.it> *
6  * Tomassino Ferrauto <tomassino.ferrauto@istc.cnr.it> *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
21  ********************************************************************************/
22 
23 #ifndef DATAEXCHANGE_H
24 #define DATAEXCHANGE_H
25 
26 #include <QEvent>
27 #include <QObject>
28 #include <QSet>
29 #include <QMutex>
30 #include <QMutexLocker>
31 #include <QWaitCondition>
32 #include <memory>
33 #include "baseexception.h"
34 #include "utilitiesexceptions.h"
35 
217 namespace farsa {
218 
219 namespace __DataExchange_internal {
220  class QueueHolderBase;
221  template <class DataType_t>
222  class QueueHolder;
223 }
224 template <class DataType_t>
225 class DatumToUpload;
226 template <class DataType_t>
227 class DataDownloader;
228 template <class C>
229 class Downloader;
230 
237 template <class DataType_t>
238 class FARSA_UTIL_TEMPLATE DataUploader
239 {
240 public:
244  typedef DataType_t DataType;
245 
250 
254  enum FullQueueBehavior {
256  BlockUploader,
258  IncreaseQueueSize,
260  SignalUploader
261  };
262 
263 public:
277  DataUploader(unsigned int queueSize, FullQueueBehavior b, DataDownloader<DataType>* downloader = NULL);
278 
282  ~DataUploader();
283 
289  unsigned int getQueueSize() const
290  {
291  return m_queueSize;
292  }
293 
299  FullQueueBehavior getFullQueueBehavior() const
300  {
301  return m_fullQueueBehavior;
302  }
303 
314  const DataDownloader<DataType>* getDownloader() const
315  {
316  return m_queue->downloader;
317  }
318 
327  unsigned int getAvailableSpace() const;
328 
336  unsigned int getNumDataInQueue() const;
337 
351  DataType* createDatum();
352 
358  void uploadDatum();
359 
366  bool datumCreatedNotUploaded() const
367  {
368  return m_datumCreatedNotUploaded;
369  }
370 
379  void checkAssociationBeforeUpload(bool v)
380  {
381  m_checkAssociationBeforeUpload = v;
382  }
383 
392  bool associationBeforeUploadChecked() const
393  {
394  return m_checkAssociationBeforeUpload;
395  }
396 
397 private:
409  void setDownloader(DataDownloader<DataType>* downloader);
410 
416  bool associationPresent() const;
417 
424  const unsigned int m_queueSize;
425 
429  const FullQueueBehavior m_fullQueueBehavior;
430 
438  std::auto_ptr<__DataExchange_internal::QueueHolder<DataType> > m_queue;
439 
445  bool m_datumCreatedNotUploaded;
446 
453  bool m_checkAssociationBeforeUpload;
454 
459  friend class DataDownloader<DataType>;
460 
466  DataUploader(const DataUploader<DataType>& other);
467 
473  DataUploader& operator=(const DataUploader<DataType>& other);
474 };
475 
484 template <class DataType_t>
485 class FARSA_UTIL_TEMPLATE DatumToUpload
486 {
487 public:
488 
492  typedef DataType_t DataType;
493 
494 public:
501  m_uploader(uploader),
502  m_datum(m_uploader.createDatum()),
503  m_datumUploaded(false)
504  {
505  }
506 
513  {
514  uploadDatum();
515  }
516 
522  void uploadDatum()
523  {
524  if (!m_datumUploaded) {
525  m_uploader.uploadDatum();
526  m_datum = NULL;
527  m_datumUploaded = true;
528  }
529  }
530 
537  const DataType* operator->() const
538  {
539  return m_datum;
540  }
541 
547  DataType* operator->()
548  {
549  return m_datum;
550  }
551 
558  bool operator==(const DataType* other) const
559  {
560  return (m_datum == other);
561  }
562 
568  operator bool() const
569  {
570  return (m_datum != NULL);
571  }
572 
573 private:
577  DataUploader<DataType>& m_uploader;
578 
582  DataType* m_datum;
583 
587  bool m_datumUploaded;
588 
595 
601  DatumToUpload& operator=(const DatumToUpload<DataType>& other);
602 };
603 
610 template<class DataType_t>
611 class FARSA_UTIL_TEMPLATE NewDatumEvent : public QEvent
612 {
613 public:
617  static const QEvent::Type newDatumEventType = static_cast<QEvent::Type>(QEvent::User + 1);
618 
622  typedef DataType_t DataType;
623 
624 public:
631  QEvent(newDatumEventType),
632  m_downloader(downloader)
633  {
634  }
635 
639  virtual ~NewDatumEvent()
640  {
641  }
642 
649  const DataDownloader<DataType>* getDownloader() const
650  {
651  return m_downloader;
652  }
653 
659  DataDownloader<DataType>* getDownloader()
660  {
661  return m_downloader;
662  }
663 
664 private:
668  DataDownloader<DataType>* const m_downloader;
669 };
670 
675 template <class DataType_t>
676 class FARSA_UTIL_TEMPLATE NewDatumNotifiable
677 {
678 public:
682  typedef DataType_t DataType;
683 
684 public:
689  {
690  }
691 
700  virtual void newDatumAvailable(DataDownloader<DataType>* downloader) = 0;
701 };
702 
709 template <class DataType_t>
710 class FARSA_UTIL_TEMPLATE DataDownloader
711 {
712 public:
716  typedef DataType_t DataType;
717 
723  NoNotificationBlocking,
726  QtEvent,
728  Callback
729  };
730 
731 public:
742  DataDownloader(NewDatumAvailableBehavior b, DataUploader<DataType>* uploader = NULL);
743 
754  DataDownloader(QObject* o, DataUploader<DataType>* uploader = NULL);
755 
767 
771  ~DataDownloader();
772 
778  NewDatumAvailableBehavior getNewDatumAvailableBehavior() const
779  {
780  return m_newDatumAvailableBehavior;
781  }
782 
793  const DataUploader<DataType>* getUploader() const
794  {
795  return (m_queue == NULL) ? NULL : m_queue->uploader;
796  }
797 
803  unsigned int getNumAvailableData() const;
804 
815  const DataType* downloadDatum();
816 
817 private:
824  void sendNotification();
825 
829  const NewDatumAvailableBehavior m_newDatumAvailableBehavior;
830 
835  QObject* const m_qoject;
836 
841  NewDatumNotifiable<DataType>* const m_newDatumNotifiable;
842 
850 
855  friend class DataUploader<DataType>;
856 
863 
869  DataDownloader& operator=(const DataDownloader<DataType>& other);
870 };
871 
878 template <class UploadedData_t, class DownloadedData_t>
879 class FARSA_UTIL_TEMPLATE DataUploaderDownloader : public DataUploader<UploadedData_t>, public DataDownloader<DownloadedData_t>
880 {
881 public:
885  typedef UploadedData_t UploadedData;
886 
890  typedef DownloadedData_t DownloadedData;
891 
896 
901 
902 public:
924  DataUploaderDownloader(unsigned int uploadQueueSize, FullQueueBehavior fullQueueBehavior, NewDatumAvailableBehavior newDatumAvailableBehavior, DataUploaderDownloader<DownloadedData, UploadedData>* other = NULL) :
925  DataUploader<UploadedData>(uploadQueueSize, fullQueueBehavior, other),
926  DataDownloader<DownloadedData>(newDatumAvailableBehavior, other)
927  {
928  }
929 
949  DataUploaderDownloader(unsigned int uploadQueueSize, FullQueueBehavior fullQueueBehavior, QObject* o, DataUploaderDownloader<DownloadedData, UploadedData>* other = NULL) :
950  DataUploader<UploadedData>(uploadQueueSize, fullQueueBehavior, other),
951  DataDownloader<DownloadedData>(o, other)
952  {
953  }
954 
975  DataUploader<UploadedData>(uploadQueueSize, fullQueueBehavior, other),
976  DataDownloader<DownloadedData>(o, other)
977  {
978  }
979 
984  {
985  // Nothing to do here
986  }
987 };
988 
1002 class FARSA_UTIL_API GlobalUploaderDownloader
1003 {
1004 public:
1010  static void stopAllDataExchanges();
1011 
1012 private:
1019 
1025  static GlobalUploaderDownloader& getInstance();
1026 
1032  void internalStopAllDataExchanges();
1033 
1040  void addQueueHolder(__DataExchange_internal::QueueHolderBase* queueHolder);
1041 
1048  void removeQueueHolder(__DataExchange_internal::QueueHolderBase* queueHolder);
1049 
1053  QSet<__DataExchange_internal::QueueHolderBase*> m_queueHolders;
1054 
1058  QMutex m_mutex;
1059 
1063  template <class DataType_t>
1065 
1066 private:
1073 
1080 };
1081 
1082 } // end namespace farsa
1083 
1084 // Implementation of all template members
1085 #include <QCoreApplication>
1086 #include <QMutex>
1087 #include <QLinkedList>
1088 #include <QWaitCondition>
1089 #include <QMutexLocker>
1090 #include <QtGlobal>
1091 
1092 namespace farsa {
1093 
1099 namespace __DataExchange_internal {
1110  {
1111  public:
1116  : mutex()
1117  , waitCondition()
1118  , dataExchangeStopped(false)
1119  {
1120  }
1121 
1122  public:
1127  QMutex mutex;
1128 
1134  QWaitCondition waitCondition;
1135 
1140  };
1141 
1148  template <class DataType_t>
1150  {
1151  public:
1155  typedef DataType_t DataType;
1156 
1157  public:
1165  QueueHolder(unsigned int queueSize, DataUploader<DataType>* u)
1166  : QueueHolderBase()
1167  , queue()
1168  , availableSpace(queueSize)
1169  , numDataInQueue(0)
1171  , nextUploaderDatum(NULL)
1172  , currentDownloaderDatum(NULL)
1173  , nextUploadIt()
1174  , nextDownloadIt()
1175  , uploader(u)
1176  , downloader(NULL)
1177  {
1178  // Allocating all memory. We use auto_ptr to ensure exception safety
1179  std::auto_ptr<DataType> uploaderDatum(new DataType());
1180  std::auto_ptr<DataType> downloaderDatum(new DataType());
1181 
1182  // Explicitly using a try-catch block to be exception-safe
1183  try {
1184  for (unsigned int i = 0; i < queueSize; i++) {
1185  queue.push_back(new DataType());
1186  }
1187  } catch (...) {
1188  // If an exception is thrown, deleting all objects allocated so far
1189  foreach(DataType* d, queue) {
1190  delete d;
1191  }
1192 
1193  // Propagating exception
1194  throw;
1195  }
1196 
1197  // Now initializing the iterators for the uploader and the downloader
1198  nextUploadIt = queue.begin();
1199  nextDownloadIt = queue.begin();
1200 
1201  // Now releasing the auto_ptrs
1202  nextUploaderDatum = uploaderDatum.release();
1203  currentDownloaderDatum = downloaderDatum.release();
1204 
1205  // Adding ourself to the list of queue holders
1206  GlobalUploaderDownloader::getInstance().addQueueHolder(this);
1207  }
1208 
1215  {
1216  // Removing ourself from the list of queue holders
1217  GlobalUploaderDownloader::getInstance().removeQueueHolder(this);
1218 
1219  foreach(DataType* d, queue) {
1220  delete d;
1221  }
1222  queue.clear();
1223 
1224  delete nextUploaderDatum;
1225  delete currentDownloaderDatum;
1226  }
1227 
1228  public:
1232  QLinkedList<DataType*> queue;
1233 
1238  unsigned int availableSpace;
1239 
1243  unsigned int numDataInQueue;
1244 
1250 
1260 
1268 
1273  typename QLinkedList<DataType*>::iterator nextUploadIt;
1274 
1279  typename QLinkedList<DataType*>::iterator nextDownloadIt;
1280 
1285 
1290  };
1291 }
1292 
1293 template <class DataType_t>
1295  m_queueSize((queueSize == 0) ? 1 : queueSize),
1296  m_fullQueueBehavior(b),
1297  m_queue(new __DataExchange_internal::QueueHolder<DataType>(m_queueSize, this)),
1298  m_datumCreatedNotUploaded(false),
1299  m_checkAssociationBeforeUpload(true)
1300 {
1301  setDownloader(downloader);
1302 }
1303 
1304 template <class DataType_t>
1306 {
1307  // If we are associated with a downloader, we must not delete the queue, the downloader will take care of it
1308  if (associationPresent()) {
1309  QMutexLocker locker(&m_queue->mutex);
1310 
1311  m_queue->uploader = NULL;
1312  m_queue.release();
1313  }
1314 }
1315 
1316 template <class DataType_t>
1318 {
1319  QMutexLocker locker(&m_queue->mutex);
1320 
1321  if (m_fullQueueBehavior == IncreaseQueueSize) {
1322  return (m_queue->availableSpace == 0) ? 1 : m_queue->availableSpace;
1323  } else {
1324  return m_queue->availableSpace;
1325  }
1326 }
1327 
1328 template <class DataType_t>
1330 {
1331  QMutexLocker locker(&m_queue->mutex);
1332 
1333  return m_queue->numDataInQueue;
1334 }
1335 
1336 template <class DataType_t>
1338 {
1339  QMutexLocker locker(&m_queue->mutex);
1340 
1341  // If the datum has already been created, returning the same datum again
1342  if (m_datumCreatedNotUploaded) {
1343  return m_queue->nextUploaderDatum;
1344  }
1345 
1346  // Checking whether data exchange has been stopped
1347  if (m_queue->dataExchangeStopped) {
1348  return NULL;
1349  }
1350 
1351  // Checking if we are associated with a downloader if we have to
1352  if (m_checkAssociationBeforeUpload && !associationPresent()) {
1354  }
1355 
1356  // Resetting the flag signalling whether the queue was full
1357  m_queue->queueFullLastDatumCreation = false;
1358 
1359  // Checking if the queue is full
1360  if (m_queue->availableSpace == 0) {
1361  // Checking that uploader and downloader iterators point to the same location (this must
1362  // always happend if we get here)
1363  Q_ASSERT(m_queue->nextUploadIt == m_queue->nextDownloadIt);
1364 
1365  // The queue is full, setting the flag
1366  m_queue->queueFullLastDatumCreation = true;
1367 
1368  // What to do depends on the FullQueueBehavior
1369  switch (m_fullQueueBehavior) {
1370  case OverrideOlder:
1371  // The next datum would go where the downloader is going to take the element, so
1372  // we have to move the downloader forward
1373  ++m_queue->nextDownloadIt;
1374  if (m_queue->nextDownloadIt == m_queue->queue.end()) {
1375  m_queue->nextDownloadIt = m_queue->queue.begin();
1376  }
1377  break;
1378  case BlockUploader:
1379  // Waiting on the wait condition, we will be woke up when the downloader downloads
1380  // an element. In that case the nextDownloadIt has been moved forward, so we can safely
1381  // use nextUploadIt
1382  m_queue->waitCondition.wait(&m_queue->mutex);
1383 
1384  // If we were woken up because data exchange has been stopped, simply returning NULL
1385  if (m_queue->dataExchangeStopped) {
1386  return NULL;
1387  }
1388  break;
1389  case IncreaseQueueSize: {
1390  // We have to add a datum to the queue at the current location. After the current
1391  // datum has been uploaded, this element will be the nextUploaderDatum
1392  std::auto_ptr<DataType> d(new DataType());
1393  m_queue->nextUploadIt = m_queue->queue.insert(m_queue->nextDownloadIt, d.get());
1394  d.release();
1395  } break;
1396  case SignalUploader:
1397  // Returning NULL to tell the uploader that there is no space
1398  return NULL;
1399  break;
1400  }
1401  }
1402 
1403  m_datumCreatedNotUploaded = true;
1404 
1405  // Returning the datum to modify
1406  return m_queue->nextUploaderDatum;
1407 }
1408 
1409 template <class DataType_t>
1411 {
1412  // If the datum hasn't been created, doing nothing
1413  if (!m_datumCreatedNotUploaded) {
1414  return;
1415  }
1416 
1417  QMutexLocker locker(&m_queue->mutex);
1418 
1419  // Checking whether data exchange has been stopped
1420  if (m_queue->dataExchangeStopped) {
1421  return;
1422  }
1423 
1424  // Putting the new datum in the queue, extracting the next element and moving the uploader iterator forward
1425  DataType* tmp = *m_queue->nextUploadIt;
1426  *m_queue->nextUploadIt = m_queue->nextUploaderDatum;
1427  m_queue->nextUploaderDatum = tmp;
1428  ++m_queue->nextUploadIt;
1429  if (m_queue->nextUploadIt == m_queue->queue.end()) {
1430  m_queue->nextUploadIt = m_queue->queue.begin();
1431  }
1432 
1433  // To update the variables with available space and data in queue, we have to check if the queue was full
1434  // and then check which is the FullQueueBehavior, to undestand what has been done in createDatum()
1435  if (m_queue->queueFullLastDatumCreation) {
1436  switch (m_fullQueueBehavior) {
1437  case OverrideOlder:
1438  // Nothing has changed, the queue is still full
1439  break;
1440  case BlockUploader:
1441  // The downloader has downloaded one datum before we could add the new one, so we have to update the counters
1442  --m_queue->availableSpace;
1443  ++m_queue->numDataInQueue;
1444  break;
1445  case IncreaseQueueSize:
1446  // The queue has grown, but still there is no space left. We only have to increase numDataInQueue
1447  ++m_queue->numDataInQueue;
1448  break;
1449  case SignalUploader:
1450  // Nothing has been done (we should never get here)
1451  Q_ASSERT(false);
1452  break;
1453  }
1454  } else {
1455  --m_queue->availableSpace;
1456  ++m_queue->numDataInQueue;
1457  }
1458 
1459  m_datumCreatedNotUploaded = false;
1460 
1461  // Waking up the downloader, in case it was sleeping. This doesn't conflict with sendNotification() because if the
1462  // downloader is sleeping it is not expecting any notification
1463  m_queue->waitCondition.wakeAll();
1464 
1465  // Now we have to notify the downloader
1466  if (m_queue->downloader != NULL) {
1467  // If the downloader expects a callback to be called, we have to release the lock, otherwise a deadlock
1468  // is possible if the downloader tries to get the datum from inside the callback
1469  if (m_queue->downloader->m_newDatumAvailableBehavior == DataDownloader<DataType>::Callback) {
1470  locker.unlock();
1471  }
1472 
1473  // Notifying the downloader
1474  m_queue->downloader->sendNotification();
1475  }
1476 }
1477 
1478 template <class DataType_t>
1480 {
1481  // Remeber that this function is not thread-safe and that the downloader must not be accessed concurrently to a
1482  // call to this function
1483 
1484  // If downloader is NULL, doing nothing
1485  if (downloader == NULL) {
1486  return;
1487  }
1488 
1489  // Checking that no association is present
1490  if ((m_queue->downloader != NULL) && (m_queue->downloader != downloader)) {
1491  throw UploaderDownloaderAssociationNotUniqueException(UploaderDownloaderAssociationNotUniqueException::UploaderAlreadyAssociated);
1492  } else if ((downloader->m_queue != NULL) && (downloader->m_queue->uploader != NULL) && (downloader->m_queue->uploader != this)) {
1493  throw UploaderDownloaderAssociationNotUniqueException(UploaderDownloaderAssociationNotUniqueException::DownloaderAlreadyAssociated);
1494  }
1495 
1496  // Setting the correct values of m_downloader and downloader->m_uploader
1497  m_queue->downloader = downloader;
1498  m_queue->uploader = this;
1499  downloader->m_queue = m_queue.get();
1500 
1501  // If there are data available, we must notify the downloader
1502  if (m_queue->numDataInQueue != 0) {
1503  m_queue->downloader->sendNotification();
1504  }
1505 }
1506 
1507 template <class DataType_t>
1508 bool DataUploader<DataType_t>::associationPresent() const
1509 {
1510  return (m_queue->downloader != NULL);
1511 }
1512 
1513 template <class DataType_t>
1515  m_newDatumAvailableBehavior(b),
1516  m_qoject(NULL),
1517  m_newDatumNotifiable(NULL),
1518  m_queue(NULL)
1519 {
1520  if ((m_newDatumAvailableBehavior != NoNotification) && (m_newDatumAvailableBehavior != NoNotificationBlocking)) {
1521  if (m_newDatumAvailableBehavior == QtEvent) {
1522  throw InvalidNewDatumAvailableBehaviorException("when the NewDatumAvailableBehavior is \"QtEvent\" you must specify the QObject that receives the event");
1523  } else if (m_newDatumAvailableBehavior == Callback) {
1524  throw InvalidNewDatumAvailableBehaviorException("when the NewDatumAvailableBehavior is \"Callback\" you must specify the NewDatumNotifiable object whose callback is called");
1525  }
1526  }
1527 
1528  if (uploader != NULL) {
1529  uploader->setDownloader(this);
1530  }
1531 }
1532 
1533 template <class DataType_t>
1535  m_newDatumAvailableBehavior(QtEvent),
1536  m_qoject(o),
1537  m_newDatumNotifiable(NULL),
1538  m_queue(NULL)
1539 {
1540  if (m_qoject == NULL) {
1541  throw InvalidNewDatumAvailableBehaviorException("when the NewDatumAvailableBehavior is \"QtEvent\" you must specify a valid (i.e. not NULL) QObject");
1542  }
1543 
1544  if (uploader != NULL) {
1545  uploader->setDownloader(this);
1546  }
1547 }
1548 
1549 template <class DataType_t>
1551  m_newDatumAvailableBehavior(Callback),
1552  m_qoject(NULL),
1553  m_newDatumNotifiable(o),
1554  m_queue(NULL)
1555 {
1556  if (m_newDatumNotifiable == NULL) {
1557  throw InvalidNewDatumAvailableBehaviorException("when the NewDatumAvailableBehavior is \"Callback\" you must specify a valid (i.e. not NULL) NewDatumNotifiable");
1558  }
1559 
1560  if (uploader != NULL) {
1561  uploader->setDownloader(this);
1562  }
1563 }
1564 
1565 template <class DataType_t>
1567 {
1568  if (m_queue != NULL) {
1569  QMutexLocker locker(&m_queue->mutex);
1570 
1571  // Setting the downloader to NULL
1572  m_queue->downloader = NULL;
1573 
1574  // If the uploader associated with us has been deleted, we have to free memory for the queue
1575  if (m_queue->uploader == NULL) {
1576  locker.unlock();
1577 
1578  delete m_queue;
1579  }
1580  }
1581 }
1582 
1583 template <class DataType_t>
1585 {
1586  if (m_queue == NULL) {
1588  }
1589 
1590  QMutexLocker locker(&m_queue->mutex);
1591 
1592  return m_queue->numDataInQueue;
1593 }
1594 
1595 template <class DataType_t>
1597 {
1598  // Checking if the queue is there, We allow to download even if no uploader is present to
1599  // be able to remove the last data from the queue
1600  if (m_queue == NULL) {
1602  }
1603 
1604  QMutexLocker locker(&m_queue->mutex);
1605 
1606  // Checking whether data exchange has been stopped
1607  if (m_queue->dataExchangeStopped) {
1608  return NULL;
1609  }
1610 
1611  // Checking if the queue is empty
1612  if (m_queue->numDataInQueue == 0) {
1613  // Checking that uploader and downloader iterators point to the same location (this must
1614  // always happend if we get here)
1615  Q_ASSERT(m_queue->nextUploadIt == m_queue->nextDownloadIt);
1616 
1617  // What to do depends on the NewDatumAvailableBehavior
1618  switch (m_newDatumAvailableBehavior) {
1619  case NoNotificationBlocking:
1620  // Waiting on the wait condition, we will be woke up when the uploader has uploaded something
1621  m_queue->waitCondition.wait(&m_queue->mutex);
1622 
1623  // If we were woken up because data exchange has been stopped, simply returning NULL
1624  if (m_queue->dataExchangeStopped) {
1625  return NULL;
1626  }
1627  break;
1628  default:
1629  // In all the other cases we return NULL to tell that no datum is available
1630  return NULL;
1631  break;
1632  }
1633  }
1634 
1635  // We can return the current datum. We have to put back in the queue the datum that was downloaded before and move
1636  // the iterator forward
1637  DataType* oldDatum = m_queue->currentDownloaderDatum;
1638  m_queue->currentDownloaderDatum = *m_queue->nextDownloadIt;
1639  *m_queue->nextDownloadIt = oldDatum;
1640  ++m_queue->nextDownloadIt;
1641  if (m_queue->nextDownloadIt == m_queue->queue.end()) {
1642  m_queue->nextDownloadIt = m_queue->queue.begin();
1643  }
1644 
1645  // Incrementing the available space and decrementing the number of data in the queue
1646  ++m_queue->availableSpace;
1647  --m_queue->numDataInQueue;
1648 
1649  // Waking up the uploader, in case it was sleeping
1650  m_queue->waitCondition.wakeAll();
1651 
1652  return m_queue->currentDownloaderDatum;
1653 }
1654 
1655 template <class DataType_t>
1657 {
1658  // What we do here depends on the NewDatumAvailableBehavior
1659  switch (m_newDatumAvailableBehavior) {
1660  case NoNotification:
1661  case NoNotificationBlocking:
1662  // Nothing to do
1663  break;
1664  case QtEvent:
1665  // Posting a QT event
1666  Q_ASSERT(m_qoject != NULL);
1667  QCoreApplication::postEvent(m_qoject, new NewDatumEvent<DataType>(this));
1668  break;
1669  case Callback:
1670  // Calling the callback
1671  Q_ASSERT(m_newDatumNotifiable != NULL);
1672  m_newDatumNotifiable->newDatumAvailable(this);
1673  break;
1674  }
1675 }
1676 
1677 } // end namespace farsa
1678 
1679 #endif