More simpler

- Remove Plan#simplify and associated tests
- Neat idea but ineffective in practice
- Should reduce the user burden of implementing plans
This commit is contained in:
Jozufozu 2024-02-28 21:23:47 -08:00
parent bd70b89621
commit c931e84b65
10 changed files with 2 additions and 239 deletions

View file

@ -38,12 +38,4 @@ public interface Plan<C> {
* @return The composed plan.
*/
Plan<C> and(Plan<C> plan);
/**
* If possible, create a new plan that accomplishes everything
* this plan does but with a simpler execution schedule.
*
* @return A simplified plan, or this.
*/
Plan<C> simplify();
}

View file

@ -95,8 +95,7 @@ public class VisualizationManagerImpl implements VisualizationManager {
effects = new VisualManagerImpl<>(effectsStorage);
tickPlan = NestedPlan.of(blockEntities.tickPlan(), entities.tickPlan(), effects.tickPlan())
.then(RaisePlan.raise(tickFlag))
.simplify();
.then(RaisePlan.raise(tickFlag));
var recreate = SimplePlan.<RenderContext>of(context -> blockEntitiesStorage.recreateAll(context.partialTick()),
context -> entitiesStorage.recreateAll(context.partialTick()),
@ -111,8 +110,7 @@ public class VisualizationManagerImpl implements VisualizationManager {
.plan()
.then(RaisePlan.raise(frameVisualsFlag))
.then(engine.createFramePlan())
.then(RaisePlan.raise(frameFlag))
.simplify();
.then(RaisePlan.raise(frameFlag));
if (level instanceof Level l) {
LevelExtension.getAllLoadedEntities(l)

View file

@ -13,18 +13,4 @@ public record BarrierPlan<C>(Plan<C> first, Plan<C> second) implements SimplyCom
first.execute(taskExecutor, context, () -> second.execute(taskExecutor, context, onCompletion));
}
@Override
public Plan<C> simplify() {
var first = this.first.simplify();
var second = this.second.simplify();
if (first == UnitPlan.of()) {
return second;
}
if (second == UnitPlan.of()) {
return first;
}
return new BarrierPlan<>(first, second);
}
}

View file

@ -30,19 +30,6 @@ public record IfElsePlan<C>(BooleanSupplierWithContext<C> condition, Plan<C> onT
}
}
@Override
public Plan<C> simplify() {
var maybeSimplifiedTrue = onTrue.simplify();
var maybeSimplifiedFalse = onFalse.simplify();
if (maybeSimplifiedTrue instanceof UnitPlan && maybeSimplifiedFalse instanceof UnitPlan) {
// The condition may have side effects that still need to be evaluated.
return SimplePlan.of(condition::test);
}
return new IfElsePlan<>(condition, maybeSimplifiedTrue, maybeSimplifiedFalse);
}
public static class Builder<C> {
private final BooleanSupplierWithContext<C> condition;
private Plan<C> onTrue = UnitPlan.of();

View file

@ -19,17 +19,6 @@ public record MapContextPlan<C, D>(SupplierWithContext<C, D> map, Plan<D> plan)
plan.execute(taskExecutor, newContext, onCompletion);
}
@Override
public Plan<C> simplify() {
var maybeSimplified = plan.simplify();
if (maybeSimplified instanceof UnitPlan) {
return UnitPlan.of();
}
return new MapContextPlan<>(map, maybeSimplified);
}
public static class Builder<C, D> {
private final SupplierWithContext<C, D> map;

View file

@ -1,13 +1,10 @@
package com.jozufozu.flywheel.lib.task;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.task.Plan;
import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.lib.task.functional.RunnableWithContext;
public record NestedPlan<C>(List<Plan<C>> parallelPlans) implements SimplyComposedPlan<C> {
@SafeVarargs
@ -44,61 +41,4 @@ public record NestedPlan<C>(List<Plan<C>> parallelPlans) implements SimplyCompos
.build());
}
@Override
public Plan<C> simplify() {
if (parallelPlans.isEmpty()) {
return UnitPlan.of();
}
if (parallelPlans.size() == 1) {
return parallelPlans.get(0)
.simplify();
}
var simplifiedTasks = new ArrayList<RunnableWithContext<C>>();
var simplifiedPlans = new ArrayList<Plan<C>>();
var toVisit = new ArrayDeque<>(parallelPlans);
while (!toVisit.isEmpty()) {
var plan = toVisit.pop()
.simplify();
if (plan == UnitPlan.of()) {
continue;
}
if (plan instanceof SimplePlan<C> simplePlan) {
// merge all simple plans into one
simplifiedTasks.addAll(simplePlan.parallelTasks());
} else if (plan instanceof NestedPlan<C> nestedPlan) {
// inline and re-visit nested plans
toVisit.addAll(nestedPlan.parallelPlans());
} else {
// /shrug
simplifiedPlans.add(plan);
}
}
if (simplifiedTasks.isEmpty() && simplifiedPlans.isEmpty()) {
// everything got simplified away
return UnitPlan.of();
}
if (simplifiedTasks.isEmpty()) {
// no simple plan to create
if (simplifiedPlans.size() == 1) {
// we only contained one complex plan, so we can just return that
return simplifiedPlans.get(0);
}
return new NestedPlan<>(simplifiedPlans);
}
if (simplifiedPlans.isEmpty()) {
// we only contained simple plans, so we can just return one
return SimplePlan.of(simplifiedTasks);
}
// we have both simple and complex plans, so we need to create a nested plan
simplifiedPlans.add(SimplePlan.of(simplifiedTasks));
return new NestedPlan<>(simplifiedPlans);
}
}

View file

@ -43,12 +43,4 @@ public record SimplePlan<C>(List<RunnableWithContext<C>> parallelTasks) implemen
return SimplyComposedPlan.super.and(plan);
}
@Override
public Plan<C> simplify() {
if (parallelTasks.isEmpty()) {
return UnitPlan.of();
}
return this;
}
}

View file

@ -13,8 +13,4 @@ public interface SimplyComposedPlan<C> extends Plan<C> {
return NestedPlan.of(this, plan);
}
@Override
default Plan<C> simplify() {
return this;
}
}

View file

@ -29,8 +29,4 @@ public class UnitPlan<C> implements Plan<C> {
return plan;
}
@Override
public Plan<C> simplify() {
return this;
}
}

View file

@ -1,113 +0,0 @@
package com.jozufozu.flywheel.lib.task;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import com.jozufozu.flywheel.api.task.Plan;
import com.jozufozu.flywheel.lib.task.functional.RunnableWithContext;
import com.jozufozu.flywheel.lib.util.Unit;
public class PlanSimplificationTest {
public static final RunnableWithContext.Ignored<Unit> NOOP = () -> {
};
public static final Plan<Unit> SIMPLE = SimplePlan.of(NOOP);
@Test
void emptyPlans() {
var empty = NestedPlan.of();
Assertions.assertEquals(empty.simplify(), UnitPlan.of());
var simpleEmpty = SimplePlan.of();
Assertions.assertEquals(simpleEmpty.simplify(), UnitPlan.of());
}
@Test
void nestedSimplePlans() {
var twoSimple = NestedPlan.of(SimplePlan.of(NOOP, NOOP, NOOP), SIMPLE);
Assertions.assertEquals(twoSimple.simplify(), SimplePlan.of(NOOP, NOOP, NOOP, NOOP));
var threeSimple = NestedPlan.of(SIMPLE, SIMPLE, SIMPLE);
Assertions.assertEquals(threeSimple.simplify(), SimplePlan.of(NOOP, NOOP, NOOP));
}
@Test
void oneNestedPlan() {
var oneSimple = NestedPlan.of(SIMPLE);
Assertions.assertEquals(oneSimple.simplify(), SIMPLE);
var mainThreadNoop = new SyncedPlan<>(NOOP);
var oneMainThread = NestedPlan.of(mainThreadNoop);
Assertions.assertEquals(oneMainThread.simplify(), mainThreadNoop);
var barrier = new BarrierPlan<>(SIMPLE, SIMPLE);
var oneBarrier = NestedPlan.of(barrier);
Assertions.assertEquals(oneBarrier.simplify(), barrier);
}
@Test
void nestedNestedPlan() {
var outer = NestedPlan.of(SIMPLE);
var outermost = NestedPlan.of(outer);
Assertions.assertEquals(outermost.simplify(), SIMPLE);
}
@Test
void nestedUnitPlan() {
var onlyUnit = NestedPlan.of(UnitPlan.of(), UnitPlan.of(), UnitPlan.of());
Assertions.assertEquals(onlyUnit.simplify(), UnitPlan.of());
var unitAndSimple = NestedPlan.of(UnitPlan.of(), UnitPlan.of(), SIMPLE);
Assertions.assertEquals(unitAndSimple.simplify(), SIMPLE);
}
@Test
void complexNesting() {
var mainThreadNoop = SyncedPlan.<Unit>of(() -> {
});
var nested = NestedPlan.of(mainThreadNoop, SIMPLE);
Assertions.assertEquals(nested.simplify(), nested); // cannot simplify
var barrier = new BarrierPlan<>(SIMPLE, SIMPLE);
var complex = NestedPlan.of(barrier, nested);
Assertions.assertEquals(complex.simplify(), NestedPlan.of(barrier, mainThreadNoop, SIMPLE));
}
@Test
void nestedNoSimple() {
var mainThreadNoop = SyncedPlan.<Unit>of(() -> {
});
var barrier = new BarrierPlan<>(SIMPLE, SIMPLE);
var oneMainThread = NestedPlan.of(mainThreadNoop, NestedPlan.of(mainThreadNoop, barrier, barrier));
Assertions.assertEquals(oneMainThread.simplify(), NestedPlan.of(mainThreadNoop, mainThreadNoop, barrier, barrier));
}
@Test
void manyNestedButJustOneAfterSimplification() {
var barrier = new BarrierPlan<>(SIMPLE, SIMPLE);
var oneMainThread = NestedPlan.of(barrier, NestedPlan.of(UnitPlan.of(), UnitPlan.of()));
Assertions.assertEquals(oneMainThread.simplify(), barrier);
}
@Test
void barrierPlan() {
var doubleUnit = new BarrierPlan<>(UnitPlan.of(), UnitPlan.of());
Assertions.assertEquals(doubleUnit.simplify(), UnitPlan.of());
var simpleThenUnit = new BarrierPlan<>(SIMPLE, UnitPlan.of());
Assertions.assertEquals(simpleThenUnit.simplify(), SIMPLE);
var unitThenSimple = new BarrierPlan<>(UnitPlan.of(), SIMPLE);
Assertions.assertEquals(unitThenSimple.simplify(), SIMPLE);
var simpleThenSimple = new BarrierPlan<>(SIMPLE, SIMPLE);
Assertions.assertEquals(simpleThenSimple.simplify(), new BarrierPlan<>(SIMPLE, SIMPLE));
}
}