mirror of
https://github.com/AdrianKuta/Tree-Data-Structure.git
synced 2026-06-19 19:00:14 +02:00
4.5 KiB
4.5 KiB
Design — four additive enhancements to tree-structure (target 4.1.0)
Date: 2026-06-07. Source issues: #34, #35, #36, #33. Integration: four separate PRs,
one per issue (Closes #NN), matching the repo's per-issue PR convention (#32).
Shared rules (every issue)
explicitApi()is on everywhere → every new public declaration ispublicwith KDoc.- New tests live in
commonTest, usekotlin("test"), and mirror the existing test style (TreeNodeV4Test.kt,TreeNodeNavigationTest.kt, …). - Add a bullet to
CHANGELOG.mdunder## [Unreleased]→### Added(do not bumpPUBLISH_VERSION; releases are a separate manual step). - Regenerate the binary-compatibility baseline with
./gradlew apiDump; verify withapiCheck. - Do not modify the core public surface in a breaking way — these are additive only.
#34 — Structural mutation helpers → members on TreeNode
Members (not extensions) because they need the private _children/_parent and the cycle/parent
validation.
- Extract the existing inline validation from
addChildinto a privatevalidateAttachable(child)and reuse it. insertChild(index: Int, child)— validated insert at index (bounds0.._children.size).removeChildAt(index: Int): TreeNode<T>— remove and return the detached child.replaceChild(index: Int, child): TreeNode<T>— swap, return the old (now detached) child.moveChild(child, toIndex): Boolean— reorder an existing direct child; no re-parent/cycle check needed (it is already a child);falseifchildis not a direct child.addChildren(vararg children)— validated append of several (per-childaddChildsemantics).sortChildren(comparator: Comparator<TreeNode<T>>)— stable in-place reorder.
#35 — Query algorithms → extensions in new TreeNodeQueryExt.kt
Built on the public API (ancestors(), parent, depth(), sequences). Return null when the
two nodes are unrelated (different trees).
lowestCommonAncestor(other): TreeNode<T>?— deepest common node; includes self/other as candidates (LCA(a, a) == a,LCA(a, descendantOfA) == a).distance(other): Int?—depth(this) + depth(other) - 2 * depth(lca).pathBetween(other): List<TreeNode<T>>?—[this … lca … other].contains(value): Boolean— value search over the subtree, including the receiver.
Document complexity (parent-walk based; O(depth) for LCA/distance, O(n) for contains).
#36 — Customizable prettyString() → extension in new TreeNodePrettyPrintExt.kt
data class TreeConnectors(branch, lastBranch, vertical, empty)with acompanion:Default(current Unicode box-drawing) andAscii.fun TreeNode<T>.prettyString(connectors = TreeConnectors.Default, render: (value: T, depth: Int, isLast: Boolean) -> String = { v, _, _ -> v.toString() }): String.- The no-arg member
prettyString()is unchanged; member resolution wins fornode.prettyString(), so existing behaviour and output are byte-for-byte identical.
#33 — Immutable variant → new module :tree-structure-immutable
Largest item; fully isolated from the other three except for settings.gradle.kts,
libs.versions.toml, the root build.gradle.kts Dokka aggregation block, and CHANGELOG.md.
settings.gradle.kts:include(":tree-structure-immutable").- New
build.gradle.ktsmirroring the serialization module's KMP target matrix; depsapi(project(":"))+kotlinx-collections-immutable. libs.versions.toml: addkotlinx-collections-immutable(a recent stable, e.g. 0.3.8) and wire it.- Root
build.gradle.kts: adddokka(project(":tree-structure-immutable"))to the aggregation. ImmutableTreeNode<T>backed bypersistentListOfchildren;addChild/removeChild/mapValuesreturn a new root with unchanged subtrees structurally shared. Mirror pre/post/ level-order traversal helpers.- Its own
tree-structure-immutable/api/baseline viaapiDump.
Orchestration
- Four git worktrees off
origin/master, one branch each (feat/...), for full isolation — no collisions onTreeNode.kt,api/*.api, orCHANGELOG.md. - A workflow pipelines each issue: implement (code + KDoc + tests + CHANGELOG +
apiDump) and verify locally (jvmTest+apiCheck), then an adversarial reviewer checks issue-conformance, test quality, invariants, explicit API,.apifreshness, and that it builds. Local checks are JVM-only for speed; CI validates the full KMP matrix on each PR. - Then push each passing branch and open a PR (
Closes #NN); remove the worktrees afterward.