Implement Iterator

This commit is contained in:
2024-05-08 16:54:36 -07:00
parent e2dde59d19
commit 4482f93895
2 changed files with 197 additions and 7 deletions

View File

@@ -400,7 +400,7 @@ struct VersionedMap::Impl {
if (finger.backNode() != 0 &&
(c = child<kOrder>(finger.backNode(), direction, at)) != 0) {
finger.push(c, direction);
while (auto c = child<kOrder>(finger.backNode(), !direction, at) != 0) {
while ((c = child<kOrder>(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<std::memory_order_acquire>(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<std::memory_order_acquire>(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<std::memory_order_relaxed>(
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;