blob: efbb8f5df935d776438cfdb3a41843a91c138ae3 [file] [log] [blame]
Junxiao Shie7b90e52019-03-27 13:29:33 -06001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
Davide Pesaventod247d492020-01-28 21:30:20 -05003 * Copyright (c) 2013-2020 Regents of the University of California.
Junxiao Shie7b90e52019-03-27 13:29:33 -06004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#ifndef NDN_IMPL_RECORD_CONTAINER_HPP
23#define NDN_IMPL_RECORD_CONTAINER_HPP
24
25#include "ndn-cxx/detail/common.hpp"
26#include "ndn-cxx/util/signal.hpp"
27
28#include <atomic>
29
30namespace ndn {
Davide Pesaventod247d492020-01-28 21:30:20 -050031namespace detail {
Junxiao Shie7b90e52019-03-27 13:29:33 -060032
Davide Pesaventod247d492020-01-28 21:30:20 -050033using RecordId = uint64_t;
Junxiao Shie7b90e52019-03-27 13:29:33 -060034
35template<typename T>
36class RecordContainer;
37
38/** \brief Template of PendingInterest, RegisteredPrefix, and InterestFilterRecord.
39 * \tparam T concrete type
40 */
41template<typename T>
42class RecordBase : noncopyable
43{
44public:
45 RecordId
46 getId() const
47 {
48 BOOST_ASSERT(m_id != 0);
49 return m_id;
50 }
51
52protected:
53 ~RecordBase() = default;
54
55 /** \brief Delete this record from the container.
56 */
57 void
58 deleteSelf()
59 {
60 BOOST_ASSERT(m_container != nullptr);
61 m_container->erase(m_id);
62 }
63
64private:
65 RecordContainer<T>* m_container = nullptr;
66 RecordId m_id = 0;
67 friend RecordContainer<T>;
68};
69
70/** \brief Container of PendingInterest, RegisteredPrefix, or InterestFilterRecord.
71 * \tparam T record type
72 */
73template<typename T>
74class RecordContainer
75{
76public:
77 using Record = T;
78 using Container = std::map<RecordId, Record>;
79
80 /** \brief Retrieve record by ID.
81 */
82 Record*
83 get(RecordId id)
84 {
85 auto i = m_container.find(id);
86 if (i == m_container.end()) {
87 return nullptr;
88 }
89 return &i->second;
90 }
91
92 /** \brief Insert a record with given ID.
93 */
94 template<typename ...TArgs>
95 Record&
96 put(RecordId id, TArgs&&... args)
97 {
98 BOOST_ASSERT(id != 0);
99 auto it = m_container.emplace(std::piecewise_construct, std::forward_as_tuple(id),
100 std::forward_as_tuple(std::forward<decltype(args)>(args)...));
101 BOOST_ASSERT(it.second);
102
103 Record& record = it.first->second;
104 record.m_container = this;
105 record.m_id = id;
106 return record;
107 }
108
109 RecordId
110 allocateId()
111 {
112 return ++m_lastId;
113 }
114
115 /** \brief Insert a record with newly assigned ID.
116 */
117 template<typename ...TArgs>
118 Record&
119 insert(TArgs&&... args)
120 {
121 return put(allocateId(), std::forward<decltype(args)>(args)...);
122 }
123
124 void
125 erase(RecordId id)
126 {
127 m_container.erase(id);
128 if (empty()) {
129 this->onEmpty();
130 }
131 }
132
133 void
134 clear()
135 {
136 m_container.clear();
137 this->onEmpty();
138 }
139
140 /** \brief Visit all records with the option to erase.
141 * \tparam Visitor function of type 'bool f(Record& record)'
142 * \param f visitor function, return true to erase record
143 */
144 template<typename Visitor>
145 void
146 removeIf(const Visitor& f)
147 {
148 for (auto i = m_container.begin(); i != m_container.end(); ) {
149 bool wantErase = f(i->second);
150 if (wantErase) {
151 i = m_container.erase(i);
152 }
153 else {
154 ++i;
155 }
156 }
157 if (empty()) {
158 this->onEmpty();
159 }
160 }
161
162 /** \brief Visit all records.
163 * \tparam Visitor function of type 'void f(Record& record)'
164 * \param f visitor function
165 */
166 template<typename Visitor>
167 void
168 forEach(const Visitor& f)
169 {
170 removeIf([&f] (Record& record) {
171 f(record);
172 return false;
173 });
174 }
175
Davide Pesavento140e9cb2019-08-19 00:02:05 -0400176 NDN_CXX_NODISCARD bool
Junxiao Shie7b90e52019-03-27 13:29:33 -0600177 empty() const noexcept
178 {
179 return m_container.empty();
180 }
181
182 size_t
183 size() const noexcept
184 {
185 return m_container.size();
186 }
187
188public:
189 /** \brief Signals when container becomes empty
190 */
191 util::Signal<RecordContainer<T>> onEmpty;
192
193private:
194 Container m_container;
195 std::atomic<RecordId> m_lastId{0};
196};
197
Davide Pesaventod247d492020-01-28 21:30:20 -0500198} // namespace detail
Junxiao Shie7b90e52019-03-27 13:29:33 -0600199} // namespace ndn
200
201#endif // NDN_IMPL_RECORD_CONTAINER_HPP