Skip to content

Commit 3e8bada

Browse files
authored
Merge pull request #29 from rafaelkallis/copilot/recreate-pr-26-with-coauthor
Fix node_16::grow() missing 128 offset in node_48 index population
2 parents 99db793 + 69f0471 commit 3e8bada

File tree

3 files changed

+87
-1
lines changed

3 files changed

+87
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ cmake-build-debug
1010
.idea
1111
*.log
1212
_codeql_build_dir/
13+
_codeql_detected_source_root

include/art/node_16.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ template <class T> inner_node<T> *node_16<T>::grow() {
115115
new_node->n_children_ = this->n_children_;
116116
std::copy(this->children_, this->children_ + this->n_children_, new_node->children_);
117117
for (int i = 0; i < n_children_; ++i) {
118-
new_node->indexes_[(uint8_t) this->keys_[i]] = i;
118+
new_node->indexes_[128 + (uint8_t) this->keys_[i]] = i;
119119
}
120120
delete this;
121121
return new_node;

test/node_16.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,4 +236,89 @@ TEST_SUITE("node 16") {
236236
REQUIRE_THROWS_AS(n.prev_partial_key(0), std::out_of_range);
237237
}
238238
}
239+
240+
TEST_CASE("grow to node_48 preserves offset (PR #20)") {
241+
// This test reproduces the bug reported in PR #20:
242+
// When node_16 grows to node_48, the indexes_ array must use 128 offset
243+
244+
SUBCASE("next_partial_key after grow") {
245+
leaf_node<void*>* dummy_children[17];
246+
for (int i = 0; i < 17; ++i) {
247+
dummy_children[i] = new leaf_node<void*>(nullptr);
248+
}
249+
node_16<void*>* n16 = new node_16<void*>();
250+
char test_keys[17];
251+
for (int i = 0; i < 17; ++i) {
252+
test_keys[i] = 'a' + i; // a, b, c, ..., q
253+
}
254+
for (int i = 0; i < 16; ++i) {
255+
n16->set_child(test_keys[i], dummy_children[i]);
256+
}
257+
REQUIRE(n16->is_full());
258+
auto* n48 = static_cast<node_48<void*>*>(n16->grow());
259+
REQUIRE(n48 != nullptr);
260+
for (int i = 0; i < 16; ++i) {
261+
auto** child_ptr = n48->find_child(test_keys[i]);
262+
REQUIRE(child_ptr != nullptr);
263+
REQUIRE(*child_ptr == dummy_children[i]);
264+
}
265+
n48->set_child(test_keys[16], dummy_children[16]);
266+
for (int i = 0; i < 17; ++i) {
267+
auto** child_ptr = n48->find_child(test_keys[i]);
268+
REQUIRE(child_ptr != nullptr);
269+
REQUIRE(*child_ptr == dummy_children[i]);
270+
}
271+
// Starting from first key 'a', we should find all keys in order
272+
char current = n48->next_partial_key('a');
273+
REQUIRE_EQ('a', current);
274+
for (int i = 1; i < 17; ++i) {
275+
current = n48->next_partial_key(current + 1);
276+
REQUIRE_EQ(test_keys[i], current);
277+
}
278+
delete n48;
279+
for (int i = 0; i < 17; ++i) {
280+
delete dummy_children[i];
281+
}
282+
}
283+
284+
SUBCASE("prev_partial_key after grow") {
285+
leaf_node<void*>* dummy_children[17];
286+
for (int i = 0; i < 17; ++i) {
287+
dummy_children[i] = new leaf_node<void*>(nullptr);
288+
}
289+
node_16<void*>* n16 = new node_16<void*>();
290+
char test_keys[17];
291+
for (int i = 0; i < 17; ++i) {
292+
test_keys[i] = 'a' + i; // a, b, c, ..., q
293+
}
294+
for (int i = 0; i < 16; ++i) {
295+
n16->set_child(test_keys[i], dummy_children[i]);
296+
}
297+
REQUIRE(n16->is_full());
298+
auto* n48 = static_cast<node_48<void*>*>(n16->grow());
299+
REQUIRE(n48 != nullptr);
300+
for (int i = 0; i < 16; ++i) {
301+
auto** child_ptr = n48->find_child(test_keys[i]);
302+
REQUIRE(child_ptr != nullptr);
303+
REQUIRE(*child_ptr == dummy_children[i]);
304+
}
305+
n48->set_child(test_keys[16], dummy_children[16]);
306+
for (int i = 0; i < 17; ++i) {
307+
auto** child_ptr = n48->find_child(test_keys[i]);
308+
REQUIRE(child_ptr != nullptr);
309+
REQUIRE(*child_ptr == dummy_children[i]);
310+
}
311+
// Starting from last key 'q', we should find all keys in reverse order
312+
char current = n48->prev_partial_key('q');
313+
REQUIRE_EQ('q', current);
314+
for (int i = 15; i >= 0; --i) {
315+
current = n48->prev_partial_key(current - 1);
316+
REQUIRE_EQ(test_keys[i], current);
317+
}
318+
delete n48;
319+
for (int i = 0; i < 17; ++i) {
320+
delete dummy_children[i];
321+
}
322+
}
323+
}
239324
}

0 commit comments

Comments
 (0)