1/***************************************************************************** 2 3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 4 more contributor license agreements. See the NOTICE file distributed 5 with this work for additional information regarding copyright ownership. 6 Accellera licenses this file to you under the Apache License, Version 2.0 7 (the "License"); you may not use this file except in compliance with the 8 License. You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 implied. See the License for the specific language governing 16 permissions and limitations under the License. 17 18 *****************************************************************************/ 19 20// 21// To the LRM writer : this class is purely an artifact of the implementation. 22// 23 24#ifndef __CIRCULAR_BUFFER_H__ 25#define __CIRCULAR_BUFFER_H__ 26 27#include <iostream> 28 29namespace tlm { 30 31template < typename T > 32class circular_buffer 33{ 34public: 35 36 explicit 37 circular_buffer( int size = 0 ); 38 ~circular_buffer(); 39 40 void resize( int size ); 41 void clear(); 42 43 T read(); 44 void write( const T & ); 45 46 bool is_empty() const { return used() == 0; } 47 bool is_full() const { return free() == 0; } 48 49 int size() const { return m_size; } 50 int used() const { return m_used; } 51 int free() const { return m_free; } 52 53 const T& read_data() const 54 { return buf_read( m_buf, m_ri ); } 55 56 const T& peek_data( int i ) const 57 { return buf_read( m_buf, (m_ri + i) % size() ); } 58 59 T & poke_data( int i ) 60 { return buf_read( m_buf , (m_wi + i) % size() ); } 61 62 void debug() const; 63 64private: 65 void increment_write_pos( int i = 1 ); 66 void increment_read_pos( int i = 1 ); 67 68 void init(); 69 70 circular_buffer( const circular_buffer<T> &b ); // disabled 71 circular_buffer<T> &operator=( const circular_buffer<T> & ); // disabled 72 73 void* buf_alloc( int size ); 74 void buf_free( void*& buf ); 75 void buf_write( void* buf, int n, const T & t ); 76 T& buf_read( void* buf, int n ) const; 77 void buf_clear( void* buf, int n ); 78 79private: 80 int m_size; // size of the buffer 81 void* m_buf; // the buffer 82 int m_free; // number of free spaces 83 int m_used; // number of used spaces 84 int m_ri; // index of next read 85 int m_wi; // index of next write 86 87}; 88 89template< typename T > 90void 91circular_buffer<T>::debug() const 92{ 93 94 std::cout << "Buffer debug" << std::endl; 95 std::cout << "Size : " << size() << std::endl; 96 std::cout << "Free/Used " << free() << "/" << used() << std::endl; 97 std::cout << "Indices : r/w = " << m_ri << "/" << m_wi << std::endl; 98 99 if( is_empty() ) { 100 101 std::cout << "empty" << std::endl; 102 103 } 104 105 if( is_full() ) { 106 107 std::cout << "full" << std::endl; 108 109 } 110 111 std::cout << "Data : " << std::endl; 112 for( int i = 0; i < used(); i++ ) { 113 114 std::cout << peek_data( i ) << std::endl; 115 116 } 117 118 119} 120 121template < typename T > 122circular_buffer<T>::circular_buffer( int size ) 123 : m_size(size) 124 , m_buf(0) 125{ 126 init(); 127 128} 129 130template < typename T > 131void 132circular_buffer<T>::clear() 133{ 134 for( int i=0; i < used(); i++ ) { 135 buf_clear( m_buf, i ); 136 } 137 m_free = m_size; 138 m_used = m_ri = m_wi = 0; 139} 140 141template < typename T > 142circular_buffer<T>::~circular_buffer() 143{ 144 clear(); 145 buf_free( m_buf ); 146} 147 148template < typename T > 149void 150circular_buffer<T>::resize( int size ) 151{ 152 153 int i; 154 void * new_buf = buf_alloc(size); 155 156 for( i = 0; i < size && i < used(); i++ ) { 157 158 buf_write( new_buf, i, peek_data( i ) ); 159 buf_clear( m_buf, (m_ri + i) % m_size ); 160 161 } 162 163 buf_free( m_buf ); 164 165 m_size = size; 166 m_ri = 0; 167 m_wi = i % m_size; 168 m_used = i; 169 m_free = m_size - m_used; 170 171 m_buf = new_buf; 172} 173 174 175template < typename T > 176void 177circular_buffer<T>::init() { 178 179 if( m_size > 0 ) { 180 m_buf = buf_alloc( m_size ); 181 } 182 183 m_free = m_size; 184 m_used = 0; 185 m_ri = 0; 186 m_wi = 0; 187 188} 189 190template < typename T > 191T 192circular_buffer<T>::read() 193{ 194 T t = read_data(); 195 196 buf_clear( m_buf, m_ri ); 197 increment_read_pos(); 198 199 return t; 200} 201 202template < typename T > 203void 204circular_buffer<T>::write( const T &t ) 205{ 206 buf_write( m_buf, m_wi, t ); 207 increment_write_pos(); 208} 209 210 211template < typename T > 212void 213circular_buffer<T>::increment_write_pos( int i ) { 214 215 m_wi = ( m_wi + i ) % m_size; 216 m_used += i; 217 m_free -= i; 218 219} 220 221template < typename T > 222void 223circular_buffer<T>::increment_read_pos( int i ) { 224 225 m_ri = ( m_ri + i ) % m_size; 226 m_used -= i; 227 m_free += i; 228 229} 230 231template < typename T > 232inline void* 233circular_buffer<T>::buf_alloc( int size ) 234 { return new unsigned char[ size * sizeof(T) ]; } 235 236template < typename T > 237inline void 238circular_buffer<T>::buf_free( void* & buf ) 239 { delete [] static_cast<unsigned char*>(buf); buf = 0; } 240 241template < typename T > 242inline void 243circular_buffer<T>::buf_write( void* buf, int n, const T & t ) 244{ 245 T* p = static_cast<T*>(buf) + n; 246 new (p) T(t); 247} 248 249template < typename T > 250inline T& 251circular_buffer<T>::buf_read( void* buf, int n ) const 252{ 253 T* p = static_cast<T*>(buf) + n; 254 return *p; 255} 256 257template < typename T > 258inline void 259circular_buffer<T>::buf_clear( void* buf, int n ) 260{ 261 T* p = static_cast<T*>(buf) + n; 262 p->~T(); 263} 264 265} // namespace tlm 266 267#endif 268 269