Skip to content

Commit

Permalink
Calculate size of subscription map and retained map, fix for referenc…
Browse files Browse the repository at this point in the history
…e counting in retained map
  • Loading branch information
kleunen committed Oct 18, 2020
1 parent 99c948c commit a94d7b0
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 38 deletions.
22 changes: 17 additions & 5 deletions test/retained_topic_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,35 @@ BOOST_AUTO_TEST_SUITE(test_retained_map)
BOOST_AUTO_TEST_CASE(general) {
retained_topic_map<std::string> map;
map.insert_or_update("a/b/c", "123");
map.insert_or_update("a/b", "123");
BOOST_TEST(map.size() == 1);
BOOST_TEST(map.internal_size() == 4);

BOOST_TEST(map.insert_or_update("a/b", "123") == 1);
BOOST_TEST(map.size() == 2);
BOOST_TEST(map.internal_size() == 4);

BOOST_TEST(map.insert_or_update("a/b", "123") == 0);
BOOST_TEST(map.size() == 2);
BOOST_TEST(map.internal_size() == 4);

BOOST_TEST(map.erase("a") == 0);
BOOST_TEST(map.erase("a") == 0);

BOOST_TEST(map.erase("a/b/c") == 1);
BOOST_TEST(map.size() != 1);
BOOST_TEST(map.size() == 1);

BOOST_TEST(map.erase("a/b") == 1);
BOOST_TEST(map.size() == 1);
BOOST_TEST(map.size() == 0);
BOOST_TEST(map.internal_size() == 1);

std::vector<std::string> values = {
"example/test/A", "example/test/B", "example/A/test", "example/B/test"
};

for(auto const &i: values) {
map.insert_or_update(i, i);
map.insert_or_update(i, i);
}
BOOST_TEST(map.size() == 4);

std::vector<std::string> matches;
map.find(values[0], [&matches](std::string const &a) {
Expand Down Expand Up @@ -85,7 +96,8 @@ BOOST_AUTO_TEST_CASE(general) {
BOOST_TEST(map.erase(i) == 1);
}

BOOST_TEST(map.size() == 1);
BOOST_TEST(map.size() == 0);
BOOST_TEST(map.internal_size() == 1);
}

BOOST_AUTO_TEST_CASE(erase_lower_first) {
Expand Down
43 changes: 35 additions & 8 deletions test/retained_topic_map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ class retained_topic_map {
using map_type_const_iterator = typename map_type::const_iterator;

map_type map;
size_t map_size = 0;
map_type_iterator root;
node_id_t next_node_id;
node_id_t next_node_id = root_node_id;

map_type_iterator create_topic(MQTT_NS::string_view topic) {
map_type_iterator parent = root;
Expand Down Expand Up @@ -214,9 +215,15 @@ class retained_topic_map {
return 0;
}

// Increase the number of topics for this path
void increate_topics(std::vector<map_type_iterator> const &path) {
for(auto i: path) {
++(i->second.count);
}
}

public:
retained_topic_map()
: next_node_id(root_node_id)
retained_topic_map()
{
// Create the root node
root =
Expand All @@ -233,8 +240,23 @@ class retained_topic_map {
// Insert a value at the specified subscription path

template <typename V>
void insert_or_update(MQTT_NS::string_view topic, V&& value) {
this->create_topic(topic)->second.value.emplace(std::forward<V>(value));
size_t insert_or_update(MQTT_NS::string_view topic, V&& value) {
auto path = this->find_topic(topic);
if(path.empty()) {
this->create_topic(topic)->second.value.emplace(std::forward<V>(value));
++map_size;
return 1;
}

if(!path.back()->second.value) {
this->increate_topics(path);
path.back()->second.value.emplace(std::forward<V>(value));
++map_size;
return 1;
}

path.back()->second.value.emplace(std::forward<V>(value));
return 0;
}

// Find all stored topics that math the specified subscription
Expand All @@ -244,11 +266,16 @@ class retained_topic_map {

// Remove a stored value at the specified topic
std::size_t erase(MQTT_NS::string_view topic) {
return (erase_topic(topic) ? 1 : 0);
auto result = erase_topic(topic);
map_size -= result;
return result;
}

// Get the size of the map
std::size_t size() const { return map.size(); }
// Get the number of entries stored in the map
std::size_t size() const { return map_size; }

// Get the number of entries in the map (for debugging purpose only)
std::size_t internal_size() const { return map.size(); }

// Dump debug information
template<typename Output>
Expand Down
58 changes: 41 additions & 17 deletions test/subscription_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,22 @@ BOOST_AUTO_TEST_CASE( failed_erase ) {
auto v1 = std::make_shared<func_t>([] { std::cout << "v1" << std::endl; });
auto v2 = std::make_shared<func_t>([] { std::cout << "v2" << std::endl; });

BOOST_TEST(m.size() == 1);
BOOST_TEST(m.size() == 0);
auto it_success1 = m.insert("a/b/c", v1);
assert(it_success1.second);
BOOST_TEST(m.size() != 1);
BOOST_TEST(m.size() == 1);

auto it_success2 = m.insert("a/b", v2);
assert(it_success2.second);
BOOST_TEST(m.size() != 1);
BOOST_TEST(m.size() == 2);

auto e1 = m.erase(it_success1.first, v1);
BOOST_TEST(e1 == 1);
BOOST_TEST(m.size() != 1);
BOOST_TEST(m.size() == 1);

auto e2 = m.erase(it_success2.first, v2); // Invalid handle was specified is thrown here
BOOST_TEST(e2 == 1);
BOOST_TEST(m.size() == 1);
BOOST_TEST(m.size() == 0);

}

Expand All @@ -53,13 +53,16 @@ BOOST_AUTO_TEST_CASE( test_single_subscription ) {
map.update(handle, "new_value");
map.erase(handle);

BOOST_TEST(map.size() == 1);
BOOST_TEST(map.size() == 0);
BOOST_TEST(map.internal_size() == 1);

map.insert(text, text);
BOOST_TEST(map.size() != 1);
BOOST_TEST(map.size() == 1);
BOOST_TEST(map.internal_size() > 1);

map.erase(text);
BOOST_TEST(map.size() == 1);
BOOST_TEST(map.size() == 0);
BOOST_TEST(map.internal_size() == 1);

std::vector<std::string> values = {
"example/test/A", "example/+/A", "example/#", "#"
Expand Down Expand Up @@ -106,7 +109,8 @@ BOOST_AUTO_TEST_CASE( test_single_subscription ) {
BOOST_TEST(map.erase(i) == 1);
}

BOOST_TEST(map.size() == 1);
BOOST_TEST(map.size() == 0);
BOOST_TEST(map.internal_size() == 1);

std::vector< single_subscription_map< std::string >::handle > handles;
for (auto const& i : values) {
Expand All @@ -118,7 +122,8 @@ BOOST_AUTO_TEST_CASE( test_single_subscription ) {
BOOST_TEST(map.erase(i) == 1);
}

BOOST_TEST(map.size() == 1);
BOOST_TEST(map.size() == 0);
BOOST_TEST(map.internal_size() == 1);

}

Expand All @@ -128,13 +133,29 @@ BOOST_AUTO_TEST_CASE( test_multiple_subscription ) {
multiple_subscription_map<std::string> map;

map.insert("a/b/c", "123");
BOOST_TEST(map.size() == 1);
BOOST_TEST(map.internal_size() == 4);

map.insert("a/b/c", "123");
BOOST_TEST(map.size() == 1);
BOOST_TEST(map.internal_size() == 4);

map.insert("a/b", "123");
BOOST_TEST(map.size() == 2);
BOOST_TEST(map.internal_size() == 4);

map.erase("a/b/c", "123");
BOOST_TEST(map.size() != 1);
map.erase("a/b", "123");
BOOST_TEST(map.size() == 1);
BOOST_TEST(map.internal_size() == 4);

map.erase("a/b", "123");
BOOST_TEST(map.size() == 1);
BOOST_TEST(map.internal_size() == 4);

map.erase("a/b/c", "123");
BOOST_TEST(map.size() == 0);
BOOST_TEST(map.internal_size() == 1);


std::vector<std::string> values = {
"example/test/A", "example/+/A", "example/#", "#"
Expand All @@ -146,26 +167,28 @@ BOOST_AUTO_TEST_CASE( test_multiple_subscription ) {
BOOST_TEST(map.insert(values[0], "blaat").second == true);

map.erase(values[0], "blaat");
BOOST_TEST(map.size() != 1);
BOOST_TEST(map.size() == 1);

map.erase(values[0], values[0]);
BOOST_TEST(map.size() == 1);
BOOST_TEST(map.size() == 0);

// Perform test again but this time using handles
map.insert(values[0], values[0]);
BOOST_TEST(map.insert(map.lookup(values[0]), values[0]).second == false);
BOOST_TEST(map.insert(map.lookup(values[0]), "blaat").second == true);

map.erase(map.lookup(values[0]), "blaat");
BOOST_TEST(map.size() != 1);
BOOST_TEST(map.size() == 1);

map.erase(map.lookup(values[0]), values[0]);
BOOST_TEST(map.size() == 1);
BOOST_TEST(map.size() == 0);

for (auto const& i : values) {
map.insert(i, i);
}

BOOST_TEST(map.size() == 4);

// Attempt to remove entry which has no value
BOOST_TEST(map.erase("example", "example") == 0);
BOOST_TEST(map.erase(map.lookup("example"), "example") == 0);
Expand Down Expand Up @@ -206,7 +229,8 @@ BOOST_AUTO_TEST_CASE( test_multiple_subscription ) {
BOOST_TEST(map.erase(i, i) == 1);
}

BOOST_TEST(map.size() == 1);
BOOST_TEST(map.size() == 0);
BOOST_TEST(map.internal_size() == 1);
}

BOOST_AUTO_TEST_SUITE_END()
33 changes: 25 additions & 8 deletions test/subscription_map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,14 @@ class subscription_map_base {
using map_type_iterator = typename map_type::iterator;
using map_type_const_iterator = typename map_type::const_iterator;

map_type map;
map_type map;
map_type_iterator root;
path_entry_key root_key;
node_id_t next_node_id;
node_id_t next_node_id = root_node_id;

protected:
size_t map_size = 0;

map_type_iterator get_key(path_entry_key key) { return map.find(key); }
map_type_iterator begin() { return map.begin(); }
map_type_iterator end() { return map.end(); }
Expand Down Expand Up @@ -284,7 +286,6 @@ class subscription_map_base {

subscription_map_base()
: root_key(path_entry_key(std::numeric_limits<node_id_t>::max(), MQTT_NS::allocate_buffer("")))
, next_node_id(root_node_id)
{
// Create the root node
root = map.emplace(root_key, path_entry(root_node_id, path_entry_key())).first;
Expand All @@ -293,7 +294,10 @@ class subscription_map_base {

public:
// Return the number of elements in the tree
std::size_t size() const { return map.size(); }
std::size_t internal_size() const { return map.size(); }

// Return the number of registered topic filters
std::size_t size() const { return this->map_size; }

// Lookup a subscription
handle lookup(MQTT_NS::string_view subscription) {
Expand Down Expand Up @@ -337,6 +341,7 @@ class single_subscription_map

auto new_subscription_path = this->create_subscription(subscription);
new_subscription_path.back()->second.value = value;
++this->map_size;
return this->path_to_handle(new_subscription_path);
}

Expand Down Expand Up @@ -368,6 +373,7 @@ class single_subscription_map
}

this->remove_subscription(path);
--this->map_size;
return 1;
}

Expand All @@ -379,6 +385,7 @@ class single_subscription_map
}

this->remove_subscription(path);
--this->map_size;
return 1;
}

Expand Down Expand Up @@ -414,11 +421,14 @@ class multiple_subscription_map
if(path.empty()) {
auto new_subscription_path = this->create_subscription(subscription);
new_subscription_path.back()->second.value.insert(std::forward<V>(value));
++this->map_size;
return std::make_pair(this->path_to_handle(new_subscription_path), true);
} else {
auto result = path.back()->second.value.insert(std::forward<V>(value));
if(result.second)
if(result.second) {
this->increase_subscriptions(path);
++this->map_size;
}
return std::make_pair(this->path_to_handle(path), result.second);
}
}
Expand All @@ -434,8 +444,11 @@ class multiple_subscription_map

auto& subscription_set = h_iter->second.value;
auto insert_result = subscription_set.insert(std::forward<V>(value));
if (insert_result.second)
if (insert_result.second) {
++this->map_size;
this->increase_subscriptions(h);
}

return std::make_pair(h, insert_result.second);
}

Expand All @@ -450,8 +463,10 @@ class multiple_subscription_map

// Remove the specified value
auto result = path.back()->second.value.erase(value);
if(result)
if(result) {
--this->map_size;
this->remove_subscription(path);
}

return result;
}
Expand All @@ -468,8 +483,10 @@ class multiple_subscription_map
// Remove the specified value
auto& subscription_set = h_iter->second.value;
auto result = subscription_set.erase(value);
if (result)
if (result) {
this->remove_subscription(this->handle_to_iterators(h));
--this->map_size;
}

return result;
}
Expand Down

0 comments on commit a94d7b0

Please sign in to comment.