diff --git a/src/radix.h b/src/radix.h --- a/src/radix.h +++ b/src/radix.h @@ -138,9 +138,9 @@ return RCUPtr::acquire(ptr); } - template void forEachLeaf(Callable &&func) const { + template bool forEachLeaf(Callable &&func) const { RCULock lock; - forEachLeaf(root.load(), std::move(func)); + return forEachLeaf(root.load(), std::move(func)); } #define SEEK_LEAF_LOOP() \ @@ -250,19 +250,20 @@ #undef SEEK_LEAF_LOOP template - void forEachLeaf(RadixElement e, Callable &&func) const { - if (e.isNode()) { - e.getNode()->forEachChild( - [&](const std::atomic *pElement) { - forEachLeaf(pElement->load(), func); - }); - return; - } + bool forEachLeaf(RadixElement e, Callable &&func) const { + if (e.isLeaf()) { + T *leaf = e.getLeaf(); + if (leaf != nullptr) { + return func(RCUPtr::copy(leaf)); + } - T *leaf = e.getLeaf(); - if (leaf != nullptr) { - func(RCUPtr::copy(leaf)); + return true; } + + return e.getNode()->forEachChild( + [&](const std::atomic *pElement) { + return forEachLeaf(pElement->load(), func); + }); } struct RadixElement { @@ -374,10 +375,13 @@ bool isShared() const { return refcount > 0; } - template void forEachChild(Callable &&func) const { + template bool forEachChild(Callable &&func) const { for (size_t i = 0; i < CHILD_PER_LEVEL; i++) { - func(&children[i]); + if (!func(&children[i])) { + return false; + } } + return true; } }; diff --git a/src/test/radix_tests.cpp b/src/test/radix_tests.cpp --- a/src/test/radix_tests.cpp +++ b/src/test/radix_tests.cpp @@ -502,14 +502,31 @@ // Check the tree is traversed in ascending key order size_t count = 0; - mytree.forEachLeaf([&](RCUPtr ptr) { + bool ret = mytree.forEachLeaf([&](RCUPtr ptr) { // This test assumes the key is equal to the value BOOST_CHECK_EQUAL(ptr->getId(), count); BOOST_CHECK_EQUAL(ptr, elements[count++]); + + return true; }); // All the elements are parsed BOOST_CHECK_EQUAL(count, ELEMENTS); + BOOST_CHECK(ret); + + // Check we can stop the traversal when needed + const size_t stopCount = ELEMENTS / 2; + count = 0; + ret = mytree.forEachLeaf([&](RCUPtr ptr) { + // This test assumes the key is equal to the value + BOOST_CHECK_EQUAL(ptr->getId(), count); + BOOST_CHECK_EQUAL(ptr, elements[count++]); + + return count < stopCount; + }); + + BOOST_CHECK_EQUAL(count, stopCount); + BOOST_CHECK(!ret); } BOOST_AUTO_TEST_CASE(uint256_key_wrapper) {