summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Queue.hpp156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/Queue.hpp b/src/Queue.hpp
new file mode 100644
index 0000000..c99ee54
--- /dev/null
+++ b/src/Queue.hpp
@@ -0,0 +1,156 @@
+/* This file is part of Patchage.
+ * Copyright 2007-2011 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 (at your option)
+ * 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 <cassert>
+
+#ifdef __APPLE__
+# include <libkern/OSAtomic.h>
+#endif
+
+/**
+ Realtime-safe single-reader single-writer queue.
+
+ This is a RingBuffer but templated for fixed sized objects which makes its
+ use a bit more efficient and cleaner in C++ than a traditional byte oriented
+ ring buffer.
+*/
+template <typename T>
+class Queue
+{
+public:
+ /** @param size Size in number of elements */
+ explicit Queue(uint32_t size);
+ ~Queue();
+
+ // Any thread:
+
+ inline uint32_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:
+ Queue(const Queue&); ///< Undefined (noncopyable)
+ Queue& operator=(const Queue&); ///< Undefined (noncopyable)
+
+ static inline void barrier() {
+#if defined(__APPLE__)
+ OSMemoryBarrier();
+#elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
+ __sync_synchronize();
+#else
+# warning Memory barriers unsupported, possible bugs on SMP systems
+#endif
+ }
+
+ int _front; ///< Index to front of queue
+ int _back; ///< Index to back of queue (1 past last element)
+ const uint32_t _size; ///< Size of _objects (1 more than can be stored)
+ T* const _objects; ///< Circular array containing queued elements
+};
+
+template<typename T>
+Queue<T>::Queue(uint32_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 == _front);
+}
+
+/** Return whether or not the queue is full.
+ */
+template <typename T>
+inline bool
+Queue<T>::full() const
+{
+ return (((_front - _back + _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];
+}
+
+/** Push an item onto the back of the Queue - realtime-safe, not thread-safe.
+ *
+ * @returns true if @a 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 {
+ const int back = _back;
+ _objects[back] = elem;
+ barrier();
+ _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);
+
+ barrier();
+ _front = (_front + 1) % (_size);
+}
+
+#endif // QUEUE_HPP_INCLUDED