1#ifndef SOFT_STATE_MAP_HPP_B0MARRWZ
2#define SOFT_STATE_MAP_HPP_B0MARRWZ
4#include <vanetza/common/clock.hpp>
5#include <vanetza/common/runtime.hpp>
6#include <boost/heap/binomial_heap.hpp>
7#include <boost/range/iterator_range_core.hpp>
8#include <boost/range/adaptor/filtered.hpp>
9#include <boost/range/adaptor/transformed.hpp>
13#include <unordered_map>
20template<
typename VALUE>
23 VALUE operator()() {
return VALUE(); }
32template<
typename KEY,
typename VALUE,
typename CTOR = SoftStateDefaultCreator<VALUE>>
37 using mapped_type = VALUE;
38 using value_type = std::pair<const key_type&, mapped_type&>;
39 using creator_type = CTOR;
46 ExpiryWithKey(
const key_type& key, Clock::time_point expiry) :
47 Clock::time_point(expiry), m_key(key) {}
49 const key_type& key()
const {
return m_key; }
54 using heap_type = boost::heap::binomial_heap<ExpiryWithKey, boost::heap::compare<std::greater<ExpiryWithKey>>>;
60 typename heap_type::handle_type handle;
63 mapped_type& operator*() {
return value; }
64 const mapped_type& operator*()
const {
return value; }
66 using map_type = std::unordered_map<key_type, ValueWithHandle>;
68 using data_range = boost::iterator_range<typename map_type::iterator>;
69 using data_filter = std::function<bool(
const typename map_type::value_type&)>;
70 using data_transform = std::function<value_type(
typename map_type::value_type&)>;
78 template<
typename T = CTOR>
79 SoftStateMap(
const Runtime& rt,
typename std::enable_if<std::is_default_constructible<T>::value>::type* =
nullptr) :
90 m_runtime(rt), m_creator(
std::move(ctor))
100 m_lifetime = lifetime;
110 return get_data(key).value;
120 auto* data = get_data_ptr(key);
121 return data && !is_expired(*data->handle) ? &data->value :
nullptr;
131 auto* data = get_data_ptr(key);
132 return data && !is_expired(*data->handle) ? &data->value :
nullptr;
152 auto* data = get_data_ptr(key);
156 data = &get_data(key);
157 assert(data !=
nullptr);
168 while (!m_heap.empty() && is_expired(m_heap.top())) {
169 m_map.erase(m_heap.top().key());
174 using map_range = boost::transformed_range<data_transform, const boost::filtered_range<data_filter, data_range>>;
181 data_filter filter_fn = [
this](
const typename map_type::value_type& v) {
182 return !this->is_expired(*v.second.handle);
184 data_transform transform_fn = [](
typename map_type::value_type& v) {
185 return value_type { v.first, v.second.value };
187 using namespace boost::adaptors;
188 data_range range_all = boost::make_iterator_range(m_map.begin(), m_map.end());
189 return range_all | filtered(filter_fn) | transformed(transform_fn);
192 const map_range
map()
const
198 ValueWithHandle& get_data(
const key_type& key)
200 auto* data = get_data_ptr(key);
202 auto insertion = m_map.emplace(std::piecewise_construct,
203 std::forward_as_tuple(key), std::forward_as_tuple(m_creator()));
204 data = &insertion.first->second;
205 data->handle = m_heap.push(ExpiryWithKey {key, m_runtime.
now() + m_lifetime});
206 }
else if (is_expired(*data->handle)) {
213 ValueWithHandle* get_data_ptr(
const key_type& key)
215 auto it = m_map.find(key);
216 return it != m_map.end() ? &it->second :
nullptr;
219 const ValueWithHandle* get_data_ptr(
const key_type& key)
const
221 auto it = m_map.find(key);
222 return it != m_map.end() ? &it->second :
nullptr;
225 bool is_expired(
const ExpiryWithKey& expiry)
const
227 return m_runtime.
now() > expiry;
230 void refresh(
typename heap_type::handle_type& handle)
232 ExpiryWithKey& expiry = *handle;
233 static_cast<Clock::time_point&
>(expiry) = m_runtime.
now() + m_lifetime;
234 m_heap.update(handle);
237 const Runtime& m_runtime;
238 Clock::duration m_lifetime;
239 creator_type m_creator;
virtual Clock::time_point now() const =0
SoftStateMap(const Runtime &rt, typename std::enable_if< std::is_default_constructible< T >::value >::type *=nullptr)
SoftStateMap(const Runtime &rt, creator_type &&ctor)
bool has_value(const key_type &key) const
mapped_type & refresh(const key_type &key)
const mapped_type * get_value_ptr(const key_type &key) const
void set_lifetime(Clock::duration lifetime)
mapped_type & get_value(const key_type &key)
mapped_type * get_value_ptr(const key_type &key)