Skip to content

Commit

Permalink
create readme
Browse files Browse the repository at this point in the history
  • Loading branch information
dnadoba committed Apr 3, 2021
1 parent 88a833e commit 06b34a6
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 5 deletions.
42 changes: 42 additions & 0 deletions Playground.playground/Contents.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import Tree

/**
`TreeNode` is a general tree data structure implementation.
Each `TreeNode` has a `Value` and 0 or more `children`.
With the help of `@resultBuilder` you can create a `TreeNode` like this:
*/

let treeNode = TreeNode("root node") {
"child 1"
"child 2"
TreeNode("child 3") {
"child of child 3"
}
"child 4"
}
print(treeNode)
// - root node
// - child 1
// - child 2
// - child 3
// - child of child 3
// - child 4

/**
`TreeList` is a list of `TreeNode`s, which enables multiple nodes to be at level 0.
In addition, `TreeList` conforms to `MutableCollection` and `BidirectionalCollection` which enables a ton of useful algorithms.
*/
let treeList = TreeList<String> {
"root 1"
"root 2"
TreeNode("root 3") {
"child of root 3"
}
"root 4"
}
print(treeList)
// - root 1
// - root 2
// - root 3
// - child of root 3
// - root 4
4 changes: 4 additions & 0 deletions Playground.playground/contents.xcplayground
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='macos' display-mode='rendered' buildActiveScheme='true' importAppTypes='true'>
<timeline fileName='timeline.xctimeline'/>
</playground>
118 changes: 116 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,117 @@
# Tree
# Tree - general tree data structure, tree diffing, NSOutlineView and SwiftUI support
## This project uses `@resultBuilder` and requires Swift 5.4 or higher (e.g. Xcode 12.5)
This package primarily includes a general tree data structure.
It also includes a tree diffing algorithm and `OutlineViewTreeDataSource` that allows to use Swift value types with `NSOutlineView`
A demo App can be found in the `Tree macOS` folder and the `NSOutlineView` Playground with support for drag and drop, undo/redo and animations.

A description of this package.
`TreeNode` and `TreeList` can also be used as a model for `OutlineGroup` in SwiftUI applications. To see it in action, take a look at the `SwiftUI-iOS` or `SwiftUI-macOS` Playground.

### `TreeNode`
`TreeNode` is a general tree data structure implementation as a value type.
Each `TreeNode` has a `value` and 0 or more `children`. It is actually just a struct which holds a value and an array of child nodes:

```swift
struct TreeNode<Value> {
var value: Value
var children: [TreeNode<Value>]
}
```
With the help of `@resultBuilder` you can create a `TreeNode` like this:

```swift
let treeNode = TreeNode("root node") {
"child 1"
"child 2"
TreeNode("child 3") {
"child of child 3"
}
"child 4"
}
print(treeNode)
// - root node
// - child 1
// - child 2
// - child 3
// - child of child 3
// - child 4
```
### `TreeList` - a list of `TreeNode`s
`TreeList` is a list of `TreeNode`s, which enables multiple nodes to be at level 0.
In addition, `TreeList` conforms to `MutableCollection` and `BidirectionalCollection` which enables a ton of useful algorithms.

```swift
let treeList = TreeList<String> {
"root 1"
"root 2"
TreeNode("root 3") {
"child of root 3"
}
"root 4"
}
print(treeList)
// - root 1
// - root 2
// - root 3
// - child of root 3
// - root 4
```
### additional methods
`TreeNode` and `TreeList` have a similar API.
They both support special map, compactMap and filter operations:

```swift
extension TreeNode {
func mapValues<NewValue>(_ transform: (Value) -> NewValue) -> TreeNode<NewValue>
func mapValuesWithNode<NewValue>(_ transform: (TreeNode<Value>) -> NewValue) -> TreeNode<NewValue>
func mapValuesWithParents<NewValue>(_ transform: ([Value], Value) -> NewValue) -> TreeNode<NewValue>
func mapChildrenWithParents<NewValue>(_ transform: ([Value], [Value]) -> NewValue) -> [NewValue]

func compactMapValues<NewValue>(_ transform: (Value) -> NewValue?) -> TreeNode<NewValue>?

func filterValues(_ isIncluded: (Value) -> Bool) -> TreeNode<Value>
}
```

In addition, they support moving nodes which is useful for implementing drag and drop:

```swift
extension TreeList where Value : Hashable {
/// Moves the TreeNodes at the given `sourceIndices` to `insertIndex`.
/// The `sourceIndices` and `insertIndex` are both specified in the before state of the tree.
/// If elements are removed before the `insertIndex`, the `insertIndex` will be adjusted.
///
/// The move operation will fail and return nil, if the `insertIndex` is a child of one of the moved TreeNodes.
/// - Parameters:
/// - sourceIndices: the indices of the elements that should be moved
/// - insertIndex: the insertion index to move the elements to
/// - Returns: A new Tree with the specified changes or nil if the the move was not possible
public func move(indices sourceIndices: [TreeIndex], to insertIndex: TreeIndex) -> TreeList<Value>?
}
```

### `NSOutlineView`
`TreeList` and `TreeNode` were originaly created to be used as data model for NSOutlineView. Therefore, this package includes a tree diffing algorithm and `OutlineViewTreeDataSource` that allows to use Swift value types with `NSOutlineView`. Take a look at NSOutlineView Playground or the Tree macOS example Xcode project which are part of this repository.
The diffing algorithm can also be used to efficiently send only what has changed over the network to another peer/server.


### SwiftUI
`TreeNode` and `TreeList` can be used with SwiftUI as well.

```swift
import SwiftUI
extension TreeNode {
var optionalChildren: [TreeNode<Value>]? {
children.isEmpty ? nil : children
}
}
struct ContentView: View {
@State var tree: TreeList<String>

var body: some View {
List(tree.nodes, id: \.value, children: \.optionalChildren) { node in
Text(node.value)
}
}
}
```
For a full example take a look into the SwiftUI-iOS or SwiftUI-macOS Playground.
14 changes: 11 additions & 3 deletions Sources/Tree/Tree.swift
Original file line number Diff line number Diff line change
Expand Up @@ -308,10 +308,18 @@ extension TreeList {
}
}

extension TreeList: CustomDebugStringConvertible where Value: CustomDebugStringConvertible {
public var debugDescription: String {
extension TreeNode: CustomStringConvertible where Value: CustomStringConvertible {
public var description: String {
return mapValuesWithParents({ parents, value -> String in
repeatElement(" ", count: parents.count).joined() + "- \(value.description)"
}).map(\.value).joined(separator: "\n")
}
}

extension TreeList: CustomStringConvertible where Value: CustomStringConvertible {
public var description: String {
return mapValuesWithParents({ parents, value -> String in
repeatElement(" ", count: parents.count).joined() + "- \(value.debugDescription)"
repeatElement(" ", count: parents.count).joined() + "- \(value.description)"
}).map(\.value).joined(separator: "\n")
}
}
Expand Down

0 comments on commit 06b34a6

Please sign in to comment.