Skip to content

Commit d14ffbc

Browse files
authored
Merge pull request #4582 from danpoe/refactor/sharing-map-iteration
Make sharing map iteration independent of tree depth
2 parents afb3df7 + 16dae89 commit d14ffbc

File tree

3 files changed

+136
-75
lines changed

3 files changed

+136
-75
lines changed

src/util/sharing_map.h

Lines changed: 106 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ class sharing_mapt
453453
if(empty())
454454
return;
455455

456-
iterate(map, 0, f);
456+
iterate(map, f);
457457
}
458458

459459
#if !defined(_MSC_VER)
@@ -525,12 +525,15 @@ class sharing_mapt
525525
}
526526

527527
void iterate(
528-
const baset &n,
529-
const unsigned start_depth,
528+
const innert &n,
530529
std::function<void(const key_type &k, const mapped_type &m)> f) const;
531530

532-
void gather_all(const baset &n, const unsigned depth, delta_viewt &delta_view)
533-
const;
531+
void gather_all(const innert &n, delta_viewt &delta_view) const;
532+
533+
bool is_singular(const leaf_listt &ll) const
534+
{
535+
return !ll.empty() && std::next(ll.begin()) == ll.end();
536+
}
534537

535538
std::size_t count_unmarked_nodes(
536539
bool leafs_only,
@@ -559,42 +562,37 @@ class sharing_mapt
559562

560563
SHARING_MAPT(void)
561564
::iterate(
562-
const baset &n,
563-
unsigned start_depth,
565+
const innert &n,
564566
std::function<void(const key_type &k, const mapped_type &m)> f) const
565567
{
566-
typedef std::pair<unsigned, const baset *> stack_itemt;
568+
SM_ASSERT(!n.empty());
567569

568-
std::stack<stack_itemt> stack;
569-
stack.push({start_depth, &n});
570+
std::stack<const innert *> stack;
571+
stack.push(&n);
570572

571573
do
572574
{
573-
const stack_itemt &si = stack.top();
574-
575-
const unsigned depth = si.first;
576-
const baset *bp = si.second;
577-
575+
const innert *ip = stack.top();
578576
stack.pop();
579577

580-
if(depth < steps) // internal
578+
SM_ASSERT(!ip->empty());
579+
580+
if(ip->is_internal())
581581
{
582-
const innert *ip = static_cast<const innert *>(bp);
583582
const to_mapt &m = ip->get_to_map();
584583
SM_ASSERT(!m.empty());
585584

586585
for(const auto &item : m)
587586
{
588587
const innert *i = &item.second;
589-
stack.push({depth + 1, i});
588+
stack.push(i);
590589
}
591590
}
592-
else // container
591+
else
593592
{
594-
SM_ASSERT(depth == steps);
593+
SM_ASSERT(ip->is_container());
595594

596-
const innert *cp = static_cast<const innert *>(bp);
597-
const leaf_listt &ll = cp->get_container();
595+
const leaf_listt &ll = ip->get_container();
598596
SM_ASSERT(!ll.empty());
599597

600598
for(const auto &l : ll)
@@ -617,23 +615,15 @@ ::count_unmarked_nodes(
617615

618616
unsigned count = 0;
619617

620-
// depth, node pointer
621-
typedef std::pair<unsigned, const baset *> stack_itemt;
622-
623-
std::stack<stack_itemt> stack;
624-
stack.push({0, &map});
618+
std::stack<const innert *> stack;
619+
stack.push(&map);
625620

626621
do
627622
{
628-
const stack_itemt &si = stack.top();
629-
630-
const unsigned depth = si.first;
631-
const baset *bp = si.second;
632-
623+
const innert *ip = stack.top();
633624
stack.pop();
634625

635626
// internal node or container node
636-
const innert *ip = static_cast<const innert *>(bp);
637627
const unsigned use_count = ip->use_count();
638628
const void *raw_ptr = ip->is_internal()
639629
? (const void *)&ip->read_internal()
@@ -657,20 +647,22 @@ ::count_unmarked_nodes(
657647
count++;
658648
}
659649

660-
if(depth < steps) // internal
650+
if(ip->is_internal())
661651
{
652+
SM_ASSERT(!ip->empty());
653+
662654
const to_mapt &m = ip->get_to_map();
663655
SM_ASSERT(!m.empty());
664656

665657
for(const auto &item : m)
666658
{
667659
const innert *i = &item.second;
668-
stack.push({depth + 1, i});
660+
stack.push(i);
669661
}
670662
}
671-
else // container
663+
else
672664
{
673-
SM_ASSERT(depth == steps);
665+
SM_ASSERT(ip->is_defined_container());
674666

675667
const leaf_listt &ll = ip->get_container();
676668
SM_ASSERT(!ll.empty());
@@ -766,17 +758,17 @@ SHARING_MAPT(void)::get_view(viewt &view) const
766758
view.push_back(view_itemt(k, m));
767759
};
768760

769-
iterate(map, 0, f);
761+
iterate(map, f);
770762
}
771763

772764
SHARING_MAPT(void)
773-
::gather_all(const baset &n, unsigned depth, delta_viewt &delta_view) const
765+
::gather_all(const innert &n, delta_viewt &delta_view) const
774766
{
775767
auto f = [&delta_view](const key_type &k, const mapped_type &m) {
776768
delta_view.push_back(delta_view_itemt(false, k, m, dummy));
777769
};
778770

779-
iterate(n, depth, f);
771+
iterate(n, f);
780772
}
781773

782774
SHARING_MAPT(void)
@@ -794,13 +786,13 @@ ::get_delta_view(
794786
{
795787
if(!only_common)
796788
{
797-
gather_all(map, 0, delta_view);
789+
gather_all(map, delta_view);
798790
}
799791

800792
return;
801793
}
802794

803-
typedef std::tuple<unsigned, const baset *, const baset *> stack_itemt;
795+
typedef std::pair<const innert *, const innert *> stack_itemt;
804796
std::stack<stack_itemt> stack;
805797

806798
// We do a DFS "in lockstep" simultaneously on both maps. For
@@ -810,71 +802,106 @@ ::get_delta_view(
810802
// The stack contains the children of already visited nodes that we
811803
// still have to visit during the traversal.
812804

813-
stack.push(stack_itemt(0, &map, &other.map));
805+
if(map.shares_with(other.map))
806+
return;
807+
808+
stack.push(stack_itemt(&map, &other.map));
814809

815810
do
816811
{
817812
const stack_itemt &si = stack.top();
818813

819-
const unsigned depth = std::get<0>(si);
820-
const baset *bp1 = std::get<1>(si);
821-
const baset *bp2 = std::get<2>(si);
814+
const innert *ip1 = si.first;
815+
const innert *ip2 = si.second;
822816

823817
stack.pop();
824818

825-
if(depth < steps) // internal
819+
SM_ASSERT(!ip1->empty());
820+
SM_ASSERT(!ip2->empty());
821+
822+
if(ip1->is_internal() && ip2->is_container())
826823
{
827-
const innert *ip1 = static_cast<const innert *>(bp1);
828-
const innert *ip2 = static_cast<const innert *>(bp2);
824+
// The container *ip2 contains one element as only containers at the
825+
// bottom of the tree can have more than one element. This happens when
826+
// two different keys have the same hash code. It is known here that *ip2
827+
// is not at the bottom of the tree, as *ip1 (the corresponding node in
828+
// the other map) is an internal node, and internal nodes cannot be at the
829+
// bottom of the map.
830+
SM_ASSERT(is_singular(ip2->get_container()));
831+
832+
for(const auto &item : ip1->get_to_map())
833+
{
834+
const innert &child = item.second;
835+
SM_ASSERT(!child.shares_with(*ip2));
836+
stack.push(stack_itemt(&child, ip2));
837+
}
829838

830-
const to_mapt &m = ip1->get_to_map();
839+
continue;
840+
}
831841

832-
for(const auto &item : m)
842+
if(ip1->is_internal())
843+
{
844+
SM_ASSERT(ip2->is_internal());
845+
846+
for(const auto &item : ip1->get_to_map())
833847
{
834-
const innert *p;
848+
const innert &child = item.second;
835849

850+
const innert *p;
836851
p = ip2->find_child(item.first);
837-
if(p==nullptr)
852+
853+
if(p == nullptr)
838854
{
839855
if(!only_common)
840856
{
841-
gather_all(item.second, depth + 1, delta_view);
857+
gather_all(child, delta_view);
842858
}
843859
}
844-
else if(!item.second.shares_with(*p))
860+
else if(!child.shares_with(*p))
845861
{
846-
stack.push(stack_itemt(depth + 1, &item.second, p));
862+
stack.push(stack_itemt(&child, p));
847863
}
848864
}
865+
866+
continue;
849867
}
850-
else // container
851-
{
852-
SM_ASSERT(depth == steps);
853868

854-
const innert *cp1 = static_cast<const innert *>(bp1);
855-
const innert *cp2 = static_cast<const innert *>(bp2);
869+
SM_ASSERT(ip1->is_container());
856870

857-
const leaf_listt &ll1 = cp1->get_container();
871+
if(ip2->is_internal())
872+
{
873+
SM_ASSERT(is_singular(ip1->get_container()));
858874

859-
for(const auto &l1 : ll1)
875+
for(const auto &item : ip2->get_to_map())
860876
{
861-
const key_type &k1=l1.get_key();
862-
const leaft *p;
877+
const innert &child = item.second;
878+
SM_ASSERT(!ip1->shares_with(child));
879+
stack.push(stack_itemt(ip1, &child));
880+
}
863881

864-
p = cp2->find_leaf(k1);
882+
continue;
883+
}
865884

866-
if(p != nullptr)
867-
{
868-
if(!l1.shares_with(*p))
869-
{
870-
delta_view.push_back({true, k1, l1.get_value(), p->get_value()});
871-
}
872-
}
873-
else if(!only_common)
885+
SM_ASSERT(ip2->is_container());
886+
887+
for(const auto &l1 : ip1->get_container())
888+
{
889+
const key_type &k1 = l1.get_key();
890+
const leaft *p;
891+
892+
p = ip2->find_leaf(k1);
893+
894+
if(p != nullptr)
895+
{
896+
if(!l1.shares_with(*p))
874897
{
875-
delta_view.push_back({false, l1.get_key(), l1.get_value(), dummy});
898+
delta_view.push_back({true, k1, l1.get_value(), p->get_value()});
876899
}
877900
}
901+
else if(!only_common)
902+
{
903+
delta_view.push_back({false, l1.get_key(), l1.get_value(), dummy});
904+
}
878905
}
879906
}
880907
while(!stack.empty());
@@ -894,6 +921,8 @@ SHARING_MAPT2(, innert *)::get_container_node(const key_type &k)
894921
key >>= chunk;
895922
}
896923

924+
SM_ASSERT(ip->is_container());
925+
897926
return ip;
898927
}
899928

@@ -916,6 +945,8 @@ SHARING_MAPT2(const, innert *)::get_container_node(const key_type &k) const
916945
key >>= chunk;
917946
}
918947

948+
SM_ASSERT(ip->is_defined_container());
949+
919950
return ip;
920951
}
921952

src/util/sharing_node.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,16 @@ SN_TYPE_PAR_DEF class sharing_node_innert : public sharing_node_baset
163163
return data.is_derived_v();
164164
}
165165

166+
bool is_defined_internal() const
167+
{
168+
return !empty() && is_internal();
169+
}
170+
171+
bool is_defined_container() const
172+
{
173+
return !empty() && is_container();
174+
}
175+
166176
const d_it &read_internal() const
167177
{
168178
SN_ASSERT(!empty());

unit/util/sharing_map.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,9 @@ TEST_CASE("Sharing map views and iteration", "[core][util]")
378378
SECTION("Iterate")
379379
{
380380
sharing_map_standardt sm;
381+
382+
sm.iterate([](const irep_idt &key, const std::string &value) {});
383+
381384
fill(sm);
382385

383386
typedef std::pair<std::string, std::string> pt;
@@ -394,6 +397,23 @@ TEST_CASE("Sharing map views and iteration", "[core][util]")
394397
REQUIRE((pairs[2] == pt("k", "2")));
395398
}
396399

400+
SECTION("Delta view (one empty)")
401+
{
402+
sharing_map_standardt sm1;
403+
fill(sm1);
404+
405+
sharing_map_standardt sm2;
406+
407+
sharing_map_standardt::delta_viewt delta_view;
408+
409+
sm1.get_delta_view(sm2, delta_view, false);
410+
REQUIRE(delta_view.size() == 3);
411+
412+
delta_view.clear();
413+
sm2.get_delta_view(sm1, delta_view, false);
414+
REQUIRE(delta_view.empty());
415+
}
416+
397417
SECTION("Delta view (no sharing, same keys)")
398418
{
399419
sharing_map_standardt sm1;

0 commit comments

Comments
 (0)