// Copyright 2015 Mobilinkd LLC // All rights reserved. #ifndef MOBILINKD__SEGMENTED_BUFFER_HPP_ #define MOBILINKD__SEGMENTED_BUFFER_HPP_ #include "memory.hpp" #include #include namespace mobilinkd { namespace tnc { namespace buffer { using boost::intrusive::list_base_hook; using boost::intrusive::list; using boost::intrusive::constant_time_size; template struct Pool { typedef memory::chunk chunk_type; typedef list > 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 struct SegmentedBufferIterator; template struct SegmentedBuffer { typedef uint8_t value_type; typedef value_type* pointer; typedef value_type& reference; typedef SegmentedBufferIterator iterator; typedef const SegmentedBufferIterator 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 struct SegmentedBufferIterator : public boost::iterator_facade< SegmentedBufferIterator, 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_