scc  2022.4.0
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() {
157  if(m_scheduled_events.empty())
158  return false;
159  sc_core::sc_time now = sc_core::sc_time_stamp();
160  if(!m_scheduled_events.size() || m_scheduled_events.begin()->first > now) {
161  if(m_scheduled_events.size())
162  m_event.notify(m_scheduled_events.begin()->first - now);
163  return false;
164  } else {
165  return true;
166  }
167  }
168 
169  void clear() {
170  while(!m_scheduled_events.empty()) {
171  get_entry();
172  }
173  }
174 
175 private:
176  map_type m_scheduled_events;
177  std::deque<std::deque<TYPE>*> free_pool;
178  sc_core::sc_event m_event;
179 
180  void insert_entry(const TYPE& entry, sc_core::sc_time abs_time) {
181  auto it = m_scheduled_events.find(abs_time);
182  if(it == m_scheduled_events.end()) {
183  if(free_pool.size()) {
184  auto r = m_scheduled_events.insert(std::make_pair(abs_time, free_pool.front()));
185  free_pool.pop_front();
186  r.first->second->push_back(entry);
187  } else {
188  auto r = m_scheduled_events.insert(std::make_pair(abs_time, new std::deque<TYPE>()));
189  r.first->second->push_back(entry);
190  }
191  } else
192  it->second->push_back(entry);
193  }
194 
195  void insert_entry(TYPE&& entry, sc_core::sc_time abs_time) {
196  auto it = m_scheduled_events.find(abs_time);
197  if(it == m_scheduled_events.end()) {
198  if(free_pool.size()) {
199  auto r = m_scheduled_events.insert(std::make_pair(abs_time, free_pool.front()));
200  free_pool.pop_front();
201  r.first->second->push_back(entry);
202  } else {
203  auto r = m_scheduled_events.insert(std::make_pair(abs_time, new std::deque<TYPE>()));
204  r.first->second->push_back(entry);
205  }
206  } else
207  it->second->push_back(entry);
208  }
209 
210  TYPE get_entry() {
211  auto entry = m_scheduled_events.begin()->second;
212  auto ret = entry->front();
213  entry->pop_front();
214  if(!entry->size()) {
215  free_pool.push_back(entry);
216  m_scheduled_events.erase(m_scheduled_events.begin());
217  }
218  if(m_scheduled_events.size())
219  m_event.notify(m_scheduled_events.begin()->first - sc_core::sc_time_stamp());
220  return ret;
221  }
222 };
223 
224 template <class TYPE> inline peq<TYPE>::~peq() {
225  while(m_scheduled_events.size()) {
226  free_pool.push_back(m_scheduled_events.begin()->second);
227  m_scheduled_events.erase(m_scheduled_events.begin());
228  }
229  for(auto* p : free_pool)
230  delete p;
231 }
232 
233 } // namespace scc // end of scc-sysc
235 #endif /* _SCC_PEQ_H_ */
SCC SystemC 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:224
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