Class Cursor<T>
A Cursor<T> is a mutable view of a location in a T
-structure,
allowing efficient access to (and editing of) a node and its parent, siblings, and immediate children.
You can think of a Cursor<T> as being focused on a particular node. After zooming in on a node, you can efficiently go up to the node's parent, down to the node's first child, or left or right to the node's immediate siblings.
Cursor<T> is generally not as efficient or useful as the SelfAndDescendantsInContext<T>(IRewriter<T>, T) family for replacing single nodes, but it efficiently supports longer sequences of edits to a location and its neighbours.
Inherited Members
Namespace: Sawmill
Assembly: Sawmill.dll
Syntax
public sealed class Cursor<T>
Type Parameters
Name | Description |
---|---|
T |
Examples
Here we traverse to, and replace, the right child of a binary node.
Expr expr = new Add(new Lit(1), new Neg(new Lit(2)));
var cursor = expr.Cursor();
cursor.Down();
cursor.Right();
Assert.Equal(new Neg(new Lit(2)), cursor.Focus);
cursor.Focus = new Lit(10);
cursor.Top();
Assert.Equal(new Add(new Lit(1), new Lit(10)), cursor.Focus);
Properties
| Improve this Doc View SourceFocus
Gets or sets the current focus of the Cursor<T>
Declaration
public T Focus { get; set; }
Property Value
Type | Description |
---|---|
T | The current focus of the Cursor<T> |
Methods
| Improve this Doc View SourceBottom()
Move the current Focus to the bottom-left of the tree. Do nothing if the current Focus has no children.
Declaration
public void Bottom()
Down()
Focus the Cursor<T> on the current Focus's first child.
This operation "opens a hole" in the current node, descending to the children so you can replace them one at a time.
Declaration
public void Down()
Exceptions
Type | Condition |
---|---|
InvalidOperationException | The current Focus's has no children. |
Down(Int32)
Go Down() count
times.
This operation "opens a hole" in the current node and its count
first descendants.
Declaration
public void Down(int count)
Parameters
Type | Name | Description |
---|---|---|
Int32 | count |
Exceptions
Type | Condition |
---|---|
InvalidOperationException | The Cursor<T> reached a node with no children. The Cursor<T> is left in the last good state, that is, at the bottom of the tree. |
ArgumentOutOfRangeException |
|
DownWhile(Func<T, Boolean>)
Go Down() as long as predicate
returns true for the current Focus.
In other words, find the first leftmost descendant of Focus (including itself) which does not satisfy predicate
.
Declaration
public void DownWhile(Func<T, bool> predicate)
Parameters
Type | Name | Description |
---|---|---|
Func<T, Boolean> | predicate | The predicate to invoke on the current focus and its leftmost descendants |
Exceptions
Type | Condition |
---|---|
InvalidOperationException | The Cursor<T> reached the root node. The Cursor<T> is left in the last good state, that is, at the bottom of the tree. |
Follow(IEnumerable<Direction>)
Follow a path.
Declaration
public void Follow(IEnumerable<Direction> path)
Parameters
Type | Name | Description |
---|---|---|
IEnumerable<Direction> | path | The path to follow |
Exceptions
Type | Condition |
---|---|
InvalidOperationException | Thrown when path leads off the edge of the tree. The Cursor<T> is left in the last known good state. |
GetPath()
Yields a sequence of Directions describing how to get from the Top() of the tree to the current Focus. The resulting path can be Follow(IEnumerable<Direction>)ed by a Cursor<T>. This is useful if, for example, you need to compare the nodes at a given position in two different trees.
Declaration
public IEnumerable<Direction> GetPath()
Returns
Type | Description |
---|---|
IEnumerable<Direction> | A sequence of Directions |
Left()
Declaration
public void Left()
Exceptions
Type | Condition |
---|---|
InvalidOperationException | The Cursor<T> is already focused on the leftmost sibling |
Left(Int32)
Go Left() count
times.
Declaration
public void Left(int count)
Parameters
Type | Name | Description |
---|---|---|
Int32 | count |
Exceptions
Type | Condition |
---|---|
InvalidOperationException | The Cursor<T> reached the leftmost sibling. The Cursor<T> is left in the last good state, that is, focused on the leftmost sibling. |
ArgumentOutOfRangeException |
|
Leftmost()
Focus the Cursor<T> on the current Focus's leftmost sibling. Do nothing if the Cursor<T> is already focused on the leftmost sibling.
Declaration
public void Leftmost()
LeftWhile(Func<T, Boolean>)
Go Left() as long as predicate
returns true for the current Focus.
In other words, find the first left sibling of Focus (including itself) which does not satisfy predicate
.
Declaration
public void LeftWhile(Func<T, bool> predicate)
Parameters
Type | Name | Description |
---|---|---|
Func<T, Boolean> | predicate | The predicate to invoke on the current focus and its ancestors |
Exceptions
Type | Condition |
---|---|
InvalidOperationException | The Cursor<T> reached the root node. The Cursor<T> is left in the last good state, that is, at the leftmost sibling. |
Move(Direction)
Move in a given Direction
Declaration
public void Move(Direction direction)
Parameters
Type | Name | Description |
---|---|---|
Direction | direction | The Direction to move in |
Exceptions
Type | Condition |
---|---|
InvalidOperationException | Thrown when the direction leads off the edge of the tree. The Cursor<T> is left in the last known good state. |
ArgumentOutOfRangeException | Thrown when |
ReleaseOldVersions()
Release old versions of the tree for garbage collection. The Cursor<T> is left focused on the current node.
Typically you won't need to call this method yourself - just call Top() at the end of your sequence of edits to get the new tree back. (This method is equivalent to calling Top() and then returning to where you were.)
The worst-case scenario for Cursor<T>'s memory usage is code which traverses a large tree and alternates Down() calls with setting the Focus, without any calls to Up() in between. If this is a typical usage pattern for your application, and you find that Cursor<T> is causing high memory usage because it's holding on to old trees, some infrequent calls to this method (say, every 1000 edits) should improve the memory usage (at the cost of some speed).
Declaration
public void ReleaseOldVersions()
Right()
Declaration
public void Right()
Exceptions
Type | Condition |
---|---|
InvalidOperationException | The Cursor<T> is already focused on the rightmost sibling |
Right(Int32)
Go Right() count
times.
Declaration
public void Right(int count)
Parameters
Type | Name | Description |
---|---|---|
Int32 | count |
Exceptions
Type | Condition |
---|---|
InvalidOperationException | The Cursor<T> reached the rightmost sibling. The Cursor<T> is left in the last good state, that is, focused on the rightmost sibling. |
ArgumentOutOfRangeException |
|
Rightmost()
Focus the Cursor<T> on the current Focus's rightmost sibling. Do nothing if the Cursor<T> is already focused on the rightmost sibling.
Declaration
public void Rightmost()
RightWhile(Func<T, Boolean>)
Go Right() as long as predicate
returns true for the current Focus.
In other words, find the first Right sibling of Focus (including itself) which does not satisfy predicate
.
Declaration
public void RightWhile(Func<T, bool> predicate)
Parameters
Type | Name | Description |
---|---|---|
Func<T, Boolean> | predicate | The predicate to invoke on the current focus and its ancestors |
Exceptions
Type | Condition |
---|---|
InvalidOperationException | The Cursor<T> reached the root node. The Cursor<T> is Right in the last good state, that is, at the Rightmost sibling. |
SearchDownAndRight(Func<T, Boolean>)
Focus the current focus's first descendant or right sibling's descendant which satisfies
This function searches the bottom-left part of the tree first, so will typically end up focusing a node lower down than SearchRightAndDown(Func<T, Boolean>).
SelfAndDescendants<T>(IRewriter<T>, T)Declaration
public bool SearchDownAndRight(Func<T, bool> predicate)
Parameters
Type | Name | Description |
---|---|---|
Func<T, Boolean> | predicate | A predicate which returns true when the search should stop |
Returns
Type | Description |
---|---|
Boolean | True if a matching focus was found, false if the search was exhaustive |
SearchRightAndDown(Func<T, Boolean>)
Focus the current focus's first descendant or right sibling's descendant which satisfies
This function searches the top-right part of the tree first, so will typically end up focusing a node higher up than SearchDownAndRight(Func<T, Boolean>).
Declaration
public bool SearchRightAndDown(Func<T, bool> predicate)
Parameters
Type | Name | Description |
---|---|---|
Func<T, Boolean> | predicate | A predicate which returns true when the search should stop |
Returns
Type | Description |
---|---|
Boolean | True if a matching focus was found, false if the search was exhaustive |
Top()
Move the Cursor<T> to the top of the tree.
This operation "plugs the hole" in all of the current node's ancestors, replacing their children as necessary. Going to the Top() releases old versions of the tree so that they can be garbage collected.
Declaration
public void Top()
TryDown()
Try to focus the Cursor<T> on the current Focus's first child.
This operation "opens a hole" in the current node, descending to the children so you can replace them one at a time.
Declaration
public bool TryDown()
Returns
Type | Description |
---|---|
Boolean | True if the operation was successful, false if the current Focus has no children |
TryDown(Int32)
Go Down() count
times, stopping if you reach a node with no children.
This operation "opens a hole" in the current node and its count
first descendants.
Declaration
public bool TryDown(int count)
Parameters
Type | Name | Description |
---|---|---|
Int32 | count |
Returns
Type | Description |
---|---|
Boolean | True if the operation was successful, false if the cursor went Down() fewer than |
Exceptions
Type | Condition |
---|---|
ArgumentOutOfRangeException |
|
TryDownWhile(Func<T, Boolean>)
Go Down() as long as predicate
returns true for the current Focus, stopping if you reach the bottom.
In other words, find the first leftmost descendant of Focus (including itself) which does not satisfy predicate
.
Declaration
public bool TryDownWhile(Func<T, bool> predicate)
Parameters
Type | Name | Description |
---|---|---|
Func<T, Boolean> | predicate | The predicate to invoke on the current focus and its leftmost descendants |
Returns
Type | Description |
---|---|
Boolean | True if a leftmost descendant not satisfying |
TryFollow(IEnumerable<Direction>)
Follow a path.
Declaration
public bool TryFollow(IEnumerable<Direction> path)
Parameters
Type | Name | Description |
---|---|---|
IEnumerable<Direction> | path | The path to follow |
Returns
Type | Description |
---|---|
Boolean | True if the path was successfully followed in full, false if the path led off the edge of the tree. |
TryLeft()
Declaration
public bool TryLeft()
Returns
Type | Description |
---|---|
Boolean | True if the operation was successful, false if the Cursor<T> is already focused on the leftmost sibling |
TryLeft(Int32)
Go Left() count
times, stopping if you reach the leftmost sibling.
Declaration
public bool TryLeft(int count)
Parameters
Type | Name | Description |
---|---|---|
Int32 | count |
Returns
Type | Description |
---|---|
Boolean | True if the operation was successful, false if the cursor went Left() fewer than |
Exceptions
Type | Condition |
---|---|
ArgumentOutOfRangeException |
|
TryLeftWhile(Func<T, Boolean>)
Go Left() as long as predicate
returns true for the current Focus, stopping if you reach the leftmost sibling.
In other words, find the left sibling of Focus (including itself) which does not satisfy predicate
.
Declaration
public bool TryLeftWhile(Func<T, bool> predicate)
Parameters
Type | Name | Description |
---|---|---|
Func<T, Boolean> | predicate | The predicate to invoke on the current focus and its ancestors |
Returns
Type | Description |
---|---|
Boolean | True if an ancestor not satisfying |
TryMove(Direction)
Try to move in a given Direction
Declaration
public bool TryMove(Direction direction)
Parameters
Type | Name | Description |
---|---|---|
Direction | direction | The Direction to move in |
Returns
Type | Description |
---|---|
Boolean | True if the operation was successful, false if the direction leads off the edge of the tree. |
Exceptions
Type | Condition |
---|---|
ArgumentOutOfRangeException | Thrown when |
TryRight()
Declaration
public bool TryRight()
Returns
Type | Description |
---|---|
Boolean | True if the operation was successful, false if the Cursor<T> is already focused on the rightmost sibling |
TryRight(Int32)
Go Right() count
times, stopping if you reach the rightmost sibling.
Declaration
public bool TryRight(int count)
Parameters
Type | Name | Description |
---|---|---|
Int32 | count |
Returns
Type | Description |
---|---|
Boolean | True if the operation was successful, false if the cursor went Right() fewer than |
Exceptions
Type | Condition |
---|---|
ArgumentOutOfRangeException |
|
TryRightWhile(Func<T, Boolean>)
Go Right() as long as predicate
returns true for the current Focus, stopping if you reach the Rightmost sibling.
In other words, find the Right sibling of Focus (including itself) which does not satisfy predicate
.
Declaration
public bool TryRightWhile(Func<T, bool> predicate)
Parameters
Type | Name | Description |
---|---|---|
Func<T, Boolean> | predicate | The predicate to invoke on the current focus and its ancestors |
Returns
Type | Description |
---|---|
Boolean | True if an ancestor not satisfying |
TryUp()
Try to focus the Cursor<T> on the current Focus's parent.
This operation "plugs the hole" in the parent, replacing the parent's children as necessary. This releases old versions of the current Focus and its children, so that they can be garbage collected.
Declaration
public bool TryUp()
Returns
Type | Description |
---|---|
Boolean | True if the operation was successful, false if the Cursor<T> is already focused on the root node |
TryUp(Int32)
Go Up() count
times, stopping if you reach the top.
This operation "plugs the hole" in the parent, replacing the parent's children as necessary. This releases old versions of the ancestors and their children, so that they can be garbage collected.
Declaration
public bool TryUp(int count)
Parameters
Type | Name | Description |
---|---|---|
Int32 | count |
Returns
Type | Description |
---|---|
Boolean | True if the operation was successful, false if the cursor went Up() fewer than |
Exceptions
Type | Condition |
---|---|
ArgumentOutOfRangeException |
|
TryUpWhile(Func<T, Boolean>)
Go Up() as long as predicate
returns true for the current Focus, stopping if you reach the top.
In other words, find the first ancestor of Focus (including itself) which does not satisfy predicate
.
This operation "plugs the hole" in the ancestors, replacing their children as necessary. This releases old versions of the ancestors and their children, so that they can be garbage collected.
Declaration
public bool TryUpWhile(Func<T, bool> predicate)
Parameters
Type | Name | Description |
---|---|---|
Func<T, Boolean> | predicate | The predicate to invoke on the current focus and its ancestors |
Returns
Type | Description |
---|---|
Boolean | True if an ancestor not satisfying |
Up()
Focus the Cursor<T> on the current Focus's parent.
Going Up() "plugs the hole" in the parent, replacing the parent's children as necessary. This releases old versions of the current Focus and its children so that they can be garbage collected.
Declaration
public void Up()
Exceptions
Type | Condition |
---|---|
InvalidOperationException | The Cursor<T> is already focused on the root node. |
Up(Int32)
Go Up() count
times.
Going Up(Int32) "plugs the hole" in the ancestors, replacing their children as necessary. This releases old versions of the ancestors and their children, so that they can be garbage collected.
Declaration
public void Up(int count)
Parameters
Type | Name | Description |
---|---|---|
Int32 | count |
Exceptions
Type | Condition |
---|---|
InvalidOperationException | The Cursor<T> reached the root node. The Cursor<T> is left in the last good state, that is, at the top of the tree. |
ArgumentOutOfRangeException |
|
UpWhile(Func<T, Boolean>)
Go Up() as long as predicate
returns true for the current Focus.
In other words, find the first ancestor of Focus (including itself) which does not satisfy predicate
.
This operation "plugs the hole" in the ancestors, replacing their children as necessary. This releases old versions of the ancestors and their children, so that they can be garbage collected.
Declaration
public void UpWhile(Func<T, bool> predicate)
Parameters
Type | Name | Description |
---|---|---|
Func<T, Boolean> | predicate | The predicate to invoke on the current focus and its ancestors |
Exceptions
Type | Condition |
---|---|
InvalidOperationException | The Cursor<T> reached the root node. The Cursor<T> is left in the last good state, that is, at the top of the tree. |