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