/* * Quasar: lightweight threads and actors for the JVM. * Copyright (c) 2013-2014, 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.fibers.SuspendExecution; import co.paralleluniverse.strands.Timeout; import com.google.common.base.Function; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; /** * Single consumer * * @author pron */ public class ZippingReceivePort<Message> implements ReceivePort<Message> { private final Function<Object[], Message> f; private final ReceivePort<?>[] targets; private Object[] ms; public ZippingReceivePort(Function<Object[], Message> f, ReceivePort<?>... targets) { this(f, Arrays.asList(targets)); } public ZippingReceivePort(Function<Object[], Message> f, List<? extends ReceivePort<?>> targets) { this.f = f; this.targets = targets.toArray(new ReceivePort[targets.size()]); this.ms = new Object[targets.size()]; } public ZippingReceivePort(ReceivePort<?>... targets) { this(null, targets); } public ZippingReceivePort(List<? extends ReceivePort<?>> targets) { this(null, targets); } @Override @SuppressWarnings("empty-statement") public Message receive() throws SuspendExecution, InterruptedException { for (int i = 0; i < targets.length; i++) { if (ms[i] == null) { Object m = targets[i].receive(); if (m == null) // closed return null; ms[i] = m; } } return transformAndReset(); } @Override public Message tryReceive() { for (int i = 0; i < targets.length; i++) { if (ms[i] == null) { Object m = targets[i].tryReceive(); if (m == null) return null; ms[i] = m; } } return transformAndReset(); } @Override public Message receive(long timeout, TimeUnit unit) throws SuspendExecution, InterruptedException { long left = unit.toNanos(timeout); final long deadline = System.nanoTime() + left; for (int i = 0; i < targets.length; i++) { if (ms[i] == null) { Object m = targets[i].receive(left, TimeUnit.NANOSECONDS); if (m == null) return null; ms[i] = m; left = deadline - System.nanoTime(); } } return transformAndReset(); } @Override public Message receive(Timeout timeout) throws SuspendExecution, InterruptedException { return receive(timeout.nanosLeft(), TimeUnit.NANOSECONDS); } private Message transformAndReset() { final Object[] ms1 = copy(ms); Arrays.fill(ms, null); return transform(ms1); } private static Object[] copy(Object[] array) { Object[] array2 = new Object[array.length]; System.arraycopy(array, 0, array2, 0, array.length); return array2; } @Override public void close() { for (ReceivePort<?> c : targets) c.close(); } @Override public boolean isClosed() { for (ReceivePort<?> c : targets) { if (c.isClosed()) return true; } return false; } protected Message transform(Object[] ms) { if (f != null) return f.apply(ms); throw new UnsupportedOperationException(); } }