You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2023/06/08 23:28:04 UTC
[calcite] 04/06: In Puffin, add actions before and after each source and all sources
This is an automated email from the ASF dual-hosted git repository.
jhyde pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
commit ac4920bb0ab52a25c3b2cf008f361ff0fbc7f82a
Author: Julian Hyde <jh...@apache.org>
AuthorDate: Thu Jun 8 00:20:49 2023 -0700
In Puffin, add actions before and after each source and all sources
---
.../main/java/org/apache/calcite/util/Puffin.java | 80 +++++++++++++++++++---
.../java/org/apache/calcite/test/PuffinTest.java | 74 ++++++++++++++++++--
2 files changed, 140 insertions(+), 14 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/util/Puffin.java b/core/src/main/java/org/apache/calcite/util/Puffin.java
index f776d58030..3be201ea4e 100644
--- a/core/src/main/java/org/apache/calcite/util/Puffin.java
+++ b/core/src/main/java/org/apache/calcite/util/Puffin.java
@@ -78,7 +78,8 @@ public class Puffin {
public static <G, F> Builder<G, F> builder(Supplier<G> globalStateFactory,
Function<G, F> fileStateFactory) {
return new BuilderImpl<>(globalStateFactory, fileStateFactory,
- PairList.of(), new ArrayList<>());
+ PairList.of(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(),
+ new ArrayList<>());
}
/** Creates a Builder with no state. */
@@ -92,9 +93,23 @@ public class Puffin {
* @param <F> Type of state that is created when we start processing a file
* @see Puffin#builder */
public interface Builder<G, F> {
+ /** Adds a predicate and action to be invoked on each line of a source. */
Builder<G, F> add(Predicate<Line<G, F>> linePredicate,
Consumer<Line<G, F>> action);
+
+ /** Adds an action to be called before each source. */
+ Builder<G, F> beforeSource(Consumer<Context<G, F>> action);
+
+ /** Adds an action to be called after each source. */
+ Builder<G, F> afterSource(Consumer<Context<G, F>> action);
+
+ /** Adds an action to be called before all sources. */
+ Builder<G, F> before(Consumer<Context<G, F>> action);
+
+ /** Adds an action to be called after all sources. */
Builder<G, F> after(Consumer<Context<G, F>> action);
+
+ /** Builds the program. */
Program<G> build();
}
@@ -239,8 +254,11 @@ public class Puffin {
private static class ProgramImpl<G, F> implements Program<G> {
private final Supplier<G> globalStateFactory;
private final Function<G, F> fileStateFactory;
- private final PairList<Predicate<Line<G, F>>, Consumer<Line<G, F>>> pairList;
- private final ImmutableList<Consumer<Context<G, F>>> endList;
+ private final PairList<Predicate<Line<G, F>>, Consumer<Line<G, F>>> onLineList;
+ private final ImmutableList<Consumer<Context<G, F>>> beforeSourceList;
+ private final ImmutableList<Consumer<Context<G, F>>> afterSourceList;
+ private final ImmutableList<Consumer<Context<G, F>>> beforeList;
+ private final ImmutableList<Consumer<Context<G, F>>> afterList;
@SuppressWarnings("Convert2MethodRef")
private final LoadingCache<String, Pattern> patternCache0 =
CacheBuilder.newBuilder()
@@ -250,18 +268,31 @@ public class Puffin {
private ProgramImpl(Supplier<G> globalStateFactory,
Function<G, F> fileStateFactory,
- PairList<Predicate<Line<G, F>>, Consumer<Line<G, F>>> pairList,
- ImmutableList<Consumer<Context<G, F>>> endList) {
+ PairList<Predicate<Line<G, F>>, Consumer<Line<G, F>>> onLineList,
+ ImmutableList<Consumer<Context<G, F>>> beforeSourceList,
+ ImmutableList<Consumer<Context<G, F>>> afterSourceList,
+ ImmutableList<Consumer<Context<G, F>>> beforeList,
+ ImmutableList<Consumer<Context<G, F>>> afterList) {
this.globalStateFactory = globalStateFactory;
this.fileStateFactory = fileStateFactory;
- this.pairList = pairList;
- this.endList = endList;
+ this.onLineList = onLineList;
+ this.beforeSourceList = beforeSourceList;
+ this.afterSourceList = afterSourceList;
+ this.beforeList = beforeList;
+ this.afterList = afterList;
}
@Override public G execute(Stream<? extends Source> sources,
PrintWriter out) {
final G globalState = globalStateFactory.get();
+ final Source source0 = Sources.of("");
+ final F fileState0 = fileStateFactory.apply(globalState);
+ final ContextImpl<G, F> x0 =
+ new ContextImpl<G, F>(out, source0, patternCache, globalState,
+ fileState0);
+ beforeList.forEach(action -> action.accept(x0));
sources.forEach(source -> execute(globalState, source, out));
+ afterList.forEach(action -> action.accept(x0));
return globalState;
}
@@ -272,20 +303,21 @@ public class Puffin {
final ContextImpl<G, F> x =
new ContextImpl<G, F>(out, source, patternCache, globalState,
fileState);
+ beforeSourceList.forEach(action -> action.accept(x));
for (;;) {
String lineText = br.readLine();
if (lineText == null) {
- endList.forEach(end -> end.accept(x));
break;
}
++x.fnr;
x.line = lineText;
- pairList.forEach((predicate, action) -> {
+ onLineList.forEach((predicate, action) -> {
if (predicate.test(x)) {
action.accept(x);
}
});
}
+ afterSourceList.forEach(action -> action.accept(x));
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -301,15 +333,24 @@ public class Puffin {
private final Supplier<G> globalStateFactory;
private final Function<G, F> fileStateFactory;
final PairList<Predicate<Line<G, F>>, Consumer<Line<G, F>>> onLineList;
+ final List<Consumer<Context<G, F>>> beforeSourceList;
+ final List<Consumer<Context<G, F>>> afterSourceList;
+ final List<Consumer<Context<G, F>>> beforeList;
final List<Consumer<Context<G, F>>> afterList;
private BuilderImpl(Supplier<G> globalStateFactory,
Function<G, F> fileStateFactory,
PairList<Predicate<Line<G, F>>, Consumer<Line<G, F>>> onLineList,
+ List<Consumer<Context<G, F>>> beforeSourceList,
+ List<Consumer<Context<G, F>>> afterSourceList,
+ List<Consumer<Context<G, F>>> beforeList,
List<Consumer<Context<G, F>>> afterList) {
this.globalStateFactory = globalStateFactory;
this.fileStateFactory = fileStateFactory;
this.onLineList = onLineList;
+ this.beforeSourceList = beforeSourceList;
+ this.afterSourceList = afterSourceList;
+ this.beforeList = beforeList;
this.afterList = afterList;
}
@@ -319,6 +360,21 @@ public class Puffin {
return this;
}
+ @Override public Builder<G, F> beforeSource(Consumer<Context<G, F>> action) {
+ beforeSourceList.add(action);
+ return this;
+ }
+
+ @Override public Builder<G, F> afterSource(Consumer<Context<G, F>> action) {
+ afterSourceList.add(action);
+ return this;
+ }
+
+ @Override public Builder<G, F> before(Consumer<Context<G, F>> action) {
+ beforeList.add(action);
+ return this;
+ }
+
@Override public Builder<G, F> after(Consumer<Context<G, F>> action) {
afterList.add(action);
return this;
@@ -326,7 +382,11 @@ public class Puffin {
@Override public Program<G> build() {
return new ProgramImpl<>(globalStateFactory, fileStateFactory,
- onLineList.immutable(), ImmutableList.copyOf(afterList));
+ onLineList.immutable(),
+ ImmutableList.copyOf(beforeSourceList),
+ ImmutableList.copyOf(afterSourceList),
+ ImmutableList.copyOf(beforeList),
+ ImmutableList.copyOf(afterList));
}
}
}
diff --git a/core/src/test/java/org/apache/calcite/test/PuffinTest.java b/core/src/test/java/org/apache/calcite/test/PuffinTest.java
index 604685e0eb..3cbebca6a8 100644
--- a/core/src/test/java/org/apache/calcite/test/PuffinTest.java
+++ b/core/src/test/java/org/apache/calcite/test/PuffinTest.java
@@ -26,14 +26,19 @@ import org.junit.jupiter.api.Test;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
import java.util.stream.Stream;
import static org.apache.calcite.test.Matchers.isLinux;
+import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.hasToString;
/** Tests {@link Puffin}. */
@@ -42,19 +47,71 @@ public class PuffinTest {
new Fixture<>(Sources.of(""), Puffin.builder().build());
@Test void testPuffin() {
- Puffin.Program<Unit> program =
- Puffin.builder(() -> Unit.INSTANCE, u -> new AtomicInteger())
+ Puffin.Program<AtomicInteger> program =
+ Puffin.builder(AtomicInteger::new, counter -> Unit.INSTANCE)
.add(line -> !line.startsWith("#")
&& !line.matches(".*/\\*.*\\*/.*"),
- line -> line.state().incrementAndGet())
+ line -> line.globalState().incrementAndGet())
.after(context ->
- context.println("counter: " + context.state().get()))
+ context.println("counter: " + context.globalState().get()))
.build();
fixture().withDefaultInput()
.withProgram(program)
.generatesOutput(isLinux("counter: 2\n"));
}
+ /** Tests Puffin with several sources, registers actions by calling
+ * {@link Puffin.Builder#beforeSource(Consumer)},
+ * {@link Puffin.Builder#afterSource(Consumer)},
+ * {@link Puffin.Builder#before(Consumer)}, and
+ * {@link Puffin.Builder#after(Consumer)}, and counts how many times each is
+ * called. */
+ @Test void testSeveralSources() {
+ Puffin.Program<GlobalState> program =
+ Puffin.builder(GlobalState::new, u -> new AtomicInteger())
+ .add(line -> true,
+ line -> line.state().incrementAndGet())
+ .beforeSource(context -> {
+ final GlobalState g = context.globalState();
+ g.beforeSourceCount.incrementAndGet();
+ })
+ .afterSource(context -> {
+ final GlobalState g = context.globalState();
+ final AtomicInteger f = context.state();
+ g.messages.add(f.intValue() + " lines");
+ g.afterSourceCount.incrementAndGet();
+ })
+ .before(context -> {
+ final GlobalState g = context.globalState();
+ g.beforeCount.incrementAndGet();
+ })
+ .after(context -> {
+ final GlobalState g = context.globalState();
+ g.afterCount.incrementAndGet();
+ g.messages.add(g.afterSourceCount + " after sources");
+ g.messages.add(g.beforeSourceCount + " before sources");
+ g.messages.add(g.beforeCount + " before");
+ g.messages.add(g.afterCount + " after");
+ })
+ .build();
+ final StringWriter sw = new StringWriter();
+ GlobalState g =
+ program.execute(
+ Stream.of(Sources.of("a\nb\n"),
+ Sources.of("a\n"),
+ Sources.of("a\nb\nc\n")),
+ new PrintWriter(sw));
+ assertThat(g.messages, hasSize(7));
+ assertThat(g.messages, hasItem("3 lines"));
+ assertThat(g.messages, hasItem("2 lines"));
+ assertThat(g.messages, hasItem("1 lines"));
+ assertThat(g.messages, hasItem("3 after sources"));
+ assertThat(g.messages, hasItem("3 before sources"));
+ assertThat(g.messages, hasItem("1 before"));
+ assertThat(g.messages, hasItem("1 after"));
+ assertThat(sw, hasToString(""));
+ }
+
@Test void testEmptyProgram() {
final Puffin.Program<Unit> program = Puffin.builder().build();
fixture().withDefaultInput()
@@ -105,4 +162,13 @@ public class PuffinTest {
return this;
}
}
+
+ /** Global state. */
+ private static class GlobalState {
+ final List<String> messages = new ArrayList<>();
+ final AtomicInteger beforeSourceCount = new AtomicInteger();
+ final AtomicInteger afterSourceCount = new AtomicInteger();
+ final AtomicInteger beforeCount = new AtomicInteger();
+ final AtomicInteger afterCount = new AtomicInteger();
+ }
}