//
// 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 .
#ifndef INCLUDED_LIBGRAS_IMPL_INPUT_BUFFERS_HPP
#define INCLUDED_LIBGRAS_IMPL_INPUT_BUFFERS_HPP
#include
#include
#include
#include
#include
#include //memcpy/memset
namespace gnuradio
{
struct BuffInfo
{
void *mem;
size_t len;
};
struct InputBufferQueues
{
boost::dynamic_bitset<> _bitset;
std::vector > _queues;
std::vector _offset_bytes;
std::vector _history_bytes;
std::vector _post_bytes;
std::vector _history_buffs;
template
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 (_offset_bytes[i] < _history_bytes[i])
{
const tsbe::Buffer &hist_buff = _history_buffs[i];
ASSERT(buff.get_length() >= _post_bytes[i]);
if (_offset_bytes[i] == 0)
{
char *src_mem = ((char *)buff.get_memory());
char *dst_mem = ((char *)hist_buff.get_memory()) + _history_bytes[i];
std::memcpy(dst_mem, src_mem, _post_bytes[i]);
}
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, and reset the offset condition.
*
* \return true if the buffer is fully consumed
*/
inline bool pop(const size_t i, const size_t bytes_consumed)
{
_offset_bytes[i] += bytes_consumed + _history_bytes[i];
//if totally consumed, memcpy history and pop
const tsbe::Buffer &buff = _queues[i].front();
if (_offset_bytes[i] >= buff.get_length())
{
ASSERT(_offset_bytes[i] == buff.get_length()); //bad to consume more than buffer allows
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;
return true;
}
return false;
}
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();
_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*/