959 lines
22 KiB
C++
959 lines
22 KiB
C++
/*******************************************************************\
|
|
|
|
Module: Unit tests for sharing map
|
|
|
|
Author: Daniel Poetzl
|
|
|
|
\*******************************************************************/
|
|
|
|
#define SM_INTERNAL_CHECKS
|
|
#define SN_INTERNAL_CHECKS
|
|
|
|
#include <climits>
|
|
#include <random>
|
|
#include <set>
|
|
|
|
#include <testing-utils/use_catch.h>
|
|
#include <util/sharing_map.h>
|
|
|
|
typedef sharing_mapt<irep_idt, std::string, false, irep_id_hash>
|
|
sharing_map_standardt;
|
|
|
|
class sharing_map_internalt : public sharing_map_standardt
|
|
{
|
|
friend void sharing_map_internals_test();
|
|
};
|
|
|
|
typedef sharing_mapt<irep_idt, std::string, true, irep_id_hash>
|
|
sharing_map_error_checkt;
|
|
|
|
struct unsigned_hasht
|
|
{
|
|
std::size_t operator()(const unsigned v) const
|
|
{
|
|
return static_cast<std::size_t>(v);
|
|
}
|
|
};
|
|
|
|
class sharing_map_unsignedt
|
|
: public sharing_mapt<unsigned, std::string, false, unsigned_hasht>
|
|
{
|
|
friend void sharing_map_internals_test();
|
|
};
|
|
|
|
// helpers
|
|
template <class some_sharing_mapt>
|
|
void fill(some_sharing_mapt &sm)
|
|
{
|
|
sm.insert("i", "0");
|
|
sm.insert("j", "1");
|
|
sm.insert("k", "2");
|
|
}
|
|
|
|
template <class some_sharing_mapt>
|
|
void fill2(some_sharing_mapt &sm)
|
|
{
|
|
sm.insert("l", "3");
|
|
sm.insert("m", "4");
|
|
sm.insert("n", "5");
|
|
}
|
|
|
|
class key_hasht
|
|
{
|
|
public:
|
|
std::size_t operator()(const std::size_t &k) const
|
|
{
|
|
return k & 0x3;
|
|
}
|
|
};
|
|
|
|
void sharing_map_internals_test()
|
|
{
|
|
SECTION("count nodes")
|
|
{
|
|
std::set<const void *> marked;
|
|
sharing_map_internalt sm;
|
|
std::size_t count = 0;
|
|
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == 0);
|
|
REQUIRE(marked.empty());
|
|
|
|
count = sm.count_unmarked_nodes(true, marked, false);
|
|
REQUIRE(count == 0);
|
|
REQUIRE(marked.empty());
|
|
|
|
sm.insert("i", "1");
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == 2);
|
|
REQUIRE(marked.empty());
|
|
|
|
count = sm.count_unmarked_nodes(true, marked, false);
|
|
REQUIRE(count == 1);
|
|
REQUIRE(marked.empty());
|
|
|
|
sm.clear();
|
|
fill(sm);
|
|
count = sm.count_unmarked_nodes(true, marked, false);
|
|
REQUIRE(count == 3);
|
|
REQUIRE(marked.empty());
|
|
}
|
|
|
|
SECTION("marking")
|
|
{
|
|
std::set<const void *> marked;
|
|
sharing_map_internalt sm;
|
|
|
|
fill(sm);
|
|
|
|
sm.count_unmarked_nodes(false, marked, true);
|
|
REQUIRE(marked.empty());
|
|
|
|
sharing_map_internalt sm2(sm);
|
|
sm.count_unmarked_nodes(false, marked, true);
|
|
REQUIRE(marked.size() == 1);
|
|
|
|
marked.clear();
|
|
sharing_map_internalt sm3(sm);
|
|
sm3.insert("x", "0");
|
|
sm.count_unmarked_nodes(false, marked, true);
|
|
REQUIRE(marked.size() >= 2);
|
|
}
|
|
|
|
// These tests check whether the internal representation of the map has the
|
|
// expected shape after a series of operations. This is done by checking
|
|
// whether the map has a number of nodes (inner nodes, container nodes, and
|
|
// leaf nodes) that is consistent with the expected shape.
|
|
SECTION("single map shape")
|
|
{
|
|
std::set<const void *> marked;
|
|
std::size_t count = 0;
|
|
const std::size_t chunk = sharing_map_unsignedt::chunk;
|
|
const std::size_t levels = sharing_map_unsignedt::levels;
|
|
|
|
sharing_map_unsignedt sm;
|
|
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == 0);
|
|
|
|
sm.insert(0, "a");
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == 2);
|
|
|
|
SECTION("first node decisive")
|
|
{
|
|
sm.insert(1, "b");
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == 3);
|
|
|
|
sm.replace(1, "c");
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == 3);
|
|
|
|
sm.erase(1);
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == 2);
|
|
}
|
|
|
|
SECTION("second node decisive")
|
|
{
|
|
sm.insert(1 << chunk, "b");
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == 4);
|
|
|
|
sm.replace(1 << chunk, "c");
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == 4);
|
|
|
|
sm.erase(1 << chunk);
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == 3);
|
|
}
|
|
|
|
SECTION("third node decisive")
|
|
{
|
|
sm.insert(1 << (2 * chunk), "b");
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == 5);
|
|
|
|
sm.replace(1 << (2 * chunk), "c");
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == 5);
|
|
|
|
sm.erase(1 << (2 * chunk));
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == 4);
|
|
}
|
|
|
|
SECTION("last non-container node is decisive")
|
|
{
|
|
sm.insert(1 << (chunk * (levels - 1)), "b");
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == levels + 2); // inner nodes + leafs
|
|
|
|
sm.replace(1 << (chunk * (levels - 1)), "c");
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == levels + 2); // inner nodes + leafs
|
|
|
|
sm.erase(1 << (chunk * (levels - 1)));
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == levels + 1); // inner nodes + leafs
|
|
}
|
|
|
|
SECTION("stored in container node")
|
|
{
|
|
// existing leaf will be migrated to the bottom
|
|
sm.insert(1 << (chunk * levels), "b");
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == levels + 1 + 2); // inner nodes + container + leafs
|
|
|
|
sm.replace(1 << (chunk * levels), "c");
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == levels + 1 + 2); // inner nodes + container + leafs
|
|
|
|
sm.erase(1 << (chunk * levels));
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == levels + 1 + 1); // inner nodes + container + leafs
|
|
|
|
// existing leaf still in container, not migrating necessary
|
|
sm.insert(1 << (chunk * levels), "d");
|
|
count = sm.count_unmarked_nodes(false, marked, false);
|
|
REQUIRE(count == levels + 1 + 2); // inner nodes + container + leafs
|
|
}
|
|
}
|
|
|
|
SECTION("delta view (sharing, one of the maps is deeper)")
|
|
{
|
|
std::set<const void *> marked;
|
|
std::size_t chunk = sharing_map_unsignedt::chunk;
|
|
|
|
std::vector<sharing_map_unsignedt> v;
|
|
v.reserve(2);
|
|
|
|
v.push_back(sharing_map_unsignedt());
|
|
sharing_map_unsignedt &sm1 = v.front();
|
|
|
|
SECTION("additional element in second map")
|
|
{
|
|
sm1.insert(0, "a");
|
|
|
|
v.emplace_back(sm1);
|
|
sharing_map_unsignedt &sm2 = v.back();
|
|
|
|
sm2.insert(1 << (2 * chunk), "b");
|
|
|
|
#if !defined(_MSC_VER)
|
|
sharing_map_unsignedt::sharing_map_statst sms;
|
|
|
|
sms = sharing_map_unsignedt::get_sharing_stats(v.begin(), v.end());
|
|
REQUIRE(sms.num_leafs == 1 + 2);
|
|
REQUIRE(sms.num_unique_leafs == 1 + 1);
|
|
REQUIRE(sms.num_nodes == 2 + 5);
|
|
REQUIRE(sms.num_unique_nodes == 2 + 4);
|
|
#endif
|
|
|
|
sharing_map_unsignedt::delta_viewt delta_view;
|
|
sm1.get_delta_view(sm2, delta_view, false);
|
|
REQUIRE(delta_view.size() == 0);
|
|
|
|
delta_view.clear();
|
|
sm2.get_delta_view(sm1, delta_view, false);
|
|
REQUIRE(delta_view.size() == 1);
|
|
REQUIRE(delta_view[0].k == (1 << (2 * chunk)));
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Sharing map internals test", "[core][util]")
|
|
{
|
|
sharing_map_internals_test();
|
|
}
|
|
|
|
TEST_CASE("Sharing map interface", "[core][util]")
|
|
{
|
|
SECTION("Empty map")
|
|
{
|
|
sharing_map_standardt sm;
|
|
|
|
REQUIRE(sm.empty());
|
|
REQUIRE(sm.size() == 0);
|
|
REQUIRE(!sm.has_key("i"));
|
|
}
|
|
|
|
SECTION("Insert elements")
|
|
{
|
|
sharing_map_standardt sm;
|
|
|
|
sm.insert("i", "0");
|
|
sm.insert("j", "1");
|
|
|
|
REQUIRE(sm.size() == 2);
|
|
REQUIRE(!sm.empty());
|
|
REQUIRE(sm.has_key("i"));
|
|
REQUIRE(sm.has_key("j"));
|
|
REQUIRE(!sm.has_key("k"));
|
|
|
|
cbmc_invariants_should_throwt invariants_throw;
|
|
|
|
REQUIRE_THROWS_AS(sm.insert("i", "4"), invariant_failedt);
|
|
}
|
|
|
|
SECTION("Replace and update elements")
|
|
{
|
|
sharing_map_standardt sm;
|
|
fill(sm);
|
|
|
|
sm.replace("i", "9");
|
|
auto r = sm.find("i");
|
|
REQUIRE(r);
|
|
REQUIRE(r->get() == "9");
|
|
|
|
sm.update("i", [](std::string &str) { str += "0"; });
|
|
auto r2 = sm.find("i");
|
|
REQUIRE(r2);
|
|
REQUIRE(r2->get() == "90");
|
|
}
|
|
|
|
SECTION("Replace and update elements errors")
|
|
{
|
|
sharing_map_standardt sm;
|
|
fill(sm);
|
|
|
|
sharing_map_error_checkt debug_sm;
|
|
fill(debug_sm);
|
|
|
|
cbmc_invariants_should_throwt invariants_throw;
|
|
|
|
SECTION("Replace non-existing")
|
|
{
|
|
REQUIRE_THROWS_AS(sm.replace("x", "0"), invariant_failedt);
|
|
}
|
|
|
|
SECTION("Update non-existing")
|
|
{
|
|
REQUIRE_THROWS_AS(
|
|
sm.update("x", [](std::string &str) {}), invariant_failedt);
|
|
}
|
|
|
|
SECTION("Replace with equal")
|
|
{
|
|
REQUIRE_THROWS_AS(debug_sm.replace("i", "0"), invariant_failedt);
|
|
}
|
|
|
|
SECTION("Update with equal")
|
|
{
|
|
REQUIRE_THROWS_AS(
|
|
debug_sm.update("i", [](std::string &str) {}), invariant_failedt);
|
|
}
|
|
}
|
|
|
|
SECTION("Retrieve elements")
|
|
{
|
|
sharing_map_standardt sm;
|
|
sm.insert("i", "0");
|
|
sm.insert("j", "1");
|
|
|
|
REQUIRE(sm.has_key("i"));
|
|
REQUIRE(sm.has_key("j"));
|
|
REQUIRE(!sm.has_key("k"));
|
|
|
|
REQUIRE(sm.size() == 2);
|
|
|
|
auto r1 = sm.find("i");
|
|
REQUIRE(r1);
|
|
REQUIRE(r1->get() == "0");
|
|
|
|
auto r2 = sm.find("k");
|
|
REQUIRE(!r2);
|
|
}
|
|
|
|
SECTION("Remove elements")
|
|
{
|
|
sharing_map_standardt sm;
|
|
sm.insert("i", "0");
|
|
sm.insert("j", "1");
|
|
|
|
REQUIRE(sm.size() == 2);
|
|
|
|
sm.erase("i");
|
|
REQUIRE(!sm.has_key("i"));
|
|
|
|
sm.erase("j");
|
|
REQUIRE(!sm.has_key("j"));
|
|
|
|
sm.erase_if_exists("j");
|
|
REQUIRE(!sm.has_key("j"));
|
|
sm.insert("j", "1");
|
|
sm.erase_if_exists("j");
|
|
REQUIRE(!sm.has_key("j"));
|
|
|
|
sm.insert("i", "0");
|
|
sm.insert("j", "1");
|
|
|
|
sharing_map_standardt sm3(sm);
|
|
|
|
REQUIRE(sm.has_key("i"));
|
|
REQUIRE(sm.has_key("j"));
|
|
REQUIRE(sm3.has_key("i"));
|
|
REQUIRE(sm3.has_key("j"));
|
|
|
|
sm.erase("i");
|
|
|
|
REQUIRE(!sm.has_key("i"));
|
|
REQUIRE(sm.has_key("j"));
|
|
|
|
REQUIRE(sm3.has_key("i"));
|
|
REQUIRE(sm3.has_key("j"));
|
|
|
|
sm3.erase("i");
|
|
REQUIRE(!sm3.has_key("i"));
|
|
|
|
cbmc_invariants_should_throwt invariants_throw;
|
|
|
|
REQUIRE_THROWS_AS(sm3.erase("x"), invariant_failedt);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Sharing map copying", "[core][util]")
|
|
{
|
|
sharing_map_standardt sm1;
|
|
fill(sm1);
|
|
|
|
sharing_map_standardt sm2(sm1);
|
|
|
|
sm2.erase("i");
|
|
REQUIRE(!sm2.has_key("i"));
|
|
REQUIRE(sm1.has_key("i"));
|
|
|
|
sharing_map_standardt sm3(sm2);
|
|
REQUIRE(!sm3.has_key("i"));
|
|
sm3.insert("i", "0");
|
|
|
|
REQUIRE(sm1.has_key("i"));
|
|
REQUIRE(!sm2.has_key("i"));
|
|
REQUIRE(sm3.has_key("i"));
|
|
}
|
|
|
|
TEST_CASE("Sharing map collisions", "[core][util]")
|
|
{
|
|
typedef sharing_mapt<std::size_t, std::string, false, key_hasht>
|
|
sharing_map_collisionst;
|
|
|
|
sharing_map_collisionst sm;
|
|
|
|
SECTION("Basic")
|
|
{
|
|
sm.insert(0, "a");
|
|
sm.insert(8, "b");
|
|
sm.insert(16, "c");
|
|
|
|
sm.insert(1, "d");
|
|
sm.insert(2, "e");
|
|
|
|
sm.erase(8);
|
|
|
|
REQUIRE(sm.has_key(0));
|
|
REQUIRE(sm.has_key(16));
|
|
|
|
REQUIRE(sm.has_key(1));
|
|
REQUIRE(sm.has_key(2));
|
|
|
|
REQUIRE(!sm.has_key(8));
|
|
}
|
|
|
|
SECTION("Delta view")
|
|
{
|
|
sm.insert(0, "a");
|
|
|
|
sharing_map_collisionst sm2;
|
|
|
|
sm2.insert(8, "b");
|
|
sm2.insert(16, "c");
|
|
|
|
sharing_map_collisionst::delta_viewt delta_view;
|
|
|
|
sm.get_delta_view(sm2, delta_view, false);
|
|
|
|
REQUIRE(delta_view.size() == 1);
|
|
REQUIRE(delta_view[0].k == 0);
|
|
REQUIRE(!delta_view[0].is_in_both_maps());
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Sharing map views and iteration", "[core][util]")
|
|
{
|
|
SECTION("View of empty map")
|
|
{
|
|
sharing_map_standardt sm;
|
|
sharing_map_standardt::viewt view;
|
|
|
|
sm.get_view(view);
|
|
}
|
|
|
|
SECTION("View")
|
|
{
|
|
typedef std::pair<std::string, std::string> pt;
|
|
|
|
sharing_map_standardt sm;
|
|
sharing_map_standardt::viewt view;
|
|
std::vector<pt> pairs;
|
|
|
|
auto sort_view = [&pairs, &view]() {
|
|
pairs.clear();
|
|
for(auto &p : view)
|
|
{
|
|
pairs.push_back({id2string(p.first), p.second});
|
|
}
|
|
std::sort(pairs.begin(), pairs.end());
|
|
};
|
|
|
|
fill(sm);
|
|
|
|
sm.get_view(view);
|
|
|
|
REQUIRE(view.size() == 3);
|
|
|
|
sort_view();
|
|
|
|
REQUIRE((pairs[0] == pt("i", "0")));
|
|
REQUIRE((pairs[1] == pt("j", "1")));
|
|
REQUIRE((pairs[2] == pt("k", "2")));
|
|
|
|
REQUIRE(!sm.has_key("l"));
|
|
sm.insert("l", "3");
|
|
|
|
view.clear();
|
|
sm.get_view(view);
|
|
|
|
REQUIRE(view.size() == 4);
|
|
|
|
sort_view();
|
|
|
|
REQUIRE((pairs[3] == pt("l", "3")));
|
|
}
|
|
|
|
SECTION("Iterate")
|
|
{
|
|
sharing_map_standardt sm;
|
|
|
|
sm.iterate([](const irep_idt &key, const std::string &value) {});
|
|
|
|
fill(sm);
|
|
|
|
typedef std::pair<std::string, std::string> pt;
|
|
std::vector<pt> pairs;
|
|
|
|
sm.iterate([&pairs](const irep_idt &key, const std::string &value) {
|
|
pairs.push_back({id2string(key), value});
|
|
});
|
|
|
|
std::sort(pairs.begin(), pairs.end());
|
|
REQUIRE(pairs.size() == 3);
|
|
REQUIRE((pairs[0] == pt("i", "0")));
|
|
REQUIRE((pairs[1] == pt("j", "1")));
|
|
REQUIRE((pairs[2] == pt("k", "2")));
|
|
}
|
|
|
|
SECTION("Delta view (one empty)")
|
|
{
|
|
sharing_map_standardt sm1;
|
|
fill(sm1);
|
|
|
|
sharing_map_standardt sm2;
|
|
|
|
sharing_map_standardt::delta_viewt delta_view;
|
|
|
|
sm1.get_delta_view(sm2, delta_view, false);
|
|
REQUIRE(delta_view.size() == 3);
|
|
|
|
delta_view.clear();
|
|
sm2.get_delta_view(sm1, delta_view, false);
|
|
REQUIRE(delta_view.empty());
|
|
}
|
|
|
|
SECTION("Delta view (no sharing, same keys)")
|
|
{
|
|
sharing_map_standardt sm1;
|
|
fill(sm1);
|
|
|
|
sharing_map_standardt sm2;
|
|
fill(sm2);
|
|
|
|
sharing_map_standardt::delta_viewt delta_view;
|
|
|
|
sm1.get_delta_view(sm2, delta_view);
|
|
REQUIRE(delta_view.size() == 3);
|
|
|
|
delta_view.clear();
|
|
sm1.get_delta_view(sm2, delta_view, false);
|
|
REQUIRE(delta_view.size() == 3);
|
|
}
|
|
|
|
SECTION("delta view (all shared, same keys)")
|
|
{
|
|
sharing_map_standardt sm1;
|
|
fill(sm1);
|
|
|
|
sharing_map_standardt sm2(sm1);
|
|
|
|
sharing_map_standardt::delta_viewt delta_view;
|
|
|
|
sm1.get_delta_view(sm2, delta_view);
|
|
REQUIRE(delta_view.size() == 0);
|
|
|
|
delta_view.clear();
|
|
sm1.get_delta_view(sm2, delta_view, false);
|
|
REQUIRE(delta_view.size() == 0);
|
|
}
|
|
|
|
SECTION("delta view (some sharing, same keys)")
|
|
{
|
|
sharing_map_standardt sm1;
|
|
fill(sm1);
|
|
|
|
sharing_map_standardt sm2(sm1);
|
|
sm2.replace("i", "3");
|
|
|
|
sharing_map_standardt::delta_viewt delta_view;
|
|
|
|
sm1.get_delta_view(sm2, delta_view);
|
|
REQUIRE(delta_view.size() > 0); // not everything is shared
|
|
REQUIRE(delta_view.size() < 3); // there is some sharing
|
|
|
|
delta_view.clear();
|
|
sm1.get_delta_view(sm2, delta_view, false);
|
|
REQUIRE(delta_view.size() > 0); // not everything is shared
|
|
REQUIRE(delta_view.size() < 3); // there is some sharing
|
|
}
|
|
|
|
SECTION("delta view (no sharing, different keys)")
|
|
{
|
|
sharing_map_standardt sm1;
|
|
fill(sm1);
|
|
|
|
sharing_map_standardt sm2;
|
|
fill2(sm2);
|
|
|
|
sharing_map_standardt::delta_viewt delta_view;
|
|
|
|
sm1.get_delta_view(sm2, delta_view);
|
|
REQUIRE(delta_view.size() == 0);
|
|
|
|
delta_view.clear();
|
|
sm1.get_delta_view(sm2, delta_view, false);
|
|
REQUIRE(delta_view.size() == 3);
|
|
}
|
|
|
|
SECTION("delta view (no sharing, one of the maps is deeper)")
|
|
{
|
|
std::set<const void *> marked;
|
|
std::size_t chunk = 3;
|
|
|
|
sharing_map_unsignedt sm1;
|
|
sharing_map_unsignedt sm2;
|
|
|
|
SECTION("left map deeper")
|
|
{
|
|
sm1.insert(0, "a");
|
|
sm1.insert(1 << (2 * chunk), "b");
|
|
|
|
sm2.insert(0, "c");
|
|
sm2.insert(1, "d");
|
|
|
|
sharing_map_unsignedt::delta_viewt delta_view;
|
|
sm1.get_delta_view(sm2, delta_view, false);
|
|
|
|
REQUIRE(delta_view.size() == 2);
|
|
|
|
const bool b0 = delta_view[0].is_in_both_maps();
|
|
const bool b1 = delta_view[1].is_in_both_maps();
|
|
|
|
REQUIRE((b0 || b1));
|
|
REQUIRE(!(b0 && b1));
|
|
|
|
if(b0)
|
|
{
|
|
REQUIRE(delta_view[0].k == 0);
|
|
REQUIRE(delta_view[0].m == "a");
|
|
REQUIRE(delta_view[0].get_other_map_value() == "c");
|
|
|
|
REQUIRE(delta_view[1].k == 1 << (2 * chunk));
|
|
REQUIRE(delta_view[1].m == "b");
|
|
}
|
|
else
|
|
{
|
|
REQUIRE(delta_view[0].k == 1 << (2 * chunk));
|
|
REQUIRE(delta_view[0].m == "b");
|
|
|
|
REQUIRE(delta_view[1].k == 0);
|
|
REQUIRE(delta_view[1].m == "a");
|
|
REQUIRE(delta_view[1].get_other_map_value() == "c");
|
|
}
|
|
}
|
|
|
|
SECTION("right map deeper")
|
|
{
|
|
sm1.insert(0, "c");
|
|
sm1.insert(1, "d");
|
|
|
|
sm2.insert(0, "a");
|
|
sm2.insert(1 << (2 * chunk), "b");
|
|
|
|
sharing_map_unsignedt::delta_viewt delta_view;
|
|
sm1.get_delta_view(sm2, delta_view, false);
|
|
|
|
REQUIRE(delta_view.size() == 2);
|
|
|
|
const bool b0 = delta_view[0].is_in_both_maps();
|
|
const bool b1 = delta_view[1].is_in_both_maps();
|
|
|
|
REQUIRE((b0 || b1));
|
|
REQUIRE(!(b0 && b1));
|
|
|
|
if(b0)
|
|
{
|
|
REQUIRE(delta_view[0].k == 0);
|
|
REQUIRE(delta_view[0].m == "c");
|
|
REQUIRE(delta_view[0].get_other_map_value() == "a");
|
|
|
|
REQUIRE(delta_view[1].k == 1);
|
|
REQUIRE(delta_view[1].m == "d");
|
|
}
|
|
else
|
|
{
|
|
REQUIRE(delta_view[0].k == 1);
|
|
REQUIRE(delta_view[0].m == "d");
|
|
|
|
REQUIRE(delta_view[1].k == 0);
|
|
REQUIRE(delta_view[1].m == "c");
|
|
REQUIRE(delta_view[1].get_other_map_value() == "a");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Sharing map view validity", "[core][util]")
|
|
{
|
|
SECTION("View validity")
|
|
{
|
|
sharing_map_standardt sm;
|
|
sharing_map_standardt::viewt view;
|
|
|
|
fill(sm);
|
|
fill2(sm);
|
|
|
|
sharing_map_standardt sm2(sm);
|
|
sm2.replace("l", "8");
|
|
|
|
sm.get_view(view);
|
|
|
|
std::size_t i_idx = 0;
|
|
std::size_t k_idx = 0;
|
|
|
|
for(std::size_t i = 0; i < view.size(); i++)
|
|
{
|
|
if(view[i].first == "i")
|
|
i_idx = i;
|
|
|
|
if(view[i].first == "k")
|
|
k_idx = i;
|
|
}
|
|
|
|
sm.erase("i");
|
|
sm.replace("k", "7");
|
|
sm.insert("o", "6");
|
|
|
|
for(std::size_t i = 0; i < view.size(); i++)
|
|
{
|
|
if(i == i_idx || i == k_idx)
|
|
continue;
|
|
|
|
auto &p = view[i];
|
|
|
|
REQUIRE(&p.second == &sm.find(p.first)->get());
|
|
}
|
|
}
|
|
|
|
SECTION("Delta view validity")
|
|
{
|
|
sharing_map_standardt sm;
|
|
|
|
sharing_map_standardt::delta_viewt delta_view;
|
|
|
|
fill(sm);
|
|
fill2(sm);
|
|
|
|
sharing_map_standardt sm2(sm);
|
|
|
|
sm2.erase("i");
|
|
sm2.erase("j");
|
|
sm2.erase("k");
|
|
|
|
sm2.erase("m");
|
|
sm2.erase("n");
|
|
|
|
sm.get_delta_view(sm2, delta_view, false);
|
|
|
|
REQUIRE(delta_view.size() == 5);
|
|
|
|
std::size_t i_idx = 0;
|
|
std::size_t k_idx = 0;
|
|
|
|
for(std::size_t i = 0; i < delta_view.size(); i++)
|
|
{
|
|
if(delta_view[i].k == "i")
|
|
i_idx = i;
|
|
|
|
if(delta_view[i].k == "k")
|
|
k_idx = i;
|
|
}
|
|
|
|
sm.erase("i");
|
|
sm.replace("k", "7");
|
|
sm.insert("o", "6");
|
|
|
|
for(std::size_t i = 0; i < delta_view.size(); i++)
|
|
{
|
|
if(i == i_idx || i == k_idx)
|
|
continue;
|
|
|
|
auto &delta_item = delta_view[i];
|
|
|
|
REQUIRE(&delta_item.m == &sm.find(delta_item.k)->get());
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Sharing map sharing stats", "[core][util]")
|
|
{
|
|
#if !defined(_MSC_VER)
|
|
SECTION("sharing stats")
|
|
{
|
|
std::vector<sharing_map_standardt> v;
|
|
sharing_map_standardt::sharing_map_statst sms;
|
|
|
|
SECTION("sharing stats no sharing")
|
|
{
|
|
v.emplace_back();
|
|
v.emplace_back();
|
|
|
|
REQUIRE(v.size() == 2);
|
|
|
|
// Empty maps
|
|
sms = sharing_map_standardt::get_sharing_stats(v.begin(), v.end());
|
|
REQUIRE(sms.num_nodes == 0);
|
|
REQUIRE(sms.num_unique_nodes == 0);
|
|
REQUIRE(sms.num_leafs == 0);
|
|
REQUIRE(sms.num_unique_leafs == 0);
|
|
|
|
sharing_map_standardt &sm1 = v.at(0);
|
|
sharing_map_standardt &sm2 = v.at(1);
|
|
|
|
fill(sm1);
|
|
fill(sm2);
|
|
|
|
// Non-empty maps
|
|
sms = sharing_map_standardt::get_sharing_stats(v.begin(), v.end());
|
|
REQUIRE(sms.num_leafs == 6);
|
|
REQUIRE(sms.num_unique_leafs == 6);
|
|
}
|
|
|
|
SECTION("sharing stats sharing 1")
|
|
{
|
|
sharing_map_standardt sm1;
|
|
fill(sm1);
|
|
v.push_back(sm1);
|
|
|
|
sharing_map_standardt sm2(sm1);
|
|
v.push_back(sm2);
|
|
|
|
sms = sharing_map_standardt::get_sharing_stats(v.begin(), v.end());
|
|
REQUIRE(sms.num_leafs == 6);
|
|
REQUIRE(sms.num_unique_leafs == 3);
|
|
}
|
|
|
|
SECTION("sharing stats sharing 2")
|
|
{
|
|
sharing_map_standardt sm1;
|
|
fill(sm1);
|
|
v.push_back(sm1);
|
|
|
|
sharing_map_standardt sm2(sm1);
|
|
v.push_back(sm2);
|
|
|
|
sharing_map_standardt sm3(sm1);
|
|
sm3.insert("x", "0");
|
|
v.push_back(sm3);
|
|
|
|
sharing_map_standardt sm4(sm1);
|
|
sm4.replace("i", "4");
|
|
v.push_back(sm4);
|
|
|
|
sms = sharing_map_standardt::get_sharing_stats(v.begin(), v.end());
|
|
REQUIRE(sms.num_leafs == 13);
|
|
REQUIRE(sms.num_unique_leafs == 5);
|
|
}
|
|
}
|
|
|
|
SECTION("sharing stats map")
|
|
{
|
|
std::map<irep_idt, sharing_map_standardt> m;
|
|
|
|
sharing_map_standardt sm1;
|
|
fill(sm1);
|
|
|
|
sharing_map_standardt sm2(sm1);
|
|
|
|
m["a"] = sm1;
|
|
m["b"] = sm2;
|
|
|
|
sharing_map_standardt::sharing_map_statst sms;
|
|
sms = sharing_map_standardt::get_sharing_stats_map(m.begin(), m.end());
|
|
REQUIRE(sms.num_leafs == 6);
|
|
REQUIRE(sms.num_unique_leafs == 3);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
struct no_default_constructort
|
|
{
|
|
no_default_constructort() = delete;
|
|
explicit no_default_constructort(int val) : val(val)
|
|
{
|
|
}
|
|
no_default_constructort(const no_default_constructort &) = default;
|
|
|
|
int val;
|
|
};
|
|
|
|
TEST_CASE("Sharing map with a non-default-constructable value", "[core][util]")
|
|
{
|
|
typedef sharing_mapt<int, no_default_constructort>
|
|
sharing_map_no_default_constructort;
|
|
|
|
sharing_map_no_default_constructort map1;
|
|
|
|
map1.insert(0, no_default_constructort{0});
|
|
map1.insert(1, no_default_constructort{1});
|
|
|
|
sharing_map_no_default_constructort map2 = map1;
|
|
map2.replace(1, no_default_constructort{3});
|
|
map2.insert(2, no_default_constructort{2});
|
|
|
|
sharing_map_no_default_constructort::delta_viewt delta_view;
|
|
map2.get_delta_view(map1, delta_view, false);
|
|
|
|
REQUIRE(delta_view.size() == 2);
|
|
const auto &entry_1 = delta_view[delta_view[0].k == 1 ? 0 : 1];
|
|
const auto &entry_2 = delta_view[delta_view[0].k == 1 ? 1 : 0];
|
|
|
|
REQUIRE(entry_1.k == 1);
|
|
REQUIRE(entry_1.is_in_both_maps());
|
|
REQUIRE(entry_1.m.val == 3);
|
|
REQUIRE(entry_1.get_other_map_value().val == 1);
|
|
|
|
REQUIRE(entry_2.k == 2);
|
|
REQUIRE(!entry_2.is_in_both_maps());
|
|
REQUIRE(entry_2.m.val == 2);
|
|
}
|