#pragma once #include "VersionedMap.h" #include #include #include using String = std::basic_string; struct Facade { explicit Facade(int64_t version) : versioned{version} {} struct View { std::vector> rangeRead(const String &begin, const String &end, int limit, bool reverse) const { std::vector> result; if (begin >= end) { return result; } weaselab::VersionedMap::Iterator versionedIter[2]; const weaselab::VersionedMap::Key key[] = { {begin.data(), int(begin.size())}, {end.data(), int(end.size())}}; const int64_t v[] = {version, version}; facade->versioned.firstGeq(key, v, versionedIter, 2); if (versionedIter[0] == versionedIter[1]) { // No mutations intersect [begin, end) facade->unversionedRead(begin, end, limit, reverse, result); return result; } // Make sure versionedIter[1] param1 is >= `end` if (versionedIter[1] != facade->versioned.end(version)) { auto m = *versionedIter[1]; if (String(m.param1, m.param1Len) < end) { ++versionedIter[1]; } } static const uint8_t zero_[] = {0}; static const String zero{zero_, 1}; if (reverse) { weaselab::VersionedMap::Iterator iter = versionedIter[1]; weaselab::VersionedMap::Iterator endIter = versionedIter[0]; String readUntil = end; do { --iter; auto m = *iter; const auto mBegin = String(m.param1, m.param1Len); const auto mEnd = m.type == weaselab::VersionedMap::Set || m.param2Len == 0 ? String(m.param1, m.param1Len) + zero : String(m.param2, m.param2Len); facade->unversionedRead(mEnd, readUntil, limit, true, result); if (limit == 0) { return result; } switch (m.type) { case weaselab::VersionedMap::Set: { result.emplace_back(mBegin, String(m.param2, m.param2Len)); --limit; if (limit == 0) { return result; } readUntil = mBegin; } break; case weaselab::VersionedMap::Clear: readUntil = mBegin; break; } } while (iter != endIter); facade->unversionedRead(begin, readUntil, limit, true, result); return result; } else { String readFrom = begin; for (auto iter = versionedIter[0]; iter != versionedIter[1]; ++iter) { auto m = *iter; const auto mBegin = String(m.param1, m.param1Len); const auto mEnd = m.type == weaselab::VersionedMap::Set || m.param2Len == 0 ? String(m.param1, m.param1Len) + zero : String(m.param2, m.param2Len); facade->unversionedRead(readFrom, mBegin, limit, false, result); if (limit == 0) { return result; } switch (m.type) { case weaselab::VersionedMap::Set: { result.emplace_back(mBegin, String(m.param2, m.param2Len)); --limit; if (limit == 0) { return result; } readFrom = mEnd; } break; case weaselab::VersionedMap::Clear: readFrom = mEnd; break; } } facade->unversionedRead(readFrom, end, limit, false, result); return result; } } /** @private */ View(const Facade *facade, int64_t version) : facade{facade}, version{version} {} private: const Facade *facade; int64_t version; }; void addMutations(const weaselab::VersionedMap::Mutation *mutations, int numMutations, int64_t version) { versioned.addMutations(mutations, numMutations, version); } void setOldestVersion(int64_t version) { for (auto iter = versioned.begin(version), end = versioned.end(version); iter != end; ++iter) { auto m = *iter; switch (m.type) { case weaselab::VersionedMap::Set: unversioned[String(m.param1, m.param1Len)] = String(m.param2, m.param2Len); break; case weaselab::VersionedMap::Clear: for (auto unversionedIter = unversioned.lower_bound(String(m.param1, m.param1Len)); unversionedIter != unversioned.end() && unversionedIter->first < String(m.param2, m.param2Len);) { unversionedIter = unversioned.erase(unversionedIter); } break; } } versioned.setOldestVersion(version); } View viewAt(int64_t version) const { return View{this, version}; } int64_t getVersion() const { return versioned.getVersion(); } int64_t getOldestVersion() const { return versioned.getOldestVersion(); } void unversionedRead(const String &begin, const String &end, int &limit, bool reverse, std::vector> &result) const { if (begin >= end) { return; } if (reverse) { auto iter = unversioned.lower_bound(end); const auto beginIter = unversioned.begin(); if (iter == beginIter) { return; } --iter; for (; iter->first >= begin && limit > 0; --iter) { result.push_back(*iter); --limit; if (iter == beginIter) { return; } } } else { for (auto iter = unversioned.lower_bound(begin), iterEnd = unversioned.lower_bound(end); iter != iterEnd && limit > 0; ++iter) { result.push_back(*iter); --limit; } } } std::map unversioned; weaselab::VersionedMap versioned; };