co.paralleluniverse.strands.channels.ReducingSendPort Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of quasar-core Show documentation
Show all versions of quasar-core Show documentation
Fibers, Channels and Actors for the JVM
The newest version!
/*
* Quasar: lightweight threads and actors for the JVM.
* Copyright (c) 2013-2015, Parallel Universe Software Co. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 3.0
* as published by the Free Software Foundation.
*/
package co.paralleluniverse.strands.channels;
import co.paralleluniverse.common.util.Function2;
import co.paralleluniverse.fibers.DefaultFiberScheduler;
import co.paralleluniverse.fibers.SuspendExecution;
import co.paralleluniverse.strands.StrandFactory;
import co.paralleluniverse.strands.SuspendableRunnable;
import co.paralleluniverse.strands.SuspendableUtils;
import co.paralleluniverse.strands.Timeout;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* A transforming {@link SendPort} that will apply a reduction function to values.
*
* @author circlespainter
*/
class ReducingSendPort extends SendPortTransformer {
private static final StrandFactory strandFactoryDefault = DefaultFiberScheduler.getInstance();
private final Function2 f;
private final AtomicBoolean closedBeforeFirstSend = new AtomicBoolean(true);
private final AtomicBoolean closing = new AtomicBoolean(false);
private final StrandFactory strandFactory;
private T prev;
public ReducingSendPort(final SendPort target, final Function2 f, final T init, final StrandFactory strandFactory) {
super(target);
this.f = f;
this.prev = init;
this.strandFactory = strandFactory;
}
public ReducingSendPort(final SendPort target, final Function2 f, final T init) {
this(target, f, init, strandFactoryDefault);
}
@Override
public void close(final Throwable t) {
if (!closing.getAndSet(true)) {
if (closedBeforeFirstSend.get()) {
strandFactory.newStrand(SuspendableUtils.runnableToCallable(new SuspendableRunnable() {
@Override
public void run() throws SuspendExecution, InterruptedException {
target.send(prev);
superClose(t);
}
})).start();
} else {
superClose(t);
}
}
}
private void superClose(final Throwable t) {
if (t != null)
super.close(t);
else
super.close();
}
@Override
public void close() {
close(null);
}
@Override
public boolean trySend(final S message) {
closedBeforeFirstSend.set(false);
return super.trySend(message);
}
@Override
public boolean send(final S message, final Timeout timeout) throws SuspendExecution, InterruptedException {
closedBeforeFirstSend.set(false);
return super.send(message, timeout);
}
@Override
public boolean send(final S message, final long timeout, final TimeUnit unit) throws SuspendExecution, InterruptedException {
closedBeforeFirstSend.set(false);
return super.send(message, timeout, unit);
}
@Override
public void send(final S message) throws SuspendExecution, InterruptedException {
closedBeforeFirstSend.set(false);
super.send(message);
}
@Override
protected T transform(final S m) {
return (this.prev = reduce(prev, m));
}
private T reduce(final T prev, final S m) {
if (f != null && prev != null)
return f.apply(prev, m);
throw new UnsupportedOperationException();
}
}