scc  2024.06
SystemC components library
peq.h
1 /*******************************************************************************
2  * Copyright 2018 MINRES Technologies GmbH
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *******************************************************************************/
16 
17 #ifndef _SCC_PEQ_H_
18 #define _SCC_PEQ_H_
19 
20 #include <boost/optional.hpp>
21 #include <deque>
22 #include <map>
23 #include <systemc>
24 #include <type_traits>
25 #include <vector>
26 
32 namespace scc {
41 template <class TYPE> struct peq : public sc_core::sc_object {
42 
43  static_assert(std::is_copy_constructible<TYPE>::value, "TYPE needs to be copy-constructible");
44 
45  using pair_type = std::pair<const sc_core::sc_time, TYPE>;
46  using map_type = std::map<const sc_core::sc_time, std::deque<TYPE>*>;
52  peq()
53  : sc_core::sc_object(sc_core::sc_gen_unique_name("peq")) {}
60  explicit peq(const char* name)
61  : sc_core::sc_object(name) {}
67  ~peq();
77  void notify(const TYPE& entry, const sc_core::sc_time& t) {
78  insert_entry(entry, t + sc_core::sc_time_stamp());
79  m_event.notify(m_scheduled_events.begin()->first - sc_core::sc_time_stamp());
80  }
89  void notify(TYPE&& entry) {
90  insert_entry(entry, sc_core::sc_time_stamp());
91  m_event.notify(); // immediate notification
92  }
101  void notify(TYPE const& entry) {
102  insert_entry(entry, sc_core::sc_time_stamp());
103  m_event.notify(); // immediate notification
104  }
111  boost::optional<TYPE> get_next() {
112  if(m_scheduled_events.empty())
113  return boost::none;
114  sc_core::sc_time now = sc_core::sc_time_stamp();
115  if(!m_scheduled_events.size() || m_scheduled_events.begin()->first > now) {
116  if(m_scheduled_events.size())
117  m_event.notify(m_scheduled_events.begin()->first - now);
118  return boost::none;
119  } else
120  return get_entry();
121  }
128  TYPE get() {
129  while(!has_next()) {
130  sc_core::wait(event());
131  }
132  return get_entry();
133  }
140  sc_core::sc_event& event() { return m_event; }
146  void cancel_all() {
147  m_scheduled_events.clear();
148  m_event.cancel();
149  }
156  bool has_next() { return !(m_scheduled_events.empty() || m_scheduled_events.begin()->first > sc_core::sc_time_stamp()); }
157 
158  void clear() {
159  while(!m_scheduled_events.empty()) {
160  auto queue = m_scheduled_events.begin()->second;
161  queue->clear();
162  free_pool.push_back(queue);
163  m_scheduled_events.erase(m_scheduled_events.begin());
164  }
165  }
166 
167 private:
168  map_type m_scheduled_events;
169  std::deque<std::deque<TYPE>*> free_pool;
170  sc_core::sc_event m_event;
171 
172  void insert_entry(const TYPE& entry, sc_core::sc_time abs_time) {
173  auto it = m_scheduled_events.find(abs_time);
174  if(it == m_scheduled_events.end()) {
175  if(free_pool.size()) {
176  auto r = m_scheduled_events.insert(std::make_pair(abs_time, free_pool.front()));
177  free_pool.pop_front();
178  r.first->second->push_back(entry);
179  } else {
180  auto r = m_scheduled_events.insert(std::make_pair(abs_time, new std::deque<TYPE>()));
181  r.first->second->push_back(entry);
182  }
183  } else
184  it->second->push_back(entry);
185  }
186 
187  void insert_entry(TYPE&& entry, sc_core::sc_time abs_time) {
188  auto it = m_scheduled_events.find(abs_time);
189  if(it == m_scheduled_events.end()) {
190  if(free_pool.size()) {
191  auto r = m_scheduled_events.insert(std::make_pair(abs_time, free_pool.front()));
192  free_pool.pop_front();
193  r.first->second->push_back(entry);
194  } else {
195  auto r = m_scheduled_events.insert(std::make_pair(abs_time, new std::deque<TYPE>()));
196  r.first->second->push_back(entry);
197  }
198  } else
199  it->second->push_back(entry);
200  }
201 
202  TYPE get_entry() {
203  auto entry = m_scheduled_events.begin()->second;
204  auto ret = entry->front();
205  entry->pop_front();
206  if(!entry->size()) {
207  free_pool.push_back(entry);
208  m_scheduled_events.erase(m_scheduled_events.begin());
209  }
210  if(m_scheduled_events.size())
211  m_event.notify(m_scheduled_events.begin()->first - sc_core::sc_time_stamp());
212  return ret;
213  }
214 };
215 
216 template <class TYPE> inline peq<TYPE>::~peq() {
217  while(m_scheduled_events.size()) {
218  free_pool.push_back(m_scheduled_events.begin()->second);
219  m_scheduled_events.erase(m_scheduled_events.begin());
220  }
221  for(auto* p : free_pool)
222  delete p;
223 }
224 
225 } // namespace scc // end of scc-sysc
227 #endif /* _SCC_PEQ_H_ */
SCC TLM utilities.
priority event queue
Definition: peq.h:41
peq()
default constructor creating a unnamed peq
Definition: peq.h:52
void notify(TYPE const &entry)
non-blocking push
Definition: peq.h:101
bool has_next()
check if value is available at current time
Definition: peq.h:156
~peq()
destructor
Definition: peq.h:216
void notify(const TYPE &entry, const sc_core::sc_time &t)
non-blocking push.
Definition: peq.h:77
TYPE get()
blocking get
Definition: peq.h:128
void cancel_all()
cancel all events from the event queue
Definition: peq.h:146
boost::optional< TYPE > get_next()
non-blocking get
Definition: peq.h:111
peq(const char *name)
named peq constructor
Definition: peq.h:60
sc_core::sc_event & event()
get the available event
Definition: peq.h:140