summaryrefslogtreecommitdiff
path: root/lib/gras_impl/input_buffer_queues.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gras_impl/input_buffer_queues.hpp')
-rw-r--r--lib/gras_impl/input_buffer_queues.hpp201
1 files changed, 201 insertions, 0 deletions
diff --git a/lib/gras_impl/input_buffer_queues.hpp b/lib/gras_impl/input_buffer_queues.hpp
new file mode 100644
index 0000000..6ac786f
--- /dev/null
+++ b/lib/gras_impl/input_buffer_queues.hpp
@@ -0,0 +1,201 @@
+//
+// Copyright 2012 Josh Blum
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with io_sig program. If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef INCLUDED_LIBGRAS_IMPL_INPUT_BUFFERS_HPP
+#define INCLUDED_LIBGRAS_IMPL_INPUT_BUFFERS_HPP
+
+#include <gras_impl/debug.hpp>
+#include <tsbe/buffer.hpp>
+#include <boost/dynamic_bitset.hpp>
+#include <vector>
+#include <queue>
+#include <cstring> //memcpy/memset
+
+namespace gnuradio
+{
+
+struct BuffInfo
+{
+ void *mem;
+ size_t len;
+};
+
+struct InputBufferQueues
+{
+ boost::dynamic_bitset<> _bitset;
+ std::vector<std::queue<tsbe::Buffer> > _queues;
+ std::vector<size_t> _offset_bytes;
+ std::vector<size_t> _history_bytes;
+ std::vector<size_t> _post_bytes;
+ std::vector<tsbe::Buffer> _history_buffs;
+
+ template <typename V>
+ inline void init(
+ const V &input_history_items,
+ const V &input_item_sizes
+ ){
+ if (this->size() == 0) return;
+
+ const size_t max_history_items = *std::max_element(input_history_items.begin(), input_history_items.end());
+
+ for (size_t i = 0; i < this->size(); i++)
+ {
+ //determine byte sizes for buffers and dealing with history
+ _history_bytes[i] = input_item_sizes[i]*input_history_items[i];
+ _post_bytes[i] = input_item_sizes[i]*max_history_items;
+
+ //allocate mini buffer for history edge conditions
+ const size_t num_bytes = _history_bytes[i] + _post_bytes[i];
+ tsbe::Buffer &buff = _history_buffs[i];
+ if (not buff or buff.get_length() != num_bytes)
+ {
+ tsbe::BufferConfig config;
+ config.memory = NULL;
+ config.length = num_bytes;
+ buff = tsbe::Buffer(config);
+ std::memset(buff.get_memory(), 0, buff.get_length());
+ }
+ }
+ }
+
+ /*!
+ * Rules for front:
+ *
+ * If we are within the mini history buffer,
+ * memcpy post bytes from the head of the input buffer.
+ * The caller must chew through the mini history buffer
+ * until offset bytes passes the history requirement.
+ *
+ * Otherwise, resolve pointers to the input buffer,
+ * moving the memory and length by num history bytes.
+ */
+ inline BuffInfo front(const size_t i) const
+ {
+ BuffInfo info;
+ const tsbe::Buffer &buff = _queues[i].front();
+
+ if (_history_bytes[i] != 0)
+ {
+ const tsbe::Buffer &hist_buff = _history_buffs[i];
+
+ if (_offset_bytes[i] == 0)
+ {
+ info.mem = (char *)hist_buff.get_memory();
+ info.len = hist_buff.get_length();
+ char *src_mem = ((char *)buff.get_memory());
+ char *dst_mem = ((char *)info.mem) + _history_bytes[i];
+ std::memcpy(dst_mem, src_mem, _post_bytes[i]);
+ }
+
+ else if (_offset_bytes[i] < _history_bytes[i]) //caller left us a partial
+ {
+ info.mem = (char *)hist_buff.get_memory() + _offset_bytes[i];
+ info.len = hist_buff.get_length() - _offset_bytes[i];
+ }
+ }
+
+ else
+ {
+ const size_t delta_bytes = _offset_bytes[i] - _history_bytes[i];
+ info.mem = ((char *)buff.get_memory()) + delta_bytes;
+ info.len = buff.get_length() - delta_bytes;
+ }
+
+ return info;
+ }
+
+ /*!
+ * Rules for popping:
+ *
+ * If we were operating in a mini history buffer, do nothing.
+ * Otherwise, check if the input buffer was entirely consumed.
+ * If so, pop the input buffer, copy the tail end of the buffer
+ * into the mini history buffer, nd reset the offset condition.
+ */
+ inline void pop(const size_t i, const size_t bytes_consumed)
+ {
+ const bool in_history = _offset_bytes[i] < _history_bytes[i];
+ _offset_bytes[i] += bytes_consumed;
+ if (in_history) return;
+
+ //if totally consumed, memcpy history and pop
+ const tsbe::Buffer &buff = _queues[i].front();
+ if (_offset_bytes[i] >= buff.get_length())
+ {
+ if (_history_bytes[i] != 0)
+ {
+ char *src_mem = ((char *)buff.get_memory()) + _offset_bytes[i] - _history_bytes[i];
+ std::memcpy(_history_buffs[i].get_memory(), src_mem, _history_bytes[i]);
+ }
+ _queues[i].pop();
+ _bitset.set(i, not _queues[i].empty());
+ _offset_bytes[i] = 0;
+ }
+ }
+
+ inline void resize(const size_t size)
+ {
+ _bitset.resize(size);
+ _queues.resize(size);
+ _post_bytes.resize(size, 0);
+ _offset_bytes.resize(size, 0);
+ _history_bytes.resize(size, 0);
+ _history_buffs.resize(size);
+ }
+
+ inline void push(const size_t i, const tsbe::Buffer &value)
+ {
+ _queues[i].push(value);
+ _bitset.set(i);
+ }
+
+ inline void flush(const size_t i)
+ {
+ _queues[i] = std::queue<tsbe::Buffer>();
+ _bitset.reset(i);
+ }
+
+ size_t size(void) const
+ {
+ return _queues.size();
+ }
+
+ inline void flush_all(void)
+ {
+ const size_t old_size = this->size();
+ this->resize(0);
+ this->resize(old_size);
+ }
+
+ inline bool ready(const size_t i) const
+ {
+ return not _queues[i].empty();
+ }
+
+ inline bool empty(const size_t i) const
+ {
+ return _queues[i].empty();
+ }
+
+ inline bool all_ready(void) const
+ {
+ return (~_bitset).none();
+ }
+};
+
+} //namespace gnuradio
+
+#endif /*INCLUDED_LIBGRAS_IMPL_INPUT_BUFFERS_HPP*/