Skip to content

Commit 8ce2aa6

Browse files
authored
Merge pull request #717 from kleunen/subscription_map_clean
Many cleanups and improvements to subscription and retained map
2 parents 184ff98 + d8b2a9b commit 8ce2aa6

File tree

3 files changed

+283
-137
lines changed

3 files changed

+283
-137
lines changed

test/retained_topic_map.hpp

+31-11
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class retained_topic_map {
8383
topic,
8484
[this, &parent](MQTT_NS::string_view t) {
8585
if (t == "+" || t == "#") {
86-
throw std::runtime_error("No wildcards allowed in retained topic name");
86+
throw_no_wildcards_allowed();
8787
}
8888

8989
node_id_t parent_id = parent->id;
@@ -94,7 +94,7 @@ class retained_topic_map {
9494
if (entry == direct_index.end()) {
9595
entry = map.insert(path_entry(parent->id, t, next_node_id++)).first;
9696
if (next_node_id == max_node_id) {
97-
throw std::overflow_error("Maximum number of topics reached");
97+
throw_max_stored_topics();
9898
}
9999
}
100100
else {
@@ -136,7 +136,7 @@ class retained_topic_map {
136136
// Match all underlying topics when a hash entry is matched
137137
// perform a breadth-first iteration over all items in the tree below
138138
template<typename Output>
139-
void match_hash_entries(node_id_t parent, Output callback, bool ignore_system) const {
139+
void match_hash_entries(node_id_t parent, Output&& callback, bool ignore_system) const {
140140
std::deque<node_id_t> entries;
141141
entries.push_back(parent);
142142
std::deque<node_id_t> new_entries;
@@ -170,7 +170,7 @@ class retained_topic_map {
170170

171171
// Find all topics that match the specified topic filter
172172
template<typename Output>
173-
void find_match(MQTT_NS::string_view topic_filter, Output callback) const {
173+
void find_match(MQTT_NS::string_view topic_filter, Output&& callback) const {
174174
std::deque<direct_const_iterator> entries;
175175
entries.push_back(root);
176176

@@ -212,7 +212,7 @@ class retained_topic_map {
212212
}
213213
);
214214

215-
for (auto entry : entries) {
215+
for (auto& entry : entries) {
216216
if (entry->value) {
217217
callback(*entry->value);
218218
}
@@ -247,11 +247,30 @@ class retained_topic_map {
247247
void increase_topics(std::vector<direct_const_iterator> const &path) {
248248
auto& direct_index = map.template get<direct_index_tag>();
249249

250-
for(auto i : path) {
250+
for(auto& i : path) {
251251
direct_index.modify(i, [](path_entry &entry){ ++entry.count; });
252252
}
253253
}
254254

255+
// Exceptions used
256+
static void throw_max_stored_topics() { throw std::overflow_error("Retained map maximum number of topics reached"); }
257+
static void throw_no_wildcards_allowed() { throw std::runtime_error("Retained map no wildcards allowed in retained topic name"); }
258+
259+
// Increase the map size (total number of topics stored)
260+
void increase_map_size() {
261+
if(map_size == std::numeric_limits<decltype(map_size)>::max()) {
262+
throw_max_stored_topics();
263+
}
264+
265+
++map_size;
266+
}
267+
268+
// Decrease the map size (total number of topics stored)
269+
void decrease_map_size(size_t count) {
270+
BOOST_ASSERT(map_size >= count);
271+
map_size -= count;
272+
}
273+
255274
public:
256275
retained_topic_map()
257276
{
@@ -268,14 +287,14 @@ class retained_topic_map {
268287
if (path.empty()) {
269288
auto new_topic = this->create_topic(topic);
270289
direct_index.modify(new_topic, [&value](path_entry &entry) mutable { entry.value.emplace(std::forward<V>(value)); });
271-
++map_size;
290+
increase_map_size();
272291
return 1;
273292
}
274293

275294
if (!path.back()->value) {
276295
this->increase_topics(path);
277296
direct_index.modify(path.back(), [&value](path_entry &entry) mutable { entry.value.emplace(std::forward<V>(value)); });
278-
++map_size;
297+
increase_map_size();
279298
return 1;
280299
}
281300

@@ -285,14 +304,15 @@ class retained_topic_map {
285304
}
286305

287306
// Find all stored topics that math the specified topic_filter
288-
void find(MQTT_NS::string_view topic_filter, std::function< void (Value const&) > const& callback) const {
289-
find_match(topic_filter, callback);
307+
template<typename Output>
308+
void find(MQTT_NS::string_view topic_filter, Output&& callback) const {
309+
find_match(topic_filter, std::forward<Output>(callback));
290310
}
291311

292312
// Remove a stored value at the specified topic
293313
std::size_t erase(MQTT_NS::string_view topic) {
294314
auto result = erase_topic(topic);
295-
map_size -= result;
315+
decrease_map_size(result);
296316
return result;
297317
}
298318

test/subscription_map.cpp

+27-4
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,16 @@ BOOST_AUTO_TEST_CASE( test_single_subscription ) {
4444
std::string text = "example/test/A";
4545

4646
single_subscription_map< std::string > map;
47-
auto handle = map.insert(text, text);
47+
auto handle = map.insert(text, text).first;
4848
BOOST_TEST(handle.second == "A");
4949
BOOST_TEST(map.handle_to_topic_filter(handle) == text);
50-
BOOST_CHECK_THROW(map.insert(text, text), std::exception);
50+
BOOST_TEST(map.insert(text, text).second == false);
5151
map.update(handle, "new_value");
5252
map.erase(handle);
5353

54+
BOOST_TEST(map.insert(text, text).second == true);
55+
BOOST_TEST(map.erase(text) == 1);
56+
5457
BOOST_TEST(map.size() == 0);
5558
BOOST_TEST(map.internal_size() == 1);
5659

@@ -112,7 +115,7 @@ BOOST_AUTO_TEST_CASE( test_single_subscription ) {
112115

113116
std::vector< single_subscription_map< std::string >::handle > handles;
114117
for (auto const& i : values) {
115-
handles.push_back(map.insert(i, i));
118+
handles.push_back(map.insert(i, i).first);
116119
}
117120

118121
for (auto const& i : handles) {
@@ -164,7 +167,6 @@ BOOST_AUTO_TEST_CASE( test_multiple_subscription ) {
164167
BOOST_TEST(map.size() == 0);
165168
BOOST_TEST(map.internal_size() == 1);
166169

167-
168170
std::vector<std::string> values = {
169171
"example/test/A", "example/+/A", "example/#", "#"
170172
};
@@ -241,6 +243,26 @@ BOOST_AUTO_TEST_CASE( test_multiple_subscription ) {
241243

242244
BOOST_TEST(map.size() == 0);
243245
BOOST_TEST(map.internal_size() == 1);
246+
247+
// Check if $ does not match # at root
248+
map = multiple_subscription_map<std::string, int>();
249+
250+
map.insert_or_assign("#", "123", 10);
251+
map.insert_or_assign("example/plus/A", "123", 10);
252+
253+
matches = {};
254+
map.find("example/plus/A", [&matches](std::string const &a, int /*value*/) {
255+
matches.push_back(a);
256+
});
257+
BOOST_TEST(matches.size() == 2);
258+
259+
matches = {};
260+
map.find("$SYS/plus/A", [&matches](std::string const &a, int /*value*/) {
261+
matches.push_back(a);
262+
});
263+
BOOST_TEST(matches.size() == 0);
264+
265+
// map.dump(std::cout);
244266
}
245267

246268
BOOST_AUTO_TEST_CASE( test_multiple_subscription_modify ) {
@@ -253,6 +275,7 @@ BOOST_AUTO_TEST_CASE( test_multiple_subscription_modify ) {
253275
}
254276
};
255277

278+
256279
using mi_t = multiple_subscription_map<std::string, my>;
257280
mi_t map;
258281
map.insert_or_assign("a/b/c", "123", my());

0 commit comments

Comments
 (0)