Skip to content

Commit 03ada6e

Browse files
committed
Use key to search in add_item_if_not_shared()
When the method get_delta_view() encounters a leaf node in the first map, it searches for a leaf with the same key in the corresponding subtree of the second map. Previously all the nodes in the subtree were visited. This commit changes the traversal such that the hash code of a key is used to determine the position of the leaf in the second map.
1 parent 2be4753 commit 03ada6e

File tree

1 file changed

+48
-38
lines changed

1 file changed

+48
-38
lines changed

src/util/sharing_map.h

+48-38
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,7 @@ class sharing_mapt
548548
void add_item_if_not_shared(
549549
const innert &container,
550550
const innert &inner,
551+
const std::size_t level,
551552
delta_viewt &delta_view,
552553
const bool only_common) const;
553554

@@ -564,6 +565,7 @@ class sharing_mapt
564565
bool mark = true) const;
565566

566567
static const std::string not_found_msg;
568+
static const std::size_t dummy_level;
567569

568570
// config
569571
static const std::size_t bits;
@@ -792,67 +794,61 @@ ::gather_all(const innert &n, delta_viewt &delta_view) const
792794
SHARING_MAPT(void)::add_item_if_not_shared(
793795
const innert &container,
794796
const innert &inner,
797+
const std::size_t level,
795798
delta_viewt &delta_view,
796799
const bool only_common) const
797800
{
798-
SM_ASSERT(!container.empty());
799-
SM_ASSERT(!inner.empty());
801+
const leaft &l1 = container.get_container().front();
800802

801-
std::stack<const innert *> stack;
802-
stack.push(&inner);
803+
const auto &k = l1.get_key();
804+
std::size_t key = hash()(k);
803805

804-
do
806+
key >>= level * chunk;
807+
808+
const innert *ip = &inner;
809+
SM_ASSERT(ip->is_defined_internal());
810+
811+
while(true)
805812
{
806-
const innert *ip = stack.top();
807-
stack.pop();
813+
std::size_t bit = key & mask;
808814

809-
SM_ASSERT(!ip->empty());
815+
ip = ip->find_child(bit);
810816

811-
if(ip->is_internal())
817+
// only in first map
818+
if(ip == nullptr)
812819
{
813-
const to_mapt &m = ip->get_to_map();
814-
SM_ASSERT(!m.empty());
815-
816-
for(const auto &item : m)
820+
if(!only_common)
817821
{
818-
const innert *i = &item.second;
819-
stack.push(i);
822+
delta_view.push_back({k, l1.get_value()});
820823
}
821-
}
822-
else
823-
{
824-
SM_ASSERT(ip->is_container());
825824

826-
if(ip->shares_with(container))
827-
return;
825+
return;
826+
}
828827

829-
const leaft &l1 = container.get_container().front();
828+
SM_ASSERT(!ip->empty());
830829

831-
const leaf_listt &ll = ip->get_container();
832-
SM_ASSERT(!ll.empty());
830+
// potentially in both maps
831+
if(ip->is_container())
832+
{
833+
if(container.shares_with(*ip))
834+
return;
833835

834-
for(const auto &l : ll)
836+
for(const auto &l2 : ip->get_container())
835837
{
836-
if(l1.shares_with(l))
838+
if(l1.shares_with(l2))
837839
return;
838840

839-
if(l1.get_key() == l.get_key())
841+
if(l1.get_key() == l2.get_key())
840842
{
841-
// element is in both maps and not shared
842-
delta_view.push_back(
843-
{true, l1.get_key(), l1.get_value(), l.get_value()});
843+
delta_view.push_back({k, l1.get_value(), l2.get_value()});
844844
return;
845845
}
846846
}
847+
848+
return;
847849
}
848-
}
849-
while(!stack.empty());
850850

851-
// element is only in first map
852-
if(!only_common)
853-
{
854-
const leaft &l1 = container.get_container().front();
855-
delta_view.push_back({false, l1.get_key(), l1.get_value(), dummy});
851+
key >>= chunk;
856852
}
857853
}
858854

@@ -880,6 +876,8 @@ ::get_delta_view(
880876
typedef std::pair<const innert *, const innert *> stack_itemt;
881877
std::stack<stack_itemt> stack;
882878

879+
std::stack<std::size_t> level_stack;
880+
883881
// We do a DFS "in lockstep" simultaneously on both maps. For
884882
// corresponding nodes we check whether they are shared between the
885883
// maps, and if not, we recurse into the corresponding subtrees.
@@ -891,6 +889,7 @@ ::get_delta_view(
891889
return;
892890

893891
stack.push(stack_itemt(&map, &other.map));
892+
level_stack.push(0);
894893

895894
do
896895
{
@@ -901,6 +900,9 @@ ::get_delta_view(
901900

902901
stack.pop();
903902

903+
const std::size_t level = level_stack.top();
904+
level_stack.pop();
905+
904906
SM_ASSERT(!ip1->empty());
905907
SM_ASSERT(!ip2->empty());
906908

@@ -920,6 +922,11 @@ ::get_delta_view(
920922
if(!child.shares_with(*ip2))
921923
{
922924
stack.push(stack_itemt(&child, ip2));
925+
926+
// The level is not needed when the node of the left map is an
927+
// internal node, and the node of the right map is a container node,
928+
// hence we just push a dummy element
929+
level_stack.push(dummy_level);
923930
}
924931
}
925932

@@ -947,6 +954,7 @@ ::get_delta_view(
947954
else if(!child.shares_with(*p))
948955
{
949956
stack.push(stack_itemt(&child, p));
957+
level_stack.push(level + 1);
950958
}
951959
}
952960

@@ -958,8 +966,9 @@ ::get_delta_view(
958966
if(ip2->is_internal())
959967
{
960968
SM_ASSERT(is_singular(ip1->get_container()));
969+
SM_ASSERT(level != dummy_level);
961970

962-
add_item_if_not_shared(*ip1, *ip2, delta_view, only_common);
971+
add_item_if_not_shared(*ip1, *ip2, level, delta_view, only_common);
963972

964973
continue;
965974
}
@@ -1283,6 +1292,7 @@ SHARING_MAPT2(optionalt<std::reference_wrapper<const, mapped_type>>)::find(
12831292
// static constants
12841293

12851294
SHARING_MAPT(const std::string)::not_found_msg="key not found";
1295+
SHARING_MAPT(const std::size_t)::dummy_level = 0xff;
12861296

12871297
SHARING_MAPT(const std::size_t)::bits = 30;
12881298
SHARING_MAPT(const std::size_t)::chunk = 3;

0 commit comments

Comments
 (0)