19class ExpirableContainer {
21 explicit ExpirableContainer(size_t max_size, std::chrono::milliseconds ttl)
22 : container_(max_size),
25 UASSERT_MSG(ttl.count() > 0,
"ttl must be positive");
28 template <
typename... Args>
29 auto emplace(Args&&... args) {
30 auto result = container_.emplace(std::forward<Args>(args)...);
33 result.first->last_accessed = std::chrono::steady_clock::now();
39 bool insert(
const Value& value) {
return emplace(value).second; }
41 bool insert(Value&& value) {
return emplace(std::move(value)).second; }
43 template <
typename Tag,
typename Key>
44 auto find(
const Key& key) {
45 const auto now = std::chrono::steady_clock::now();
46 auto it = container_.
template find<Tag, Key>(key);
48 if (it != container_.
template end<Tag>()) {
49 if (now > it->last_accessed + ttl_) {
50 container_.
template get_index<Tag>().erase(it);
53 it->last_accessed = now;
57 return impl::IteratorToValue{it};
60 template <
typename Tag,
typename Key>
61 auto find_no_update(
const Key& key)
const {
62 auto it = container_.
template find_no_update<Tag, Key>(key);
63 return impl::IteratorToValue{it};
66 template <
typename Tag,
typename Key>
67 auto equal_range(
const Key& key) {
68 const auto now = std::chrono::steady_clock::now();
69 auto& index = container_.
template get_index<Tag>();
70 auto range = container_.
template equal_range<Tag, Key>(key);
72 auto it = range.first;
75 while (it != range.second) {
76 if (now > it->last_accessed + ttl_) {
80 it->last_accessed = now;
85 range = index.equal_range(key);
87 return std::pair{impl::IteratorToValue{range.first}, impl::IteratorToValue{range.second}};
90 template <
typename Tag,
typename Key>
91 auto equal_range_no_update(
const Key& key)
const {
92 auto [begin, end] = container_.
template equal_range_no_update<Tag, Key>(key);
93 return std::pair{impl::IteratorToValue{begin}, impl::IteratorToValue{end}};
96 template <
typename Tag,
typename Key>
97 bool contains(
const Key& key) {
98 return this->
template find<Tag, Key>(key) !=
this->
template end<Tag>();
101 template <
typename Tag,
typename Key>
102 bool contains_no_update(
const Key& key)
const {
103 return this->
template find_no_update<Tag, Key>(key) !=
this->
template end<Tag>();
106 template <
typename Tag,
typename Key>
107 bool erase(
const Key& key) {
108 return container_.
template erase<Tag, Key>(key);
111 std::size_t size()
const noexcept {
return container_.size(); }
112 bool empty()
const noexcept {
return container_.empty(); }
113 std::size_t capacity()
const noexcept {
return container_.capacity(); }
115 void set_capacity(std::size_t new_capacity) { container_.set_capacity(new_capacity); }
117 void clear() { container_.clear(); }
119 template <
typename Tag>
121 return impl::IteratorToValue{container_.
template end<Tag>()};
124 void cleanup_expired() {
125 const auto now = std::chrono::steady_clock::now();
126 auto& seq_index = container_.get_sequenced();
128 while (!seq_index.empty()) {
129 const auto it = seq_index.rbegin();
130 if (now > it->last_accessed + ttl_) {
131 seq_index.pop_back();
139 using CacheItem = impl::TimestampedValue<Value>;
140 using CacheContainer =
Container<CacheItem, IndexSpecifierList, Allocator>;
142 CacheContainer container_;
143 std::chrono::milliseconds ttl_;