diff --git a/VersionedMap.cpp b/VersionedMap.cpp index 1f77aab..87c36df 100644 --- a/VersionedMap.cpp +++ b/VersionedMap.cpp @@ -400,7 +400,7 @@ struct VersionedMap::Impl { if (finger.backNode() != 0 && (c = child(finger.backNode(), direction, at)) != 0) { finger.push(c, direction); - while (auto c = child(finger.backNode(), !direction, at) != 0) { + while ((c = child(finger.backNode(), !direction, at)) != 0) { finger.push(c, !direction); } } else { @@ -755,6 +755,159 @@ void VersionedMap::addMutations(const Mutation *mutations, int numMutations, impl->addMutations(mutations, numMutations, version); } +struct VersionedMap::Iterator::Impl { + Finger finger; + int64_t version; + VersionedMap::Impl *map; + int cmp; + bool materializeClearEndingHere = false; +}; + +VersionedMap::Iterator::~Iterator() { + if (impl != nullptr) { + impl->~Impl(); + free(impl); + } +} + +VersionedMap::Iterator::Iterator(const Iterator &other) + : impl(new(malloc(sizeof(Impl))) Impl(*other.impl)) {} + +VersionedMap::Iterator & +VersionedMap::Iterator::operator=(const Iterator &other) { + if (impl != nullptr) { + impl->~Impl(); + free(impl); + } + impl = new (malloc(sizeof(Impl))) Impl(*other.impl); + return *this; +} + +VersionedMap::Iterator::Iterator(Iterator &&other) noexcept + : impl(std::exchange(other.impl, nullptr)) {} + +VersionedMap::Iterator & +VersionedMap::Iterator::operator=(Iterator &&other) noexcept { + if (impl != nullptr) { + impl->~Impl(); + free(impl); + } + impl = std::exchange(other.impl, nullptr); + return *this; +} + +VersionedMap::Mutation VersionedMap::Iterator::operator*() const { + assert(impl->finger.backNode() != 0); + assert(impl->finger.searchPathSize() != 0); + const auto &entry = *impl->map->mm.base[impl->finger.backNode()].entry; + if (impl->materializeClearEndingHere) { + assert(entry.clearTo); + auto prev = *this; + --prev; + const auto &prevEntry = + *prev.impl->map->mm.base[prev.impl->finger.backNode()].entry; + return {prevEntry.getKey(), entry.getKey(), prevEntry.keyLen + 1, + entry.keyLen, Clear}; + } + if (entry.valLen >= 0) { + return {entry.getKey(), entry.getVal(), entry.keyLen, entry.valLen, Set}; + } else { + return {entry.getKey(), nullptr, entry.keyLen, -1, Clear}; + } +} + +VersionedMap::Iterator &VersionedMap::Iterator::operator++() { + const auto &entry = *impl->map->mm.base[impl->finger.backNode()].entry; + if (impl->materializeClearEndingHere) { + assert(entry.clearTo); + impl->materializeClearEndingHere = false; + return *this; + } + + impl->map->move(impl->finger, impl->version, true); + impl->materializeClearEndingHere = + impl->finger.searchPathSize() > 0 && + impl->map->mm.base[impl->finger.backNode()].entry->clearTo; + + return *this; +} + +VersionedMap::Iterator VersionedMap::Iterator::operator++(int) { + auto result = *this; + ++*this; + return result; +} + +VersionedMap::Iterator &VersionedMap::Iterator::operator--() { + const auto &entry = *impl->map->mm.base[impl->finger.backNode()].entry; + if (entry.clearTo && !impl->materializeClearEndingHere) { + impl->materializeClearEndingHere = true; + return *this; + } + + impl->map->move(impl->finger, impl->version, + false); + impl->materializeClearEndingHere = false; + return *this; +} + +VersionedMap::Iterator VersionedMap::Iterator::operator--(int) { + auto result = *this; + --*this; + return result; +} + +bool VersionedMap::Iterator::operator==(const Iterator &other) const { + assert(impl->map == other.impl->map); + assert(impl->version == other.impl->version); + if (impl->finger.searchPathSize() == 0 || + other.impl->finger.searchPathSize() == 0) { + return impl->finger.searchPathSize() == other.impl->finger.searchPathSize(); + } + return impl->finger.backNode() == other.impl->finger.backNode() && + impl->materializeClearEndingHere == + other.impl->materializeClearEndingHere; +} + +bool VersionedMap::Iterator::operator!=(const Iterator &other) const { + return !(*this == other); +} + +int VersionedMap::Iterator::cmp() const { return impl->cmp; } + +VersionedMap::Iterator VersionedMap::begin(int64_t version) const { + VersionedMap::Iterator result; + result.impl = new (malloc(sizeof(Iterator::Impl))) Iterator::Impl(); + result.impl->cmp = 1; + + bool ignored; + result.impl->finger.push( + impl->roots.getThreadSafeHandle().rootForVersion(version), ignored); + if (result.impl->finger.backNode() == 0) { + result.impl->finger.pop(); + } else { + uint32_t c; + while ((c = impl->child( + result.impl->finger.backNode(), false, version)) != 0) { + result.impl->finger.push(c, false); + } + } + result.impl->map = impl; + result.impl->materializeClearEndingHere = false; + result.impl->version = version; + return result; +} + +VersionedMap::Iterator VersionedMap::end(int64_t version) const { + VersionedMap::Iterator result; + result.impl = new (malloc(sizeof(Iterator::Impl))) Iterator::Impl(); + result.impl->cmp = 1; + result.impl->map = impl; + result.impl->materializeClearEndingHere = false; + result.impl->version = version; + return result; +} + // ==================== END IMPLEMENTATION ==================== // GCOVR_EXCL_START @@ -791,6 +944,12 @@ void VersionedMap::Impl::printInOrderHelper(int64_t version, uint32_t node, depth + 1); } +VersionedMap::Impl *cast(const VersionedMap &m) { + VersionedMap::Impl *result; + memcpy(&result, &m, sizeof(void *)); + return result; +} + } // namespace weaselab #ifdef ENABLE_MAIN @@ -798,7 +957,7 @@ void VersionedMap::Impl::printInOrderHelper(int64_t version, uint32_t node, int main() { { - weaselab::VersionedMap::Impl impl; + weaselab::VersionedMap versionedMap{0}; { weaselab::VersionedMap::Mutation m[] = { {(const uint8_t *)"a", nullptr, 1, 0, weaselab::VersionedMap::Set}, @@ -808,23 +967,53 @@ int main() { {(const uint8_t *)"e", nullptr, 1, 0, weaselab::VersionedMap::Set}, {(const uint8_t *)"f", nullptr, 1, 0, weaselab::VersionedMap::Set}, }; - impl.addMutations(m, sizeof(m) / sizeof(m[0]), 1); + versionedMap.addMutations(m, sizeof(m) / sizeof(m[0]), 1); } { weaselab::VersionedMap::Mutation m[] = { {(const uint8_t *)"a", (const uint8_t *)"d", 1, 1, weaselab::VersionedMap::Clear}, }; - impl.addMutations(m, sizeof(m) / sizeof(m[0]), 2); + versionedMap.addMutations(m, sizeof(m) / sizeof(m[0]), 2); } { weaselab::VersionedMap::Mutation m[] = { {(const uint8_t *)"b", (const uint8_t *)"", 1, 0, weaselab::VersionedMap::Clear}, }; - impl.addMutations(m, sizeof(m) / sizeof(m[0]), 3); + versionedMap.addMutations(m, sizeof(m) / sizeof(m[0]), 3); + } + cast(versionedMap)->printInOrder(3); + for (auto iter = versionedMap.begin(3), end = versionedMap.end(3); + iter != end; ++iter) { + const auto &m = *iter; + switch (m.type) { + case weaselab::VersionedMap::Set: + printf("set "); + for (int i = 0; i < m.param1Len; ++i) { + printf("x%02x", m.param1[i]); + } + printf(" -> "); + for (int i = 0; i < m.param2Len; ++i) { + printf("x%02x", m.param2[i]); + } + printf("\n"); + break; + case weaselab::VersionedMap::Clear: + printf("clear ["); + for (int i = 0; i < m.param1Len; ++i) { + printf("x%02x", m.param1[i]); + } + printf(", "); + for (int i = 0; i < m.param2Len; ++i) { + printf("x%02x", m.param2[i]); + } + printf(")\n"); + break; + default: // GCOVR_EXCL_LINE + __builtin_unreachable(); // GCOVR_EXCL_LINE + } } - impl.printInOrder(3); } return 0; diff --git a/include/VersionedMap.h b/include/VersionedMap.h index 0c41155..3db8c84 100644 --- a/include/VersionedMap.h +++ b/include/VersionedMap.h @@ -135,6 +135,7 @@ struct VersionedMap { struct Impl; private: + friend struct VersionedMap; Impl *impl = nullptr; }; @@ -156,7 +157,7 @@ struct VersionedMap { Iterator begin(int64_t version) const; /** The "past-the-end" iterator. */ - Iterator end() const; + Iterator end(int64_t version) const; /** Returns the memory usage in bytes. */ int64_t getBytes() const;