Skip to content

Commit 86c5a3f

Browse files
committed
Sharing map variable height trees
Previously the sharing map was a fixed-height tree (with height 6 by default). This changes the sharing map to a variable-height tree.
1 parent c1dae4a commit 86c5a3f

File tree

2 files changed

+434
-22
lines changed

2 files changed

+434
-22
lines changed

src/util/sharing_map.h

+239-21
Original file line numberDiff line numberDiff line change
@@ -535,10 +535,22 @@ class sharing_mapt
535535
return lp;
536536
}
537537

538+
innert *migrate(
539+
const std::size_t i,
540+
const std::size_t key_suffix,
541+
const std::size_t bit_last,
542+
innert &inner);
543+
538544
void iterate(
539545
const innert &n,
540546
std::function<void(const key_type &k, const mapped_type &m)> f) const;
541547

548+
void add_item_if_not_shared(
549+
const innert &container,
550+
const innert &inner,
551+
delta_viewt &delta_view,
552+
const bool only_common) const;
553+
542554
void gather_all(const innert &n, delta_viewt &delta_view) const;
543555

544556
bool is_singular(const leaf_listt &ll) const
@@ -592,8 +604,7 @@ ::iterate(
592604

593605
for(const auto &item : m)
594606
{
595-
const innert *i = &item.second;
596-
stack.push(i);
607+
stack.push(&item.second);
597608
}
598609
}
599610
else
@@ -664,8 +675,7 @@ ::count_unmarked_nodes(
664675

665676
for(const auto &item : m)
666677
{
667-
const innert *i = &item.second;
668-
stack.push(i);
678+
stack.push(&item.second);
669679
}
670680
}
671681
else
@@ -779,6 +789,73 @@ ::gather_all(const innert &n, delta_viewt &delta_view) const
779789
iterate(n, f);
780790
}
781791

792+
SHARING_MAPT(void)::add_item_if_not_shared(
793+
const innert &container,
794+
const innert &inner,
795+
delta_viewt &delta_view,
796+
const bool only_common) const
797+
{
798+
SM_ASSERT(!container.empty());
799+
SM_ASSERT(!inner.empty());
800+
801+
std::stack<const innert *> stack;
802+
stack.push(&inner);
803+
804+
do
805+
{
806+
const innert *ip = stack.top();
807+
stack.pop();
808+
809+
SM_ASSERT(!ip->empty());
810+
811+
if(ip->is_internal())
812+
{
813+
const to_mapt &m = ip->get_to_map();
814+
SM_ASSERT(!m.empty());
815+
816+
for(const auto &item : m)
817+
{
818+
const innert *i = &item.second;
819+
stack.push(i);
820+
}
821+
}
822+
else
823+
{
824+
SM_ASSERT(ip->is_container());
825+
826+
if(ip->shares_with(container))
827+
return;
828+
829+
const leaft &l1 = container.get_container().front();
830+
831+
const leaf_listt &ll = ip->get_container();
832+
SM_ASSERT(!ll.empty());
833+
834+
for(const auto &l : ll)
835+
{
836+
if(l1.shares_with(l))
837+
return;
838+
839+
if(l1.get_key() == l.get_key())
840+
{
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()});
844+
return;
845+
}
846+
}
847+
}
848+
}
849+
while(!stack.empty());
850+
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});
856+
}
857+
}
858+
782859
SHARING_MAPT(void)
783860
::get_delta_view(
784861
const sharing_mapt &other,
@@ -840,8 +917,10 @@ ::get_delta_view(
840917
for(const auto &item : ip1->get_to_map())
841918
{
842919
const innert &child = item.second;
843-
SM_ASSERT(!child.shares_with(*ip2));
844-
stack.push(stack_itemt(&child, ip2));
920+
if(!child.shares_with(*ip2))
921+
{
922+
stack.push(stack_itemt(&child, ip2));
923+
}
845924
}
846925

847926
continue;
@@ -880,12 +959,7 @@ ::get_delta_view(
880959
{
881960
SM_ASSERT(is_singular(ip1->get_container()));
882961

883-
for(const auto &item : ip2->get_to_map())
884-
{
885-
const innert &child = item.second;
886-
SM_ASSERT(!ip1->shares_with(child));
887-
stack.push(stack_itemt(ip1, &child));
888-
}
962+
add_item_if_not_shared(*ip1, *ip2, delta_view, only_common);
889963

890964
continue;
891965
}
@@ -903,11 +977,13 @@ ::get_delta_view(
903977
{
904978
if(!l1.shares_with(*p))
905979
{
980+
SM_ASSERT(other.has_key(k1));
906981
delta_view.push_back({k1, l1.get_value(), p->get_value()});
907982
}
908983
}
909984
else if(!only_common)
910985
{
986+
SM_ASSERT(!other.has_key(k1));
911987
delta_view.push_back({k1, l1.get_value()});
912988
}
913989
}
@@ -917,21 +993,28 @@ ::get_delta_view(
917993

918994
SHARING_MAPT2(, innert *)::get_container_node(const key_type &k)
919995
{
996+
SM_ASSERT(has_key(k));
997+
920998
std::size_t key = hash()(k);
921999
innert *ip = &map;
1000+
SM_ASSERT(ip->is_internal());
9221001

9231002
for(std::size_t i = 0; i < steps; i++)
9241003
{
9251004
std::size_t bit = key & mask;
9261005

9271006
ip = ip->add_child(bit);
1007+
SM_ASSERT(ip != nullptr);
1008+
SM_ASSERT(!ip->empty());
1009+
1010+
if(ip->is_container())
1011+
return ip;
9281012

9291013
key >>= chunk;
9301014
}
9311015

932-
SM_ASSERT(ip->is_container());
933-
934-
return ip;
1016+
UNREACHABLE;
1017+
return nullptr;
9351018
}
9361019

9371020
SHARING_MAPT2(const, innert *)::get_container_node(const key_type &k) const
@@ -942,24 +1025,33 @@ SHARING_MAPT2(const, innert *)::get_container_node(const key_type &k) const
9421025
std::size_t key = hash()(k);
9431026
const innert *ip = &map;
9441027

1028+
SM_ASSERT(ip->is_defined_internal());
1029+
9451030
for(std::size_t i = 0; i < steps; i++)
9461031
{
9471032
std::size_t bit = key & mask;
9481033

9491034
ip = ip->find_child(bit);
1035+
9501036
if(ip == nullptr)
9511037
return nullptr;
9521038

1039+
SM_ASSERT(!ip->empty());
1040+
1041+
if(ip->is_container())
1042+
return ip;
1043+
9531044
key >>= chunk;
9541045
}
9551046

956-
SM_ASSERT(ip->is_defined_container());
957-
958-
return ip;
1047+
UNREACHABLE;
1048+
return nullptr;
9591049
}
9601050

9611051
SHARING_MAPT(void)::erase(const key_type &k)
9621052
{
1053+
SM_ASSERT(has_key(k));
1054+
9631055
innert *del = nullptr;
9641056
std::size_t del_bit = 0;
9651057

@@ -980,6 +1072,9 @@ SHARING_MAPT(void)::erase(const key_type &k)
9801072

9811073
ip = ip->add_child(bit);
9821074

1075+
if(ip->is_defined_container())
1076+
break;
1077+
9831078
key >>= chunk;
9841079
}
9851080

@@ -1001,13 +1096,136 @@ SHARING_MAPT(void)::erase(const key_type &k)
10011096
num--;
10021097
}
10031098

1099+
SHARING_MAPT2(, innert *)::migrate(
1100+
const std::size_t step,
1101+
const std::size_t key_suffix,
1102+
const std::size_t bit_last,
1103+
innert &inner)
1104+
{
1105+
SM_ASSERT(step < steps - 1);
1106+
SM_ASSERT(inner.is_defined_internal());
1107+
1108+
const innert &child = *inner.find_child(bit_last);
1109+
SM_ASSERT(child.is_defined_container());
1110+
1111+
const leaf_listt &ll = child.get_container();
1112+
1113+
// Only containers at the bottom can contain more than two elements
1114+
SM_ASSERT(is_singular(ll));
1115+
1116+
const leaft &leaf = ll.front();
1117+
std::size_t key_existing = hash()(leaf.get_key());
1118+
1119+
key_existing >>= chunk * step;
1120+
1121+
// Copy the container
1122+
innert container_copy(child);
1123+
1124+
// Delete existing container
1125+
inner.remove_child(bit_last);
1126+
1127+
// Add internal node
1128+
innert *ip = inner.add_child(bit_last);
1129+
SM_ASSERT(ip->empty());
1130+
1131+
// Find place for both elements
1132+
1133+
std::size_t i = step + 1;
1134+
std::size_t key = key_suffix;
1135+
1136+
key_existing >>= chunk;
1137+
key >>= chunk;
1138+
1139+
SM_ASSERT(i < steps);
1140+
1141+
do
1142+
{
1143+
std::size_t bit_existing = key_existing & mask;
1144+
std::size_t bit = key & mask;
1145+
1146+
if(bit != bit_existing)
1147+
{
1148+
// Place found
1149+
1150+
innert *cp2 = ip->add_child(bit_existing);
1151+
cp2->swap(container_copy);
1152+
1153+
innert *cp1 = ip->add_child(bit);
1154+
return cp1;
1155+
}
1156+
1157+
SM_ASSERT(bit == bit_existing);
1158+
ip = ip->add_child(bit);
1159+
1160+
key >>= chunk;
1161+
key_existing >>= chunk;
1162+
1163+
i++;
1164+
} while(i < steps);
1165+
1166+
leaft leaf_copy(as_const(&container_copy)->get_container().front());
1167+
ip->get_container().push_front(leaf_copy);
1168+
1169+
return ip;
1170+
}
1171+
10041172
SHARING_MAPT4(valueU, void)
10051173
::insert(const key_type &k, valueU &&m)
10061174
{
1007-
innert *cp = get_container_node(k);
1008-
SM_ASSERT(cp != nullptr);
1175+
SM_ASSERT(!has_key(k));
1176+
1177+
std::size_t key = hash()(k);
1178+
innert *ip = &map;
1179+
1180+
// The root cannot be a container node
1181+
SM_ASSERT(ip->is_internal());
1182+
1183+
for(std::size_t i = 0; i < steps; i++)
1184+
{
1185+
std::size_t bit = key & mask;
1186+
1187+
SM_ASSERT(ip != nullptr);
1188+
SM_ASSERT(ip->is_internal());
1189+
SM_ASSERT(i == 0 || !ip->empty());
1190+
1191+
innert *child = ip->add_child(bit);
1192+
1193+
// Place is unoccupied
1194+
if(child->empty())
1195+
{
1196+
// Create container and insert leaf
1197+
child->place_leaf(k, std::forward<valueU>(m));
1198+
1199+
SM_ASSERT(child->is_defined_container());
1200+
1201+
num++;
1202+
1203+
return;
1204+
}
1205+
1206+
if(child->is_container() && i < steps - 1)
1207+
{
1208+
// Migrate the elements downwards
1209+
innert *cp = migrate(i, key, bit, *ip);
1210+
1211+
cp->place_leaf(k, std::forward<valueU>(m));
1212+
1213+
num++;
1214+
1215+
return;
1216+
}
1217+
1218+
SM_ASSERT(i == steps - 1 || child->is_defined_internal());
1219+
1220+
ip = child;
1221+
key >>= chunk;
1222+
}
1223+
1224+
SM_ASSERT(ip->is_defined_container());
1225+
1226+
// Add to the bottom container
1227+
ip->place_leaf(k, std::forward<valueU>(m));
10091228

1010-
cp->place_leaf(k, std::forward<valueU>(m));
10111229
num++;
10121230
}
10131231

0 commit comments

Comments
 (0)