diff --git a/index.hxx b/index.hxx index e40185c..6710743 100644 --- a/index.hxx +++ b/index.hxx @@ -7,11 +7,11 @@ namespace Hyper { namespace Core { namespace FlatTree { - size_t T0 = 0; - size_t T1 = 1; - size_t T2 = 2; - size_t T30 = 30; - size_t T31 = 30; + size_t constexpr T0 = 0; + size_t constexpr T1 = 1; + size_t constexpr T2 = 2; + size_t constexpr T30 = 30; + size_t constexpr T31 = 31; auto rightShift (size_t n) { return (n - (n & T1)) / T2; @@ -30,7 +30,7 @@ namespace Hyper { } auto twoPow (size_t n) { - if (n < T30) { + if (n < T31) { return T1 << n; } else { return ((T1 << T30) * (T1 << (n - T30))); @@ -168,7 +168,7 @@ namespace Hyper { auto parent (size_t index, size_t depth) { auto offset = FlatTree::offset(index, depth); - return FlatTree::index(depth + T1, FlatTree::offset(offset) >> T1); + return FlatTree::index(depth + T1, rightShift(offset)); } auto parent (size_t index) { @@ -339,6 +339,37 @@ namespace Hyper { this->offset = T2 * this->offset + T1; return this->index; } + + size_t nextTree () { + this->index = this->index + this->factor / T2 + T1; + this->offset = this->index / T2; + this->factor = T2; + return this->index; + } + + size_t prevTree () { + if (!static_cast(this->offset)) { + this->index = 0; + this->factor = 2; + } else { + this->index = this->index - this->factor / T2 - T1; + this->offset = this->index / T2; + this->factor = T2; + } + return this->index; + } + + size_t fullRoot (size_t index) { + if (index <= this->index || (this->index & 1) > T0) { + return false; + } + while (index > this->index + this->factor + this->factor / 2) { + this->index += this->factor / 2; + this->factor *= 2; + this->offset /= 2; + } + return true; + } }; } // namespace FlatTree } // namespace Core diff --git a/test/index.cxx b/test/index.cxx index 49728a7..3cecb40 100644 --- a/test/index.cxx +++ b/test/index.cxx @@ -3,6 +3,7 @@ #include #include #include +#include #define ASSERT(message, ...) do { \ if(!(__VA_ARGS__)) { \ @@ -18,13 +19,12 @@ int main() { namespace FlatTree = Hyper::Core::FlatTree; - int plan = 81; + int plan = 111; int count = 0; ASSERT("base blocks 0", FlatTree::index(0, 0) == 0) ASSERT("base blocks 2", FlatTree::index(0, 1) == 2) ASSERT("base blocks 4", FlatTree::index(0, 2) == 4) - ASSERT("base blocks 4", FlatTree::index(0, 2) == 4) ASSERT("parents 1", FlatTree::index(1, 0) == 1) ASSERT("parents 5", FlatTree::index(1, 1) == 5) @@ -136,13 +136,53 @@ int main() { { FlatTree::Iterator it(1); - ASSERT("iterator index == 1", it.index == 1) - ASSERT("iterator parent() == 3", it.parent() == 3) - ASSERT("iterator parent() == 7", it.parent() == 7) - ASSERT("iterator rightChild() == 11", it.rightChild() == 11) - ASSERT("iterator leftChild == 9", it.leftChild() == 9) - ASSERT("iterator next() == 13", it.next() == 13) - ASSERT("iterator leftSpan() == 12", it.leftSpan() == 12) + ASSERT("nonleaf index == 1", it.index == 1) + ASSERT("nonleaf parent() == 3", it.parent() == 3) + ASSERT("nonleaf parent() == 7", it.parent() == 7) + ASSERT("nonleaf rightChild() == 11", it.rightChild() == 11) + ASSERT("nonleaf leftChild == 9", it.leftChild() == 9) + ASSERT("nonleaf next() == 13", it.next() == 13) + ASSERT("nonleaf leftSpan() == 12", it.leftSpan() == 12) + } + + { + FlatTree::Iterator it(0); + + ASSERT("iterator fullRoot(0) == false", it.fullRoot(0) == false) + + ASSERT("iterator fullRoot(22) == true", it.fullRoot(22) == true) + ASSERT("iterator index == 7", it.index == 7) + + ASSERT("iterator nextTree() == 16", it.nextTree() == 16) + + ASSERT("iterator fullRoot(22) == true", it.fullRoot(22) == true) + ASSERT("iterator index == 17", it.index == 17) + + ASSERT("iterator nextTree() == 20", it.nextTree() == 20) + + ASSERT("iterator fullRoot(22) == true", it.fullRoot(22) == true) + ASSERT("iterator index == 20", it.index == 20) + + ASSERT("iterator nextTree() == 22", it.nextTree() == 22) + ASSERT("iterator.fullRoot(22) == false", it.fullRoot(22) == false) + } + + { + std::random_device randdev; + std::mt19937 randgen(randdev()); + for (int i = 0; i < 10; i++) { + FlatTree::Iterator it(0); + size_t tree = static_cast(std::generate_canonical(randgen) * 0xffffffff) * 2; + std::vector expected = FlatTree::fullRoots(tree); + std::vector actual; + + for (; it.fullRoot(tree); it.nextTree()) { + actual.push_back(it.index); + } + + ASSERT("big full root " << i << " actual == expected", actual == expected); + ASSERT("big full root " << i << " fullRoot(tree) == false", it.fullRoot(tree) == false); + } } ASSERT("PLAN == COUNT", plan == count)