tnc3-firmware/TNC/SegmentedBuffer.hpp

145 wiersze
3.6 KiB
C++

// Copyright 2015 Mobilinkd LLC <rob@mobilinkd.com>
// All rights reserved.
#ifndef MOBILINKD__SEGMENTED_BUFFER_HPP_
#define MOBILINKD__SEGMENTED_BUFFER_HPP_
#include "memory.hpp"
#include <boost/iterator/iterator_facade.hpp>
#include <cstdint>
namespace mobilinkd { namespace tnc { namespace buffer {
using boost::intrusive::list_base_hook;
using boost::intrusive::list;
using boost::intrusive::constant_time_size;
template <uint16_t SIZE, uint16_t CHUNK_SIZE = 256>
struct Pool {
typedef memory::chunk<CHUNK_SIZE> chunk_type;
typedef list<chunk_type, constant_time_size<false> > chunk_list;
chunk_type segments[SIZE];
chunk_list free_list;
Pool() {
for(uint16_t i = 0; i != SIZE; ++i) {
free_list.push_back(segments[i]);
}
}
bool allocate(chunk_list& list) {
bool result = false;
auto x = taskENTER_CRITICAL_FROM_ISR();
if (!free_list.empty()) {
list.splice(list.end(), free_list, free_list.begin());
result = true;
}
taskEXIT_CRITICAL_FROM_ISR(x);
return result;
}
void deallocate(chunk_list& list) {
auto x = taskENTER_CRITICAL_FROM_ISR();
free_list.splice(free_list.end(), list);
taskEXIT_CRITICAL_FROM_ISR(x);
}
};
template <typename POOL, POOL* allocator> struct SegmentedBufferIterator;
template <typename POOL, POOL* allocator>
struct SegmentedBuffer {
typedef uint8_t value_type;
typedef value_type* pointer;
typedef value_type& reference;
typedef SegmentedBufferIterator<POOL, allocator> iterator;
typedef const SegmentedBufferIterator<POOL, allocator> const_iterator;
typename POOL::chunk_list segments_;
typename POOL::chunk_list::iterator current_;
uint16_t size_;
SegmentedBuffer()
: segments_(), current_(segments_.end()), size_(0)
{}
~SegmentedBuffer() {
allocator->deallocate(segments_);
}
void clear() {
if (size_) {
allocator->deallocate(segments_);
size_ = 0;
current_ = segments_.end();
}
}
uint16_t size() const {return size_;}
bool push_back(value_type value) {
uint16_t offset = size_ & 0xFF;
if (offset == 0) { // Must allocate.
if (not allocator->allocate(segments_))
return false;
current_ = segments_.end();
--current_;
}
current_->buffer[offset] = value;
++size_;
return true;
}
iterator begin() __attribute__((noinline)) {
return iterator(segments_.begin(), 0);
}
iterator end() __attribute__((noinline)) {
return iterator(segments_.end(), size_);
}
};
template <typename POOL, POOL* allocator>
struct SegmentedBufferIterator : public boost::iterator_facade<
SegmentedBufferIterator<POOL, allocator>, uint8_t, boost::bidirectional_traversal_tag>
{
typename POOL::chunk_list::iterator iter_;
uint16_t index_;
SegmentedBufferIterator()
: iter_(), index_(0)
{}
SegmentedBufferIterator(typename POOL::chunk_list::iterator it, uint16_t index)
: iter_(it), index_(index)
{}
friend class boost::iterator_core_access;
void increment() {
++index_;
if ((index_ & 0xFF) == 0) ++iter_;
}
void decrement() {
if ((index_ & 0xFF) == 0) --iter_;
--index_;
}
bool equal(SegmentedBufferIterator const& other) const {
return (index_ == other.index_);
}
uint8_t& dereference() const {
return iter_->buffer[index_ & 0xFF];
}
};
}}} // mobilinkd::tnc::buffer
#endif // MOBILINKD__SEGMENTED_BUFFER_HPP_