From 17611c7dbac6978929fd60c5761b2c29827dac65 Mon Sep 17 00:00:00 2001 From: skyjake Date: Wed, 1 May 2013 19:51:54 +0300 Subject: [PATCH] libdeng2: Added FIFO, Waitable::reset() WaitableFIFO automatically updates the Waitable semaphore as the FIFO is used. --- doomsday/libdeng2/data.pri | 2 + doomsday/libdeng2/include/de/data/fifo.h | 121 ++++++++++++++++++ doomsday/libdeng2/include/de/data/waitable.h | 5 +- .../libdeng2/include/de/data/waitablefifo.h | 12 +- doomsday/libdeng2/src/data/waitable.cpp | 24 +++- 5 files changed, 155 insertions(+), 9 deletions(-) create mode 100644 doomsday/libdeng2/include/de/data/fifo.h diff --git a/doomsday/libdeng2/data.pri b/doomsday/libdeng2/data.pri index 59389549e1..54a73c4004 100644 --- a/doomsday/libdeng2/data.pri +++ b/doomsday/libdeng2/data.pri @@ -14,6 +14,7 @@ HEADERS += \ include/de/Counted \ include/de/Date \ include/de/DictionaryValue \ + include/de/FIFO \ include/de/FixedByteArray \ include/de/Guard \ include/de/IBlock \ @@ -62,6 +63,7 @@ HEADERS += \ include/de/data/counted.h \ include/de/data/date.h \ include/de/data/dictionaryvalue.h \ + include/de/data/fifo.h \ include/de/data/fixedbytearray.h \ include/de/data/guard.h \ include/de/data/huffman.h \ diff --git a/doomsday/libdeng2/include/de/data/fifo.h b/doomsday/libdeng2/include/de/data/fifo.h new file mode 100644 index 0000000000..0fb6f65776 --- /dev/null +++ b/doomsday/libdeng2/include/de/data/fifo.h @@ -0,0 +1,121 @@ +/* + * The Doomsday Engine Project -- libdeng2 + * + * Copyright (c) 2004-2013 Jaakko Keränen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef LIBDENG2_FIFO_H +#define LIBDENG2_FIFO_H + +#include "../Lockable" +#include "../Guard" + +#include + +namespace de { + +/** + * A template FIFO buffer that maintains pointers to objects. This is a + * thread-safe implementation: lock() and unlock() are automatically called + * when necessary. + * + * @ingroup data + */ +template +class FIFO : public Lockable +{ +public: + enum PutMode { + PutHead, + PutTail + }; + +public: + FIFO() : Lockable() {} + + virtual ~FIFO() { + DENG2_GUARD(this); + for(typename Objects::iterator i = _objects.begin(); i != _objects.end(); ++i) { + delete *i; + } + } + + /** + * Insert a new object to the buffer. + * + * @param object Object to add to the buffer. FIFO gets ownership. + * @param mode Where to insert the object: + * - PutHead: (default) object is put to the head of the buffer. + * - PutTail: object is put to the tail, meaning it will be the + * next one to come out. + */ + void put(Type *object, PutMode mode = PutHead) { + DENG2_GUARD(this); + if(mode == PutHead) { + _objects.push_front(object); + } + else { + _objects.push_back(object); + } + } + + /** + * Takes the oldest object in the buffer. + * + * @return The oldest object in the buffer, or NULL if the buffer is empty. + * Caller gets ownership of the returned object. + */ + Type *take() { + DENG2_GUARD(this); + if(_objects.empty()) return NULL; + Type *last = _objects.back(); + _objects.pop_back(); + return last; + } + + /** + * Returns the oldest object in the buffer. + * + * @return The oldest object in the buffer, or NULL if the buffer is empty. + * The object is not removed from the buffer. + */ + Type* tail() const { + DENG2_GUARD(this); + if(_objects.empty()) return NULL; + return _objects.back(); + } + + /** + * Determines whether the buffer is empty. + */ + bool isEmpty() const { + DENG2_GUARD(this); + return _objects.empty(); + } + + void clear() { + DENG2_GUARD(this); + while(!isEmpty()) delete take(); + } + +private: + typedef std::list Objects; + Objects _objects; +}; + +} // namespace de + +#endif // LIBDENG2_FIFO_H diff --git a/doomsday/libdeng2/include/de/data/waitable.h b/doomsday/libdeng2/include/de/data/waitable.h index 703199ef18..e692c6a2c2 100644 --- a/doomsday/libdeng2/include/de/data/waitable.h +++ b/doomsday/libdeng2/include/de/data/waitable.h @@ -45,7 +45,10 @@ class DENG2_PUBLIC Waitable Waitable(duint initialValue = 0); virtual ~Waitable(); - /// Wait until the resource becomes available. + /// Resets the semaphore to zero. + void reset(); + + /// Wait until the resource becomes available. Waits indefinitely. void wait(); /// Wait for the specified period of time to secure the diff --git a/doomsday/libdeng2/include/de/data/waitablefifo.h b/doomsday/libdeng2/include/de/data/waitablefifo.h index f1c678a03d..81f74ab665 100644 --- a/doomsday/libdeng2/include/de/data/waitablefifo.h +++ b/doomsday/libdeng2/include/de/data/waitablefifo.h @@ -36,8 +36,18 @@ class WaitableFIFO : public FIFO, public Waitable { public: WaitableFIFO() {} + + void put(Type *object, typename FIFO::PutMode mode = FIFO::PutHead) { + FIFO::put(object, mode); + post(); + } + + Type *take() { + wait(); + return FIFO::take(); + } }; } // namespace de -#endif /* LIBDENG2_WAITABLEFIFO_H */ +#endif // LIBDENG2_WAITABLEFIFO_H diff --git a/doomsday/libdeng2/src/data/waitable.cpp b/doomsday/libdeng2/src/data/waitable.cpp index abf988ca4c..b9cd0e9851 100644 --- a/doomsday/libdeng2/src/data/waitable.cpp +++ b/doomsday/libdeng2/src/data/waitable.cpp @@ -22,26 +22,36 @@ using namespace de; -#define WAITABLE_TIMEOUT 10 - Waitable::Waitable(duint initialValue) : _semaphore(initialValue) {} Waitable::~Waitable() {} +void Waitable::reset() +{ + _semaphore.tryAcquire(_semaphore.available()); +} + void Waitable::wait() { - wait(WAITABLE_TIMEOUT); + wait(0.0); } void Waitable::wait(TimeDelta const &timeOut) { - // Wait until the resource becomes available. - if(!_semaphore.tryAcquire(1, int(timeOut.asMilliSeconds()))) + if(timeOut <= 0.0) + { + _semaphore.acquire(); + } + else { - /// @throw WaitError Failed to secure the resource due to an error. - throw WaitError("Waitable::wait", "Timed out"); + // Wait until the resource becomes available. + if(!_semaphore.tryAcquire(1, int(timeOut.asMilliSeconds()))) + { + /// @throw WaitError Failed to secure the resource due to an error. + throw WaitError("Waitable::wait", "Timed out"); + } } }