#ifndef CIRCULAR_BUFFER_TEMPLATE_HPP #define CIRCULAR_BUFFER_TEMPLATE_HPP #include #include #include #include #include #if defined(WIN32) || defined(_WIN32) || defined(MINGW32) #include #else #include #include #endif // defined /** Linear data buffer (NOT FIFO) Simplified data buffer that provides pop and push operations and bundles the actual container with metadata required by . It stores the actual data in an accessible C-style array. **/ template class PacketBuffer{ public: PacketBuffer() { // Initialize C-structures as expected by for (int i = 0; i < CAPACITY; i++) { m_recv_buff_ptr[i].iov_base = (void*) &(m_container[i]); m_recv_buff_ptr[i].iov_len = sizeof(T); m_msgs[i].msg_hdr.msg_iov = &m_recv_buff_ptr[i]; m_msgs[i].msg_hdr.msg_iovlen = 1; m_msgs[i].msg_hdr.msg_name = &m_sock_from[i]; m_msgs[i].msg_hdr.msg_namelen = sizeof(sockaddr_in); } }; // ~PacketBuffer() {}; /**Diagnostics**/ int size() const { return ( idx_write-idx_read ); } int capacity() const { return m_capacity; } bool is_full() const { return bool(idx_write >= m_capacity); } bool is_empty() const { return bool(idx_write <= idx_read); } /**Operators**/ void reset(){ idx_write = 0; idx_read = 0; }; // Reset the buffer T& container(){ return m_container; }; // Direct container reference mmsghdr& msgs(){ return m_msgs; }; /**Element access**/ T& pop_front(); //Destructive read const T& peek_front(); //Non-destructive read void push_back(T item); //Write new element to buffer /**Fill from UDP receiver (threadsafe)**/ template void fill_from(TY& recv){ std::lock_guard g_guard(m_mutex); this->idx_write = recv.receive_many(m_msgs, this->capacity()); // Returns -1 with errno=11 if no data received if(idx_write==-1){ idx_write = 0; } this->idx_read = 0; } private: // Main container T m_container[CAPACITY]; const size_t m_capacity = CAPACITY; /**Guards**/ std::mutex m_mutex; /**Read and write index**/ int idx_write = 0; int idx_read = 0; // C-structures as expected by mmsghdr m_msgs[CAPACITY]; iovec m_recv_buff_ptr[CAPACITY]; sockaddr_in m_sock_from[CAPACITY]; }; /*********************************************************************/ /*********************************************************************/ /*********************************************************************/ /** Destructive read Standard read access to queues (i.e. progress the read pointer). Throws 'std::length_error' if container is empty. **/ template T& PacketBuffer::pop_front(){ std::lock_guard g_guard(m_mutex); if(this->is_empty()) { throw std::out_of_range("Attempted to read empty queue!"); } idx_read++; return m_container[idx_read-1]; } /** Non-destructive read Standard, non-destructive read access (does not progress the read pointer). Throws 'std::length_error' if container is empty. **/ template const T& PacketBuffer::peek_front(){ std::lock_guard g_guard(m_mutex); if(this->is_empty()) { throw std::out_of_range("Attempted to read empty queue!"); } return m_container[idx_read]; } /** Push an element into the end of the buffer**/ template void PacketBuffer::push_back(T item){ std::lock_guard g_guard(m_mutex); if(this->is_full()) { throw std::out_of_range("Attempted to write a full buffer!"); } m_container[idx_write] = item; idx_write++; } #endif // CIRCULAR_BUFFER_TEMPLATE_HPP