Skip to content
This repository was archived by the owner on Oct 25, 2024. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 14 additions & 39 deletions flow/src/main/java/flow/Flow.java
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,19 @@ public void setHistory(@NonNull final History history, @NonNull final Direction
});
}

/**
* Accepts a {@link HistoryUpdater function} to be applied to the history, allowing a
* transition to be calculated.
*/
public void updateHistory(@NonNull final HistoryUpdater updater) {
move(new PendingTraversal() {
@Override void doExecute() {
HistoryUpdater.Result result = updater.call(getHistory());
dispatch(preserveEquivalentPrefix(getHistory(), result.history), result.direction);
}
});
}

/**
* Replaces the history with the given key and dispatches in the given direction.
*/
Expand Down Expand Up @@ -219,45 +232,7 @@ public void replaceTop(@NonNull final Object key, @NonNull final Direction direc
* Objects' equality is always checked using {@link Object#equals(Object)}.
*/
public void set(@NonNull final Object newTopKey) {
move(new PendingTraversal() {
@Override void doExecute() {
if (newTopKey.equals(history.top())) {
dispatch(history, Direction.REPLACE);
return;
}

History.Builder builder = history.buildUpon();
int count = 0;
// Search backward to see if we already have newTop on the stack
Object preservedInstance = null;
for (Iterator<Object> it = history.reverseIterator(); it.hasNext(); ) {
Object entry = it.next();

// If we find newTop on the stack, pop back to it.
if (entry.equals(newTopKey)) {
for (int i = 0; i < history.size() - count; i++) {
preservedInstance = builder.pop();
}
break;
} else {
count++;
}
}

History newHistory;
if (preservedInstance != null) {
// newTop was on the history. Put the preserved instance back on and dispatch.
builder.push(preservedInstance);
newHistory = builder.build();
dispatch(newHistory, Direction.BACKWARD);
} else {
// newTop was not on the history. Push it on and dispatch.
builder.push(newTopKey);
newHistory = builder.build();
dispatch(newHistory, Direction.FORWARD);
}
}
});
updateHistory(new HistoryUpdater.DoSet(newTopKey));
}

/**
Expand Down
69 changes: 69 additions & 0 deletions flow/src/main/java/flow/HistoryUpdater.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package flow;

import java.util.Iterator;

/**
* A function that calculates the next state of a given {@link History}.
*/
public interface HistoryUpdater {

Result call(History history);

final class Result {
public final History history;
public final Direction direction;

public Result(History history, Direction direction) {
this.history = history;
this.direction = direction;
}

@Override public String toString() {
return String.format("%s: %s to %s", getClass().getName(), direction, history);
}
}

final class DoSet implements HistoryUpdater {
private final Object newTopKey;

public DoSet(Object newTopKey) {
this.newTopKey = newTopKey;
}

@Override public Result call(History history) {
if (newTopKey.equals(history.top())) {
return new Result(history, Direction.REPLACE);
}

History.Builder builder = history.buildUpon();
int count = 0;
// Search backward to see if we already have newTop on the stack
Object preservedInstance = null;
for (Iterator<Object> it = history.reverseIterator(); it.hasNext(); ) {
Object entry = it.next();

// If we find newTop on the stack, pop back to it.
if (entry.equals(newTopKey)) {
for (int i = 0; i < history.size() - count; i++) {
preservedInstance = builder.pop();
}
break;
} else {
count++;
}
}

History newHistory;
if (preservedInstance != null) {
// newTop was on the history. Put the preserved instance back on and dispatch.
builder.push(preservedInstance);
newHistory = builder.build();
return new Result(newHistory, Direction.BACKWARD);
}
// newTop was not on the history. Push it on and dispatch.
builder.push(newTopKey);
newHistory = builder.build();
return new Result(newHistory, Direction.FORWARD);
}
}
}