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

java8.util.LBDSpliterator Maven / Gradle / Ivy

Go to download

streamsupport is a backport of the Java 8 java.util.function (functional interfaces) and java.util.stream (streams) API for Java 6 / 7 and Android developers

There is a newer version: 1.7.4
Show newest version
/*
 * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package java8.util;

import java.util.Comparator;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.locks.ReentrantLock;

import java8.util.function.Consumer;

/**
 * A customized variant of Spliterators.IteratorSpliterator for
 * LinkedBlockingDeques.
 * 

* The returned spliterator is weakly consistent. *

* The {@code Spliterator} reports {@link Spliterator#CONCURRENT}, * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}. *

* The {@code Spliterator} implements {@code trySplit} to permit limited * parallelism. * * @param * the type of elements held in the LinkedBlockingDeque */ final class LBDSpliterator implements Spliterator { private static final int MAX_BATCH = 1 << 25; // max batch array size private final LinkedBlockingDeque queue; private final ReentrantLock queueLock; private Object current; // current node; null until initialized private int batch; // batch size for splits private boolean exhausted; // true when no more nodes private long est; // size estimate private LBDSpliterator(LinkedBlockingDeque queue) { this.queue = queue; this.est = queue.size(); this.queueLock = getQueueLock(queue); } static Spliterator spliterator(LinkedBlockingDeque queue) { return new LBDSpliterator(queue); } @Override public int characteristics() { return Spliterator.ORDERED | Spliterator.NONNULL | Spliterator.CONCURRENT; } @Override public long estimateSize() { return est; } @Override public void forEachRemaining(Consumer action) { Objects.requireNonNull(action); LinkedBlockingDeque q = queue; ReentrantLock lock = queueLock; if (!exhausted) { exhausted = true; Object p = current; do { E e = null; lock.lock(); try { if (p == null) { p = getQueueFirst(q); } while (p != null) { e = getNodeItem(p); p = getNextNode(p); if (e != null) { break; } } } finally { lock.unlock(); } if (e != null) { action.accept(e); } } while (p != null); } } @Override public Comparator getComparator() { return Spliterators.getComparator(this); } @Override public long getExactSizeIfKnown() { return Spliterators.getExactSizeIfKnown(this); } @Override public boolean hasCharacteristics(int characteristics) { return Spliterators.hasCharacteristics(this, characteristics); } @Override public boolean tryAdvance(Consumer action) { Objects.requireNonNull(action); LinkedBlockingDeque q = queue; ReentrantLock lock = queueLock; if (!exhausted) { E e = null; lock.lock(); try { if (current == null) { current = getQueueFirst(q); } while (current != null) { e = getNodeItem(current); current = getNextNode(current); if (e != null) { break; } } } finally { lock.unlock(); } if (current == null) { exhausted = true; } if (e != null) { action.accept(e); return true; } } return false; } @Override public Spliterator trySplit() { Object h; LinkedBlockingDeque q = queue; int b = batch; int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1; if (!exhausted && ((h = current) != null || (h = getQueueFirst(q)) != null) && getNextNode(h) != null) { Object[] a = new Object[n]; ReentrantLock lock = queueLock; int i = 0; Object p = current; lock.lock(); try { if (p != null || (p = getQueueFirst(q)) != null) { do { if ((a[i] = getNodeItem(p)) != null) { ++i; } } while ((p = getNextNode(p)) != null && i < n); } } finally { lock.unlock(); } if ((current = p) == null) { est = 0L; exhausted = true; } else if ((est -= i) < 0L) { est = 0L; } if (i > 0) { batch = i; return Spliterators.spliterator(a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL | Spliterator.CONCURRENT); } } return null; } private static ReentrantLock getQueueLock(LinkedBlockingDeque queue) { return (ReentrantLock) U.getObject(queue, LOCK_OFF); } private static Object getQueueFirst(LinkedBlockingDeque queue) { return U.getObject(queue, FIRST_OFF); } /** * Returns node.next as an Object */ private static Object getNextNode(Object node) { return U.getObject(node, NODE_NEXT_OFF); } /** * Returns node.item as a T */ private static T getNodeItem(Object node) { return (T) U.getObject(node, NODE_ITEM_OFF); } // Unsafe mechanics private static final sun.misc.Unsafe U = UnsafeAccess.unsafe; private static final long FIRST_OFF; private static final long LOCK_OFF; private static final long NODE_ITEM_OFF; private static final long NODE_NEXT_OFF; static { try { Class nc = Class .forName("java.util.concurrent.LinkedBlockingDeque$Node"); FIRST_OFF = U.objectFieldOffset(LinkedBlockingDeque.class .getDeclaredField("first")); LOCK_OFF = U.objectFieldOffset(LinkedBlockingDeque.class .getDeclaredField("lock")); NODE_ITEM_OFF = U.objectFieldOffset(nc .getDeclaredField("item")); NODE_NEXT_OFF = U.objectFieldOffset(nc .getDeclaredField("next")); } catch (Exception e) { throw new Error(e); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy