| /***************************************************************************** |
| |
| Licensed to Accellera Systems Initiative Inc. (Accellera) under one or |
| more contributor license agreements. See the NOTICE file distributed |
| with this work for additional information regarding copyright ownership. |
| Accellera licenses this file to you under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with the |
| License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| implied. See the License for the specific language governing |
| permissions and limitations under the License. |
| |
| *****************************************************************************/ |
| |
| #ifndef __TLM_CORE_1_REQ_RSP_CHANNELS_FIFO_CIRCULAR_BUFFER_HH__ |
| #define __TLM_CORE_1_REQ_RSP_CHANNELS_FIFO_CIRCULAR_BUFFER_HH__ |
| |
| #include <iostream> |
| |
| namespace tlm |
| { |
| |
| template <typename T> |
| class circular_buffer |
| { |
| public: |
| explicit circular_buffer(int size=0); |
| ~circular_buffer(); |
| |
| void resize(int size); |
| void clear(); |
| |
| T read(); |
| void write(const T &); |
| |
| bool is_empty() const { return used() == 0; } |
| bool is_full() const { return free() == 0; } |
| |
| int size() const { return m_size; } |
| int used() const { return m_used; } |
| int free() const { return m_free; } |
| |
| const T &read_data() const { return buf_read(m_buf, m_ri); } |
| const T & |
| peek_data(int i) const |
| { |
| return buf_read(m_buf, (m_ri + i) % size()); |
| } |
| |
| T & |
| poke_data(int i) |
| { |
| return buf_read(m_buf, (m_wi + i) % size()); |
| } |
| |
| void debug() const; |
| |
| private: |
| void increment_write_pos(int i=1); |
| void increment_read_pos(int i=1); |
| |
| void init(); |
| |
| // Disabled. |
| circular_buffer(const circular_buffer<T> &b); |
| circular_buffer<T> &operator = (const circular_buffer<T> &); |
| |
| void *buf_alloc(int size); |
| void buf_free(void *&buf); |
| void buf_write(void *buf, int n, const T &t); |
| T &buf_read(void *buf, int n) const; |
| void buf_clear(void *buf, int n); |
| |
| private: |
| int m_size; // size of the buffer |
| void *m_buf; // the buffer |
| int m_free; // number of free spaces |
| int m_used; // number of used spaces |
| int m_ri; // index of next read |
| int m_wi; // index of next write |
| }; |
| |
| template <typename T> |
| void |
| circular_buffer<T>::debug() const |
| { |
| std::cout << "Buffer debug" << std::endl; |
| std::cout << "Size : " << size() << std::endl; |
| std::cout << "Free/Used " << free() << "/" << used() << std::endl; |
| std::cout << "Indices : r/w = " << m_ri << "/" << m_wi << std::endl; |
| |
| if (is_empty()) { |
| std::cout << "empty" << std::endl; |
| } |
| |
| if (is_full()) { |
| std::cout << "full" << std::endl; |
| } |
| |
| std::cout << "Data : " << std::endl; |
| for (int i = 0; i < used(); i++) { |
| std::cout << peek_data( i ) << std::endl; |
| } |
| } |
| |
| template <typename T> |
| circular_buffer<T>::circular_buffer(int size) : m_size(size), m_buf(0) |
| { |
| init(); |
| } |
| |
| template <typename T> |
| void |
| circular_buffer<T>::clear() |
| { |
| for (int i = 0; i < used(); i++) { |
| buf_clear(m_buf, (m_ri + i) % m_size); |
| } |
| m_free = m_size; |
| m_used = m_ri = m_wi = 0; |
| } |
| |
| template <typename T> |
| circular_buffer<T>::~circular_buffer() |
| { |
| clear(); |
| buf_free(m_buf); |
| } |
| |
| template <typename T> |
| void |
| circular_buffer<T>::resize(int size) |
| { |
| int i; |
| void *new_buf = buf_alloc(size); |
| |
| for (i = 0; i < size && i < used(); i++) { |
| buf_write(new_buf, i, peek_data(i)); |
| buf_clear(m_buf, (m_ri + i) % m_size); |
| } |
| |
| buf_free(m_buf); |
| |
| m_size = size; |
| m_ri = 0; |
| m_wi = i % m_size; |
| m_used = i; |
| m_free = m_size - m_used; |
| |
| m_buf = new_buf; |
| } |
| |
| |
| template <typename T> |
| void |
| circular_buffer<T>::init() |
| { |
| if (m_size > 0) { |
| m_buf = buf_alloc(m_size); |
| } |
| |
| m_free = m_size; |
| m_used = 0; |
| m_ri = 0; |
| m_wi = 0; |
| } |
| |
| template <typename T> |
| T |
| circular_buffer<T>::read() |
| { |
| T t = read_data(); |
| |
| buf_clear(m_buf, m_ri); |
| increment_read_pos(); |
| |
| return t; |
| } |
| |
| template <typename T> |
| void |
| circular_buffer<T>::write(const T &t) |
| { |
| buf_write(m_buf, m_wi, t); |
| increment_write_pos(); |
| } |
| |
| template <typename T> |
| void |
| circular_buffer<T>::increment_write_pos(int i) |
| { |
| m_wi = (m_wi + i) % m_size; |
| m_used += i; |
| m_free -= i; |
| } |
| |
| template <typename T> |
| void |
| circular_buffer<T>::increment_read_pos(int i) |
| { |
| m_ri = (m_ri + i) % m_size; |
| m_used -= i; |
| m_free += i; |
| } |
| |
| template <typename T> |
| inline void * |
| circular_buffer<T>::buf_alloc(int size) |
| { |
| return new unsigned char [size * sizeof(T)]; |
| } |
| |
| template <typename T> |
| inline void |
| circular_buffer<T>::buf_free(void *&buf) |
| { |
| delete [] static_cast<unsigned char *>(buf); |
| buf = nullptr; |
| } |
| |
| template <typename T> |
| inline void |
| circular_buffer<T>::buf_write(void *buf, int n, const T &t) |
| { |
| T *p = static_cast<T *>(buf) + n; |
| new (p)T(t); |
| } |
| |
| template <typename T> |
| inline T & |
| circular_buffer<T>::buf_read(void *buf, int n) const |
| { |
| T *p = static_cast<T *>(buf) + n; |
| return *p; |
| } |
| |
| template <typename T> |
| inline void |
| circular_buffer<T>::buf_clear(void *buf, int n) |
| { |
| T *p = static_cast<T *>(buf) + n; |
| p->~T(); |
| } |
| |
| } // namespace tlm |
| |
| #endif /* __TLM_CORE_1_REQ_RSP_CHANNELS_FIFO_CIRCULAR_BUFFER_HH__ */ |