summaryrefslogtreecommitdiffstats
path: root/src/Queue.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Queue.hpp')
-rw-r--r--src/Queue.hpp131
1 files changed, 131 insertions, 0 deletions
diff --git a/src/Queue.hpp b/src/Queue.hpp
new file mode 100644
index 0000000..ab47aed
--- /dev/null
+++ b/src/Queue.hpp
@@ -0,0 +1,131 @@
+/* This file is part of Patchage.
+ * Copyright 2007-2017 David Robillard <http://drobilla.net>
+ *
+ * Patchage 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 3 of the License, or any later version.
+ *
+ * Patchage 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 details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * Patchage. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QUEUE_HPP_INCLUDED
+#define QUEUE_HPP_INCLUDED
+
+#include <atomic>
+#include <cassert>
+
+/** Realtime-safe single-reader single-writer queue */
+template <typename T>
+class Queue
+{
+public:
+ /** @param size Size in number of elements */
+ explicit Queue(size_t size);
+ ~Queue();
+
+ // Any thread:
+
+ inline size_t capacity() const { return _size - 1; }
+
+ // Write thread(s):
+
+ inline bool full() const;
+ inline bool push(const T& obj);
+
+ // Read thread:
+
+ inline bool empty() const;
+ inline T& front() const;
+ inline void pop();
+
+private:
+ std::atomic<size_t> _front; ///< Index to front of queue
+ std::atomic<size_t> _back; ///< Index to back of queue (one past end)
+ const size_t _size; ///< Size of `_objects` (at most _size-1)
+ T* const _objects; ///< Fixed array containing queued elements
+};
+
+template<typename T>
+Queue<T>::Queue(size_t size)
+ : _front(0)
+ , _back(0)
+ , _size(size + 1)
+ , _objects(new T[_size])
+{
+ assert(size > 1);
+}
+
+template <typename T>
+Queue<T>::~Queue()
+{
+ delete[] _objects;
+}
+
+/** Return whether or not the queue is empty.
+ */
+template <typename T>
+inline bool
+Queue<T>::empty() const
+{
+ return (_back.load() == _front.load());
+}
+
+/** Return whether or not the queue is full.
+ */
+template <typename T>
+inline bool
+Queue<T>::full() const
+{
+ return (((_front.load() - _back.load() + _size) % _size) == 1);
+}
+
+/** Return the element at the front of the queue without removing it
+ */
+template <typename T>
+inline T&
+Queue<T>::front() const
+{
+ return _objects[_front.load()];
+}
+
+/** Push an item onto the back of the Queue - realtime-safe, not thread-safe.
+ *
+ * @returns true if `elem` was successfully pushed onto the queue,
+ * false otherwise (queue is full).
+ */
+template <typename T>
+inline bool
+Queue<T>::push(const T& elem)
+{
+ if (full()) {
+ return false;
+ } else {
+ unsigned back = _back.load();
+ _objects[back] = elem;
+ _back = (back + 1) % _size;
+ return true;
+ }
+}
+
+/** Pop an item off the front of the queue - realtime-safe, not thread-safe.
+ *
+ * It is a fatal error to call pop() when the queue is empty.
+ *
+ * @returns the element popped.
+ */
+template <typename T>
+inline void
+Queue<T>::pop()
+{
+ assert(!empty());
+ assert(_size > 0);
+
+ _front = (_front.load() + 1) % (_size);
+}
+
+#endif // QUEUE_HPP_INCLUDED