Commit 1265a114 authored by Philipp Götze's avatar Philipp Götze
Browse files

🐞 Fixed a bug for wBP/wHBP Trees +++ Refactored wHBPTreeTest

parent e9e6d95b
Pipeline #280 passed with stages
in 10 minutes and 2 seconds
......@@ -705,7 +705,8 @@ class wBPTree {
auto d = depth.get_ro();
while (d-- > 0) {
auto pos = lookupPositionInBranchNode(node.branch, key);
node = node.branch->children.get_ro()[pos];
auto &nodeRef = *node.branch;
node = nodeRef.children.get_ro()[nodeRef.search.get_ro().slot[pos]];
}
return node.leaf;
}
......
......@@ -74,10 +74,8 @@ class wHBPTree {
struct Node {
Node() : tag(BLANK) {};
Node(pptr<LeafNode> leaf_) : tag(LEAF), leaf(leaf_) {};
Node(BranchNode branch_) : tag(BRANCH), branch(branch_) {};
explicit Node(pptr<LeafNode> leaf_) : tag(LEAF), leaf(leaf_) {};
explicit Node(BranchNode branch_) : tag(BRANCH), branch(branch_) {};
Node(const Node &other) { copy(other); };
void copy(const Node &other) throw() {
......@@ -190,7 +188,11 @@ class wHBPTree {
return new BranchNode();
}
void deleteBranchNode(BranchNode*& node) {
BranchNode *newBranchNode(const BranchNode *other) {
return new BranchNode(*other);
}
void deleteBranchNode(BranchNode *&node) {
delete node;
node = nullptr;
}
......@@ -383,7 +385,7 @@ class wHBPTree {
++leafs;
currentLeaf = currentLeaf->nextLeaf;
}
float x = std::log(leafs)/std::log(N+1);
float x = std::log(leafs)/std::log1p(N);
assert(x == int(x) && "Not supported for this amount of leafs, yet");
/* actual recovery */
......@@ -505,7 +507,7 @@ class wHBPTree {
auto &splitRef = *splitInfo;
/// insert the new entry
if (slotPos-1 <= (M + 1) / 2)
if (slotPos < (M + 1) / 2)
insertInLeafNodeAtPosition(splitRef.leftChild.leaf, slotPos, key, val);
else
insertInLeafNodeAtPosition(splitRef.rightChild.leaf,
......@@ -741,7 +743,7 @@ class wHBPTree {
auto d = depth;
while (d-- > 0) {
auto pos = lookupPositionInBranchNode(node.branch, key);
node = node.branch->children[pos];
node = node.branch->children[node.branch->search.slot[pos]];
}
return node.leaf;
}
......@@ -810,7 +812,7 @@ class wHBPTree {
* @param key the key to be deleted
* @return true if the entry was deleted
*/
bool eraseFromBranchNode(BranchNode *node, unsigned int d, const KeyType &key) {
bool eraseFromBranchNode(BranchNode *const node, const unsigned int d, const KeyType &key) {
assert(d >= 1);
bool deleted = false;
const auto &nodeRef = *node;
......@@ -925,7 +927,7 @@ class wHBPTree {
* @param child the node at which the underflow occured
* @return the (possibly new) child node (in case of a merge)
*/
BranchNode *underflowAtBranchLevel(BranchNode *node, unsigned int pos,
BranchNode *underflowAtBranchLevel(BranchNode * const node, unsigned int pos,
BranchNode *child) {
assert(node != nullptr);
assert(child != nullptr);
......
......@@ -937,7 +937,7 @@ TEST_CASE("Finding the leaf node containing a key", "[wBPTree]") {
nodeRef.search.get_rw().slot[0] = 1;
btree.rootNode = node;
btree.depth = 2;
btree.depth = 1;
btree.insertInBranchNode(node, 1, 12, 112, &splitInfo);
REQUIRE(leaf2->search.get_ro().slot[0] == 2);
......
......@@ -23,31 +23,24 @@
#define UNIT_TESTS 1
#include "wHBPTree.hpp"
using namespace dbis::pbptrees;
using pmem::obj::delete_persistent;
using pmem::obj::delete_persistent_atomic;
using pmem::obj::make_persistent;
using pmem::obj::p;
using pmem::obj::persistent_ptr;
using pmem::obj::pool;
using pmem::obj::transaction;
TEST_CASE("Finding the leaf node containing a key", "[wHBPTree]") {
using wHBPTreeType = wHBPTree<int, int, 10, 10> ;
using wHBPTreeType2 = wHBPTree<int, int, 4, 4>;
using wHBPTreeType3 = wHBPTree<int, int, 6, 6>;
using wHBPTreeType4 = wHBPTree<int, int, 12, 12>;
using wHBPTreeType5 = wHBPTree<int, int, 20, 20>;
using wHBPTreeType4 = wHBPTree<int, int, 4, 4>;
using wHBPTreeType6 = wHBPTree<int, int, 6, 6>;
using wHBPTreeType10 = wHBPTree<int, int, 10, 10> ;
using wHBPTreeType12 = wHBPTree<int, int, 12, 12>;
using wHBPTreeType20 = wHBPTree<int, int, 20, 20>;
struct root {
persistent_ptr<wHBPTreeType> btree1;
persistent_ptr<wHBPTreeType2> btree2;
persistent_ptr<wHBPTreeType2> btree2_2;
persistent_ptr<wHBPTreeType3> btree3;
persistent_ptr<wHBPTreeType4> btree4;
persistent_ptr<wHBPTreeType5> btree5;
pptr<wHBPTreeType4> btree4;
pptr<wHBPTreeType6> btree6;
pptr<wHBPTreeType10> btree10;
pptr<wHBPTreeType12> btree12;
pptr<wHBPTreeType20> btree20;
};
pool<root> pop;
......@@ -61,475 +54,502 @@ TEST_CASE("Finding the leaf node containing a key", "[wHBPTree]") {
}
auto q = pop.root();
auto &rootRef = *q;
if (!q->btree1)
transaction::run(pop, [&] { q->btree1 = make_persistent<wHBPTreeType>(); });
if (!rootRef.btree4)
transaction::run(pop, [&] { rootRef.btree4 = make_persistent<wHBPTreeType4>(); });
if (!q->btree2)
transaction::run(pop, [&] { q->btree2 = make_persistent<wHBPTreeType2>(); });
if (!q->btree2_2)
transaction::run(pop, [&] { q->btree2_2 = make_persistent<wHBPTreeType2>(); });
if (!rootRef.btree6)
transaction::run(pop, [&] { rootRef.btree6 = make_persistent<wHBPTreeType6>(); });
if (!q->btree3)
transaction::run(pop, [&] { q->btree3 = make_persistent<wHBPTreeType3>(); });
if (!rootRef.btree10)
transaction::run(pop, [&] { rootRef.btree10 = make_persistent<wHBPTreeType10>(); });
if (!q->btree4)
transaction::run(pop, [&] { q->btree4 = make_persistent<wHBPTreeType4>(); });
if (!rootRef.btree12)
transaction::run(pop, [&] { rootRef.btree12 = make_persistent<wHBPTreeType12>(); });
if (!q->btree5)
transaction::run(pop, [&] { q->btree5 = make_persistent<wHBPTreeType5>(); });
if (!rootRef.btree20)
transaction::run(pop, [&] { rootRef.btree20 = make_persistent<wHBPTreeType20>(); });
/* ------------------------------------------------------------------ */
SECTION("Looking up a key in an inner node") {
auto node = q->btree1->newBranchNode();
auto &btree = *rootRef.btree10;
auto node = btree.newBranchNode();
auto &nodeRef = *node;
for (auto i = 0; i < 10; i++) {
node->keys[i] = i + 1;
node->search.b.set(i);
node->search.slot[i+1] = i;
nodeRef.keys[i] = i + 1;
nodeRef.search.b.set(i);
nodeRef.search.slot[i+1] = i;
}
node->search.slot[0] = 10;
nodeRef.search.slot[0] = 10;
REQUIRE(q->btree1->lookupPositionInBranchNode(node, 0) == 1);
REQUIRE(q->btree1->lookupPositionInBranchNode(node, 1) == 2);
REQUIRE(q->btree1->lookupPositionInBranchNode(node, 10) == 11);
REQUIRE(q->btree1->lookupPositionInBranchNode(node, 5) == 6);
REQUIRE(q->btree1->lookupPositionInBranchNode(node, 20) == 11);
REQUIRE(btree.lookupPositionInBranchNode(node, 0) == 1);
REQUIRE(btree.lookupPositionInBranchNode(node, 1) == 2);
REQUIRE(btree.lookupPositionInBranchNode(node, 10) == 11);
REQUIRE(btree.lookupPositionInBranchNode(node, 5) == 6);
REQUIRE(btree.lookupPositionInBranchNode(node, 20) == 11);
q->btree1->deleteBranchNode(node);
btree.deleteBranchNode(node);
}
/* ------------------------------------------------------------------ */
SECTION("Looking up a key in a leaf node") {
auto node = q->btree1->newLeafNode();
auto &btree = *rootRef.btree10;
auto node = btree.newLeafNode();
auto &nodeRef = *node;
for (auto i = 0; i < 10; i++) {
node->keys.get_rw()[i] = i + 1;
node->search.get_rw().b.set(i);
node->search.get_rw().slot[i+1] = i;
nodeRef.keys.get_rw()[i] = i + 1;
nodeRef.search.get_rw().b.set(i);
nodeRef.search.get_rw().slot[i+1] = i;
}
node->search.get_rw().slot[0] = 10;
nodeRef.search.get_rw().slot[0] = 10;
REQUIRE(q->btree1->lookupPositionInLeafNode(node, 1) == 1);
REQUIRE(q->btree1->lookupPositionInLeafNode(node, 10) == 10);
REQUIRE(q->btree1->lookupPositionInLeafNode(node, 5) == 5);
REQUIRE(q->btree1->lookupPositionInLeafNode(node, 20) == 11);
REQUIRE(btree.lookupPositionInLeafNode(node, 1) == 1);
REQUIRE(btree.lookupPositionInLeafNode(node, 10) == 10);
REQUIRE(btree.lookupPositionInLeafNode(node, 5) == 5);
REQUIRE(btree.lookupPositionInLeafNode(node, 20) == 11);
q->btree1->deleteLeafNode(node);
btree.deleteLeafNode(node);
}
/* ------------------------------------------------------------------ */
SECTION("Balancing two inner nodes from left to right") {
auto btree = q->btree2;
std::array<persistent_ptr<wHBPTreeType2::LeafNode>, 7> leafNodes = {{btree->newLeafNode(), btree->newLeafNode(), btree->newLeafNode(),
btree->newLeafNode(), btree->newLeafNode(), btree->newLeafNode(), btree->newLeafNode()}};
auto node1 = btree->newBranchNode();
auto node2 = btree->newBranchNode();
auto node3 = btree->newBranchNode();
node1->keys[0] = 8;
node1->keys[1] = 20;
node1->children[0] = node2;
node1->children[1] = node3;
node1->search.b.set(0);
node1->search.b.set(1);
node1->search.slot[1] = 0;
node1->search.slot[2] = 1;
node1->search.slot[0] = 2;
node2->keys[0] = 3;
node2->keys[1] = 4;
node2->keys[2] = 5;
node2->keys[3] = 6;
node2->children[0] = leafNodes[0];
node2->children[1] = leafNodes[1];
node2->children[2] = leafNodes[2];
node2->children[3] = leafNodes[3];
node2->children[4] = leafNodes[4];
node2->search.b.set(0);
node2->search.b.set(1);
node2->search.b.set(2);
node2->search.b.set(3);
node2->search.slot[1] = 0;
node2->search.slot[2] = 1;
node2->search.slot[3] = 2;
node2->search.slot[4] = 3;
node2->search.slot[0] = 4;
node3->keys[0] = 10;
node3->children[0] = leafNodes[5];
node3->children[4] = leafNodes[6];
node3->search.b.set(0);
node3->search.slot[1] = 0;
node3->search.slot[0] = 1;
btree->rootNode = node1;
btree->depth = 2;
btree->balanceBranchNodes(node2, node3, node1, 1);
REQUIRE(node1->search.slot[0] == 2);
REQUIRE(node2->search.slot[0] == 2);
REQUIRE(node3->search.slot[0] == 3);
auto &btree = *rootRef.btree4;
std::array<pptr<wHBPTreeType4::LeafNode>, 7> leafNodes = {
{ btree.newLeafNode(), btree.newLeafNode(), btree.newLeafNode(), btree.newLeafNode(),
btree.newLeafNode(), btree.newLeafNode(), btree.newLeafNode() }
};
const auto node1 = btree.newBranchNode();
const auto node2 = btree.newBranchNode();
const auto node3 = btree.newBranchNode();
auto &node1Ref = *node1;
auto &node2Ref = *node2;
auto &node3Ref = *node3;
node1Ref.keys[0] = 8;
node1Ref.keys[1] = 20;
node1Ref.children[0] = node2;
node1Ref.children[1] = node3;
node1Ref.search.b.set(0);
node1Ref.search.b.set(1);
node1Ref.search.slot[1] = 0;
node1Ref.search.slot[2] = 1;
node1Ref.search.slot[0] = 2;
node2Ref.keys[0] = 3;
node2Ref.keys[1] = 4;
node2Ref.keys[2] = 5;
node2Ref.keys[3] = 6;
node2Ref.children[0] = leafNodes[0];
node2Ref.children[1] = leafNodes[1];
node2Ref.children[2] = leafNodes[2];
node2Ref.children[3] = leafNodes[3];
node2Ref.children[4] = leafNodes[4];
node2Ref.search.b.set(0);
node2Ref.search.b.set(1);
node2Ref.search.b.set(2);
node2Ref.search.b.set(3);
node2Ref.search.slot[1] = 0;
node2Ref.search.slot[2] = 1;
node2Ref.search.slot[3] = 2;
node2Ref.search.slot[4] = 3;
node2Ref.search.slot[0] = 4;
node3Ref.keys[0] = 10;
node3Ref.children[0] = leafNodes[5];
node3Ref.children[4] = leafNodes[6];
node3Ref.search.b.set(0);
node3Ref.search.slot[1] = 0;
node3Ref.search.slot[0] = 1;
btree.rootNode = node1;
btree.depth = 2;
btree.balanceBranchNodes(node2, node3, node1, 1);
REQUIRE(node1Ref.search.slot[0] == 2);
REQUIRE(node2Ref.search.slot[0] == 2);
REQUIRE(node3Ref.search.slot[0] == 3);
std::array<int, 2> expectedKeys1{{5, 20}};
std::array<int, 2> expectedKeys2{{3, 4}};
std::array<int, 3> expectedKeys3{{6, 8, 10}};
std::array<persistent_ptr<wHBPTreeType2::LeafNode>, 3> expectedChildren2 = {{ leafNodes[0], leafNodes[1], leafNodes[2] }};
std::array<persistent_ptr<wHBPTreeType2::LeafNode>, 4> expectedChildren3 = {{ leafNodes[3], leafNodes[4], leafNodes[5], leafNodes[6] }};
std::array<pptr<wHBPTreeType4::LeafNode>, 3> expectedChildren2 = {
{ leafNodes[0], leafNodes[1], leafNodes[2] }
};
std::array<pptr<wHBPTreeType4::LeafNode>, 4> expectedChildren3 = {
{ leafNodes[3], leafNodes[4], leafNodes[5], leafNodes[6] }
};
std::vector<int> actualKeys{};
for(auto i = 1u; i < node1->search.slot[0] + 1; i++)
actualKeys.push_back(node1->keys[node1->search.slot[i]]);
for(auto i = 1u; i < node1Ref.search.slot[0] + 1; i++)
actualKeys.push_back(node1Ref.keys[node1Ref.search.slot[i]]);
REQUIRE(std::equal(std::begin(expectedKeys1), std::end(expectedKeys1),
std::begin(actualKeys)));
actualKeys.clear();
for(auto i = 1u; i < node2->search.slot[0] + 1; i++)
actualKeys.push_back(node2->keys[node2->search.slot[i]]);
for(auto i = 1u; i < node2Ref.search.slot[0] + 1; i++)
actualKeys.push_back(node2Ref.keys[node2Ref.search.slot[i]]);
REQUIRE(std::equal(std::begin(expectedKeys2), std::end(expectedKeys2),
std::begin(actualKeys)));
actualKeys.clear();
for(auto i = 1u; i < node3->search.slot[0] + 1; i++)
actualKeys.push_back(node3->keys[node3->search.slot[i]]);
for(auto i = 1u; i < node3Ref.search.slot[0] + 1; i++)
actualKeys.push_back(node3Ref.keys[node3Ref.search.slot[i]]);
REQUIRE(std::equal(std::begin(expectedKeys3), std::end(expectedKeys3),
std::begin(actualKeys)));
std::array<persistent_ptr<wHBPTreeType2::LeafNode>, 3> node2Children;
std::array<pptr<wHBPTreeType4::LeafNode>, 3> node2Children;
for (auto i = 1; i < 3; i++)
node2Children[i-1] = node2->children[node2->search.slot[i]].leaf;
node2Children[2] = node2->children[4].leaf;
node2Children[i-1] = node2Ref.children[node2Ref.search.slot[i]].leaf;
node2Children[2] = node2Ref.children[4].leaf;
REQUIRE(std::equal(std::begin(expectedChildren2), std::end(expectedChildren2),
std::begin(node2Children)));
std::array<persistent_ptr<wHBPTreeType2::LeafNode>, 4> node3Children;
std::array<pptr<wHBPTreeType4::LeafNode>, 4> node3Children;
for (auto i = 1; i < 4; i++)
node3Children[i-1] = node3->children[node3->search.slot[i]].leaf;
node3Children[3] = node3->children[4].leaf;
node3Children[i-1] = node3Ref.children[node3Ref.search.slot[i]].leaf;
node3Children[3] = node3Ref.children[4].leaf;
REQUIRE(std::equal(std::begin(expectedChildren3), std::end(expectedChildren3),
std::begin(node3Children)));
}
/* ------------------------------------------------------------------ */
SECTION("Balancing two inner nodes from right to left") {
auto btree = q->btree2;
std::array<persistent_ptr<wHBPTreeType2::LeafNode>, 7> leafNodes = {{btree->newLeafNode(), btree->newLeafNode(), btree->newLeafNode(),
btree->newLeafNode(), btree->newLeafNode(), btree->newLeafNode(), btree->newLeafNode()}};
auto node1 = btree->newBranchNode();
auto node2 = btree->newBranchNode();
auto node3 = btree->newBranchNode();
node1->keys[0] = 4;
node1->keys[1] = 20;
node1->children[0] = node2;
node1->children[4] = node3;
node1->search.b.set(0);
node1->search.b.set(1);
node1->search.slot[1] = 0;
node1->search.slot[2] = 1;
node1->search.slot[0] = 2;
node2->keys[0] = 3;
node2->children[0] = leafNodes[0];
node2->children[4] = leafNodes[1];
node2->search.b.set(0);
node2->search.slot[1] = 0;
node2->search.slot[0] = 1;
node3->keys[0] = 5;
node3->keys[1] = 6;
node3->keys[2] = 7;
node3->keys[3] = 8;
node3->children[0] = leafNodes[2];
node3->children[1] = leafNodes[3];
node3->children[2] = leafNodes[4];
node3->children[3] = leafNodes[5];
node3->children[4] = leafNodes[6];
node3->search.b.set(0);
node3->search.b.set(1);
node3->search.b.set(2);
node3->search.b.set(3);
node3->search.slot[1] = 0;
node3->search.slot[2] = 1;
node3->search.slot[3] = 2;
node3->search.slot[4] = 3;
node3->search.slot[0] = 4;
btree->rootNode = node1;
btree->depth = 2;
btree->balanceBranchNodes(node3, node2, node1, 1);
REQUIRE(node1->search.slot[0] == 2);
REQUIRE(node2->search.slot[0] == 3);
REQUIRE(node3->search.slot[0] == 2);
auto &btree = *rootRef.btree4;
std::array<pptr<wHBPTreeType4::LeafNode>, 7> leafNodes = {{btree.newLeafNode(), btree.newLeafNode(), btree.newLeafNode(),
btree.newLeafNode(), btree.newLeafNode(), btree.newLeafNode(), btree.newLeafNode()}};
const auto node1 = btree.newBranchNode();
const auto node2 = btree.newBranchNode();
const auto node3 = btree.newBranchNode();
auto &node1Ref = *node1;
auto &node2Ref = *node2;
auto &node3Ref = *node3;
node1Ref.keys[0] = 4;
node1Ref.keys[1] = 20;
node1Ref.children[0] = node2;
node1Ref.children[4] = node3;
node1Ref.search.b.set(0);
node1Ref.search.b.set(1);
node1Ref.search.slot[1] = 0;
node1Ref.search.slot[2] = 1;
node1Ref.search.slot[0] = 2;
node2Ref.keys[0] = 3;
node2Ref.children[0] = leafNodes[0];
node2Ref.children[4] = leafNodes[1];
node2Ref.search.b.set(0);
node2Ref.search.slot[1] = 0;
node2Ref.search.slot[0] = 1;
node3Ref.keys[0] = 5;
node3Ref.keys[1] = 6;
node3Ref.keys[2] = 7;
node3Ref.keys[3] = 8;
node3Ref.children[0] = leafNodes[2];
node3Ref.children[1] = leafNodes[3];
node3Ref.children[2] = leafNodes[4];
node3Ref.children[3] = leafNodes[5];
node3Ref.children[4] = leafNodes[6];
node3Ref.search.b.set(0);
node3Ref.search.b.set(1);
node3Ref.search.b.set(2);
node3Ref.search.b.set(3);
node3Ref.search.slot[1] = 0;
node3Ref.search.slot[2] = 1;
node3Ref.search.slot[3] = 2;
node3Ref.search.slot[4] = 3;
node3Ref.search.slot[0] = 4;
btree.rootNode = node1;
btree.depth = 2;
btree.balanceBranchNodes(node3, node2, node1, 1);
REQUIRE(node1Ref.search.slot[0] == 2);
REQUIRE(node2Ref.search.slot[0] == 3);
REQUIRE(node3Ref.search.slot[0] == 2);
std::array<int, 2> expectedKeys1{{6, 20}};
std::array<int, 3> expectedKeys2{{3, 4, 5}};
std::array<int, 2> expectedKeys3{{7, 8}};
std::array<persistent_ptr<wHBPTreeType2::LeafNode>, 4> expectedChildren2 = {{ leafNodes[0], leafNodes[1], leafNodes[2], leafNodes[3] }};
std::array<persistent_ptr<wHBPTreeType2::LeafNode>, 3> expectedChildren3 = {{ leafNodes[4], leafNodes[5], leafNodes[6] }};
std::array<pptr<wHBPTreeType4::LeafNode>, 4> expectedChildren2 = {
{ leafNodes[0], leafNodes[1], leafNodes[2], leafNodes[3] }
};
std::array<pptr<wHBPTreeType4::LeafNode>, 3> expectedChildren3 = {
{ leafNodes[4], leafNodes[5], leafNodes[6] }
};
std::vector<int> actualKeys{};
for(auto i = 1u; i < node1->search.slot[0] + 1; i++)
actualKeys.push_back(node1->keys[node1->search.slot[i]]);
for(auto i = 1u; i < node1Ref.search.slot[0] + 1; i++)
actualKeys.push_back(node1Ref.keys[node1Ref.search.slot[i]]);
REQUIRE(std::equal(std::begin(expectedKeys1), std::end(expectedKeys1),
std::begin(actualKeys)));
actualKeys.clear();
for(auto i = 1u; i < node2->search.slot[0] + 1; i++)
actualKeys.push_back(node2->keys[node2->search.slot[i]]);
for(auto i = 1u; i < node2Ref.search.slot[0] + 1; i++)
actualKeys.push_back(node2Ref.keys[node2Ref.search.slot[i]]);
REQUIRE(std::equal(std::begin(expectedKeys2), std::end(expectedKeys2),
std::begin(actualKeys)));
actualKeys.clear();
for(auto i = 1u; i < node3->search.slot[0] + 1; i++)
actualKeys.push_back(node3->keys[node3->search.slot[i]]);
for(auto i = 1u; i < node3Ref.search.slot[0] + 1; i++)
actualKeys.push_back(node3Ref.keys[node3Ref.search.slot[i]]);
REQUIRE(std::equal(std::begin(expectedKeys3), std::end(expectedKeys3),
std::begin(actualKeys)));
std::array<persistent_ptr<wHBPTreeType2::LeafNode>, 4> node2Children;
std::array<pptr<wHBPTreeType4::LeafNode>, 4> node2Children;
for (auto i = 1; i < 4; i++)
node2Children[i-1] = node2->children[node2->search.slot[i]].leaf;
node2Children[3] = node2->children[4].leaf;
node2Children[i-1] = node2Ref.children[node2Ref.search.slot[i]].leaf;
node2Children[3] = node2Ref.children[4].leaf;
REQUIRE(std::equal(std::begin(expectedChildren2), std::end(expectedChildren2),
std::begin(node2Children)));
std::array<persistent_ptr<wHBPTreeType2::LeafNode>, 3> node3Children;
std::array<pptr<wHBPTreeType4::LeafNode>, 3> node3Children;
for (auto i = 1; i < 3; i++)
node3Children[i-1] = node3->children[node3->search.slot[i]].leaf;
node3Children[2] = node3->children[4].leaf;
node3Children[i-1] = node3Ref.children[node3Ref.search.slot[i]].leaf;
node3Children[2] = node3Ref.children[4].leaf;
REQUIRE(std::equal(std::begin(expectedChildren3), std::end(expectedChildren3),
std::begin(node3Children)));
}
/* ------------------------------------------------------------------ */
SECTION("Handling of underflow at a inner node by rebalance") {
auto btree = q->btree2;
std::array<persistent_ptr<wHBPTreeType2::LeafNode>, 6> l