All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.shaded.org.apache.calcite.util.Puffin Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to you under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hazelcast.shaded.org.apache.calcite.util;

import com.hazelcast.shaded.org.apache.calcite.runtime.PairList;
import com.hazelcast.shaded.org.apache.calcite.runtime.Unit;

import com.hazelcast.shaded.com.google.common.cache.CacheBuilder;
import com.hazelcast.shaded.com.google.common.cache.CacheLoader;
import com.hazelcast.shaded.com.google.common.cache.LoadingCache;
import com.hazelcast.shaded.com.google.common.collect.ImmutableList;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import static java.util.Objects.requireNonNull;

/**
 * A text processor similar to Awk.
 *
 * 

Example use: * *

{@code
 * File file;
 * final Puffin.Program program =
 *   Puffin.builder()
 *       .add(line -> !line.startsWith("#"),
 *           line -> counter.incrementAndGet())
 *       .after(context ->
 *           context.println("There were " + counter.get()
 *               + " uncommented lines"))
 *       .build();
 * program.execute(Source.of(file), System.out);
 * }
* *

prints the following to stdout: * *

{@code * There were 3 uncommented lines. * }
*/ public class Puffin { private Puffin() { } /** Creates a Builder. * * @param fileStateFactory Creates the state for each file * @return Builder * @param Type of state that is created when we start processing * @param Type of state that is created when we start processing a file */ public static Builder builder(Supplier globalStateFactory, Function fileStateFactory) { return new BuilderImpl<>(globalStateFactory, fileStateFactory, PairList.of(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); } /** Creates a Builder with no state. */ public static Builder builder() { return builder(() -> Unit.INSTANCE, u -> u); } /** Fluent interface for constructing a Program. * * @param Type of state that is created when we start processing * @param Type of state that is created when we start processing a file * @see Puffin#builder */ public interface Builder { /** Adds a predicate and action to be invoked on each line of a source. */ Builder add(Predicate> linePredicate, Consumer> action); /** Adds an action to be called before each source. */ Builder beforeSource(Consumer> action); /** Adds an action to be called after each source. */ Builder afterSource(Consumer> action); /** Adds an action to be called before all sources. */ Builder before(Consumer> action); /** Adds an action to be called after all sources. */ Builder after(Consumer> action); /** Builds the program. */ Program build(); } /** A Puffin program. You can execute it on a file. * * @param Type of state that is created when we start processing */ public interface Program { /** Executes this program. */ G execute(Stream sources, PrintWriter out); /** Executes this program, writing to an output stream such as * {@link System#out}. */ default void execute(Stream sources, OutputStream out) { try (PrintWriter w = Util.printWriter(out)) { execute(sources, w); } } /** Executes this program on a single source. */ default void execute(Source source, OutputStream out) { execute(Stream.of(source), out); } } /** A line in a file. * *

Created by an executing program and passed to the predicate * and action that you registered in * {@link Builder#add(Predicate, Consumer)}. * * @param Type of state that is created when we start processing * @param Type of state that is created when we start processing a file */ public interface Line { G globalState(); F state(); int fnr(); String filename(); Source source(); boolean startsWith(String prefix); boolean contains(CharSequence s); boolean endsWith(String suffix); boolean matches(String regex); String line(); } /** Context for executing a Puffin program within a given file. * * @param Type of state that is created when we start processing * @param Type of state that is created when we start processing a file */ public static class Context { final PrintWriter out; final Source source; final F fileState; final G globalState; private final Function patternCache; /** Holds the current line. */ String line = ""; /** Holds the current line number in the file (starting from 1). * *

Corresponds to the Awk variable {@code FNR}, which stands for "file * number of records". */ int fnr = 0; Context(PrintWriter out, Source source, Function patternCache, G globalState, F fileState) { this.out = requireNonNull(out, "out"); this.source = requireNonNull(source, "source"); this.patternCache = requireNonNull(patternCache, "patternCache"); this.globalState = requireNonNull(globalState, "globalState"); this.fileState = requireNonNull(fileState, "fileState"); } public F state() { return fileState; } public G globalState() { return globalState; } public void println(String s) { out.println(s); } Pattern pattern(String regex) { return patternCache.apply(regex); } } /** Extension to {@link Context} that also implements {@link Line}. * *

We don't want clients to know that {@code Context} implements * {@code Line}, but neither do we want to create a new {@code Line} object * for every line in the file. Making this a subclass accomplishes both * goals. * * @param Type of state that is created when we start processing * @param Type of state that is created when we start processing a file */ static class ContextImpl extends Context implements Line { ContextImpl(PrintWriter out, Source source, Function patternCache, G globalState, F state) { super(out, source, patternCache, globalState, state); } @Override public int fnr() { return fnr; } @Override public String filename() { return source().toString(); } @Override public Source source() { return source; } @Override public boolean startsWith(String prefix) { return line.startsWith(prefix); } @Override public boolean contains(CharSequence s) { return line.contains(s); } @Override public boolean endsWith(String suffix) { return line.endsWith(suffix); } @Override public boolean matches(String regex) { return pattern(regex).matcher(line).matches(); } @Override public String line() { return line; } } /** Implementation of {@link Program}. * * @param Type of state that is created when we start processing * @param Type of state that is created when we start processing a file */ private static class ProgramImpl implements Program { private final Supplier globalStateFactory; private final Function fileStateFactory; private final PairList>, Consumer>> onLineList; private final ImmutableList>> beforeSourceList; private final ImmutableList>> afterSourceList; private final ImmutableList>> beforeList; private final ImmutableList>> afterList; @SuppressWarnings("Convert2MethodRef") private final LoadingCache patternCache0 = CacheBuilder.newBuilder() .build(CacheLoader.from(regex -> Pattern.compile(regex))); private final Function patternCache = patternCache0::getUnchecked; private ProgramImpl(Supplier globalStateFactory, Function fileStateFactory, PairList>, Consumer>> onLineList, ImmutableList>> beforeSourceList, ImmutableList>> afterSourceList, ImmutableList>> beforeList, ImmutableList>> afterList) { this.globalStateFactory = globalStateFactory; this.fileStateFactory = fileStateFactory; this.onLineList = onLineList; this.beforeSourceList = beforeSourceList; this.afterSourceList = afterSourceList; this.beforeList = beforeList; this.afterList = afterList; } @Override public G execute(Stream sources, PrintWriter out) { final G globalState = globalStateFactory.get(); final Source source0 = Sources.of(""); final F fileState0 = fileStateFactory.apply(globalState); final ContextImpl x0 = new ContextImpl(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; } private void execute(G globalState, Source source, PrintWriter out) { try (Reader r = source.reader(); BufferedReader br = new BufferedReader(r)) { final F fileState = fileStateFactory.apply(globalState); final ContextImpl x = new ContextImpl(out, source, patternCache, globalState, fileState); beforeSourceList.forEach(action -> action.accept(x)); for (;;) { String lineText = br.readLine(); if (lineText == null) { break; } ++x.fnr; x.line = lineText; onLineList.forEach((predicate, action) -> { if (predicate.test(x)) { action.accept(x); } }); } afterSourceList.forEach(action -> action.accept(x)); } catch (IOException e) { throw new RuntimeException(e); } } } /** Implementation of Builder. * * @param Type of state that is created when we start processing * @param Type of state that is created when we start processing a file */ private static class BuilderImpl implements Builder { private final Supplier globalStateFactory; private final Function fileStateFactory; final PairList>, Consumer>> onLineList; final List>> beforeSourceList; final List>> afterSourceList; final List>> beforeList; final List>> afterList; private BuilderImpl(Supplier globalStateFactory, Function fileStateFactory, PairList>, Consumer>> onLineList, List>> beforeSourceList, List>> afterSourceList, List>> beforeList, List>> afterList) { this.globalStateFactory = globalStateFactory; this.fileStateFactory = fileStateFactory; this.onLineList = onLineList; this.beforeSourceList = beforeSourceList; this.afterSourceList = afterSourceList; this.beforeList = beforeList; this.afterList = afterList; } @Override public Builder add(Predicate> linePredicate, Consumer> action) { onLineList.add(linePredicate, action); return this; } @Override public Builder beforeSource(Consumer> action) { beforeSourceList.add(action); return this; } @Override public Builder afterSource(Consumer> action) { afterSourceList.add(action); return this; } @Override public Builder before(Consumer> action) { beforeList.add(action); return this; } @Override public Builder after(Consumer> action) { afterList.add(action); return this; } @Override public Program build() { return new ProgramImpl<>(globalStateFactory, fileStateFactory, onLineList.immutable(), ImmutableList.copyOf(beforeSourceList), ImmutableList.copyOf(afterSourceList), ImmutableList.copyOf(beforeList), ImmutableList.copyOf(afterList)); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy