From 0ec64a4aa7e3be1cca31af4b87c7fee80ffc4e88 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 10 May 2025 08:41:53 -0500 Subject: [PATCH] Implement `previous()` method for reverse tree traversal --- src/lib/data_structures/publication_tree.ts | 79 ++++++++++++++++++++- 1 file changed, 76 insertions(+), 3 deletions(-) diff --git a/src/lib/data_structures/publication_tree.ts b/src/lib/data_structures/publication_tree.ts index f0ecbb6..de2c04c 100644 --- a/src/lib/data_structures/publication_tree.ts +++ b/src/lib/data_structures/publication_tree.ts @@ -229,6 +229,24 @@ export class PublicationTree implements AsyncIterable { return true; } + async tryMoveToLastChild(): Promise { + if (!this.target) { + console.debug("Cursor: Target node is null or undefined."); + return false; + } + + if (this.target.type === PublicationTreeNodeType.Leaf) { + return false; + } + + if (this.target.children == null || this.target.children.length === 0) { + return false; + } + + this.target = await this.target.children?.at(-1)?.value(); + return true; + } + async tryMoveToNextSibling(): Promise { if (!this.target) { console.debug("Cursor: Target node is null or undefined."); @@ -253,9 +271,35 @@ export class PublicationTree implements AsyncIterable { return false; } - const nextSibling = (await siblings.at(currentIndex + 1)?.value()); - this.target = nextSibling; + this.target = await siblings.at(currentIndex + 1)?.value(); + return true; + } + + async tryMoveToPreviousSibling(): Promise { + if (!this.target) { + console.debug("Cursor: Target node is null or undefined."); + return false; + } + + const parent = this.target.parent; + const siblings = parent?.children; + if (!siblings) { + return false; + } + + const currentIndex = await siblings.findIndexAsync( + async (sibling: Lazy) => (await sibling.value())?.address === this.target!.address + ); + if (currentIndex === -1) { + return false; + } + + if (currentIndex <= 0) { + return false; + } + + this.target = await siblings.at(currentIndex - 1)?.value(); return true; } @@ -283,9 +327,14 @@ export class PublicationTree implements AsyncIterable { return this; } + // TODO: Add `previous()` method. + async next(): Promise> { if (!this.#cursor.target) { - await this.#cursor.tryMoveTo(this.#bookmark); + if (await this.#cursor.tryMoveTo(this.#bookmark)) { + const event = await this.getEvent(this.#cursor.target!.address); + return { done: false, value: event }; + } } // Based on Raymond Chen's tree traversal algorithm. @@ -306,6 +355,30 @@ export class PublicationTree implements AsyncIterable { return { done: true, value: null }; } + async previous(): Promise> { + if (!this.#cursor.target) { + if (await this.#cursor.tryMoveTo(this.#bookmark)) { + const event = await this.getEvent(this.#cursor.target!.address); + return { done: false, value: event }; + } + } + + // Based on Raymond Chen's tree traversal algorithm. + // https://devblogs.microsoft.com/oldnewthing/20200106-00/?p=103300 + do { + if (await this.#cursor.tryMoveToPreviousSibling()) { + while (await this.#cursor.tryMoveToLastChild()) { + continue; + } + + const event = await this.getEvent(this.#cursor.target!.address); + return { done: false, value: event }; + } + } while (this.#cursor.tryMoveToParent()); + + return { done: true, value: null }; + } + // #endregion // #region Private Methods