
groovyx.gpars.dataflow.stream.StreamCore Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gpars Show documentation
Show all versions of gpars Show documentation
The Groovy and Java high-level concurrency library offering actors, dataflow, CSP, agents, parallel collections, fork/join and more
// GPars - Groovy Parallel Systems
//
// Copyright © 2008-2012 The original author or authors
//
// Licensed 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 groovyx.gpars.dataflow.stream;
import groovy.lang.Closure;
import groovyx.gpars.actor.impl.MessageStream;
import groovyx.gpars.dataflow.DataCallback;
import groovyx.gpars.dataflow.Dataflow;
import groovyx.gpars.dataflow.DataflowChannelListener;
import groovyx.gpars.dataflow.DataflowReadChannel;
import groovyx.gpars.dataflow.DataflowVariable;
import groovyx.gpars.dataflow.expression.DataflowExpression;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReference;
/**
* Represents a common base for publish-subscribe deterministic channels.
*
* @param Type for values to pass through the channels
* @author Johannes Link, Vaclav Pech
*/
public abstract class StreamCore implements FList {
protected final DataflowVariable first;
protected final AtomicReference> rest = new AtomicReference>();
/**
* A collection of listeners who need to be informed each time the stream is bound to a value
*/
protected final Collection wheneverBoundListeners;
/**
* Creates an empty stream
*
* @param first The variable to store as the head of the stream
*/
protected StreamCore(final DataflowVariable first) {
this.first = first;
wheneverBoundListeners = new CopyOnWriteArrayList();
}
/**
* Creates a stream while applying the supplied initialization closure to it
*
* @param first The variable to store as the head of the stream
* @param toBeApplied The closure to use for initialization
*/
protected StreamCore(final DataflowVariable first, final Closure toBeApplied) {
this(first);
apply(toBeApplied);
}
@SuppressWarnings({"AssignmentToCollectionOrArrayFieldFromParameter"})
protected StreamCore(final DataflowVariable first, final Collection wheneverBoundListeners, final Collection> updateListeners) {
this.first = first;
this.wheneverBoundListeners = wheneverBoundListeners;
hookWheneverBoundListeners(first);
addUpdateListeners(updateListeners);
}
private void addUpdateListeners(final Collection> updateListeners) {
first.getEventManager().addAllDataflowChannelListeners(updateListeners);
}
final void addUpdateListener(final DataflowChannelListener updateListener) {
first.getEventManager().addDataflowChannelListener(updateListener);
}
public static T eos() {
return null;
}
private static T eval(final Object valueOrDataflowVariable) {
if (valueOrDataflowVariable instanceof DataflowVariable)
try {
return ((DataflowReadChannel) valueOrDataflowVariable).getVal();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return (T) valueOrDataflowVariable;
}
/**
* Populates the stream with generated values
*
* @param seed The initial element to evaluate and add as the first value of the stream
* @param generator A closure generating stream elements from the previous values
* @param condition A closure indicating whether the generation should continue based on the last generated value
* @return This stream
*/
public final StreamCore generate(final T seed, final Closure generator, final Closure condition) {
generateNext(seed, this, generator, condition);
return this;
}
private void generateNext(final T value, final StreamCore stream, final Closure generator, final Closure condition) {
T recurValue = value;
StreamCore recurStream = stream;
while (true) {
final boolean addValue = (Boolean) condition.call(new Object[]{recurValue});
if (!addValue) {
recurStream.leftShift(StreamCore.eos());
return;
}
recurStream = recurStream.leftShift(recurValue);
recurValue = (T) eval(generator.call(new Object[]{recurValue}));
}
}
/**
* Calls the supplied closure with the stream as a parameter
*
* @param closure The closure to call
* @return This instance of DataflowStream
*/
public final StreamCore apply(final Closure closure) {
closure.call(new Object[]{this});
return this;
}
/**
* Adds a dataflow variable value to the stream, once the value is available
*
* @param ref The DataflowVariable to check for value
* @return The rest of the stream
*/
public final StreamCore leftShift(final DataflowReadChannel ref) {
ref.getValAsync(new MessageStream() {
@Override
public MessageStream send(final Object message) {
first.bind((T) message);
return null;
}
});
return (StreamCore) getRest();
}
/**
* Adds a value to the stream
*
* @param value The value to add
* @return The rest of the stream
*/
public final StreamCore leftShift(final T value) {
bind(value);
return (StreamCore) getRest();
}
private void bind(final T value) {
first.bind(value);
}
final DataflowVariable getFirstDFV() {
return first;
}
/**
* Retrieved the first element in the stream, blocking until a value is available
*
* @return The first item in the stream
*/
@Override
public final T getFirst() {
try {
return first.getVal();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
/**
* Retrieves a DataflowStream representing the rest of this Stream after removing the first element
*
* @return The remaining stream elements
*/
@Override
public abstract FList getRest();
/**
* Indicates, whether the first element in the stream is an eos
*/
@Override
public final boolean isEmpty() {
return getFirst() == eos();
}
/**
* Builds a filtered stream using the supplied filter closure
*
* @param filterClosure The closure to decide on inclusion of elements
* @return The first item of the filtered stream
*/
@Override
public final FList filter(final Closure filterClosure) {
final StreamCore newStream = createNewStream();
filter(this, filterClosure, newStream);
return newStream;
}
private void filter(final StreamCore rest, final Closure filterClosure, final StreamCore result) {
StreamCore recurRest = rest;
StreamCore recurResult = result;
while (true) {
if (recurRest.isEmpty()) {
recurResult.leftShift(StreamCore.eos());
return;
}
final boolean include = (Boolean) eval(filterClosure.call(new Object[]{recurRest.getFirst()}));
if (include) recurResult = recurResult.leftShift(recurRest.getFirst());
recurRest = (StreamCore) recurRest.getRest();
}
}
/**
* Builds a modified stream using the supplied map closure
*
* @param mapClosure The closure to transform elements
* @return The first item of the transformed stream
*/
@Override
public final FList
© 2015 - 2025 Weber Informatics LLC | Privacy Policy