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

java8.util.HMSpliterators 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

The newest version!
/*
 * Copyright (c) 2012, 2018, 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.Collection;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import java8.util.function.Consumer;

final class HMSpliterators {
// CVS rev. 1.10

    private HMSpliterators() {
    }

    static  Spliterator getKeySetSpliterator(Set keySet) {
        return new KeySpliterator(getHashMapFromKeySet(keySet), 0,
                -1, 0, 0);
    }

    static  Spliterator> getEntrySetSpliterator(
            Set> entrySet) {
        return new EntrySpliterator(getHashMapFromEntrySet(entrySet), 0,
                -1, 0, 0);
    }

    static  Spliterator getValuesSpliterator(Collection values) {
        return new ValueSpliterator(getHashMapFromValues(values), 0,
                -1, 0, 0);
    }

    static  Spliterator getHashSetSpliterator(HashSet hashSet) {
        return new KeySpliterator(getHashMapFromHashSet(hashSet), 0,
                -1, 0, 0);
    }

    private static final class KeySpliterator extends
            HashMapSpliterator implements Spliterator {

        KeySpliterator(HashMap m, int origin, int fence, int est,
                int expectedModCount) {
            super(m, origin, fence, est, expectedModCount);
        }

        @Override
        public KeySpliterator trySplit() {
            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
            return (lo >= mid || current != null) ? null
                    : new KeySpliterator(map, lo, index = mid,
                            est >>>= 1, expectedModCount);
        }

        @Override
        public void forEachRemaining(Consumer action) {
            Objects.requireNonNull(action);
            int i, hi, mc;
            HashMap m = map;
            Object[] tab = getTable(m);
            if ((hi = fence) < 0) {
                mc = expectedModCount = getModCount(m);
                hi = fence = (tab == null) ? 0 : tab.length;
            } else {
                mc = expectedModCount;
            }
            if (tab != null && tab.length >= hi && (i = index) >= 0
                    && (i < (index = hi) || current != null)) {
                Object p = current;
                current = null;
                do {
                    if (p == null) {
                        p = tab[i++];
                    } else {
                        action.accept(HashMapSpliterator. getNodeKey(p));
                        p = getNextNode(p);
                    }
                } while (p != null || i < hi);
                if (mc != getModCount(m)) {
                    throw new ConcurrentModificationException();
                }
            }
        }

        @Override
        public boolean tryAdvance(Consumer action) {
            Objects.requireNonNull(action);
            int hi;
            Object[] tab = getTable(map);
            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
                while (current != null || index < hi) {
                    if (current == null) {
                        current = tab[index++];
                    } else {
                        K k = getNodeKey(current);
                        current = getNextNode(current);
                        action.accept(k);
                        if (expectedModCount != getModCount(map)) {
                            throw new ConcurrentModificationException();
                        }
                        return true;
                    }
                }
            }
            return false;
        }

        @Override
        public int characteristics() {
            return (fence < 0 || est == map.size() ? Spliterator.SIZED : 0)
                    | Spliterator.DISTINCT;
        }

        @Override
        public Comparator getComparator() {
            return Spliterators.getComparator(null);
        }
    }

    private static final class ValueSpliterator extends
            HashMapSpliterator implements Spliterator {

        ValueSpliterator(HashMap m, int origin, int fence,
                int est, int expectedModCount) {
            super(m, origin, fence, est, expectedModCount);
        }

        @Override
        public ValueSpliterator trySplit() {
            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
            return (lo >= mid || current != null) ? null
                    : new ValueSpliterator(map, lo, index = mid,
                            est >>>= 1, expectedModCount);
        }

        @Override
        public void forEachRemaining(Consumer action) {
            Objects.requireNonNull(action);
            int i, hi, mc;
            HashMap m = map;
            Object[] tab = getTable(m);
            if ((hi = fence) < 0) {
                mc = expectedModCount = getModCount(m);
                hi = fence = (tab == null) ? 0 : tab.length;
            } else {
                mc = expectedModCount;
            }
            if (tab != null && tab.length >= hi && (i = index) >= 0
                    && (i < (index = hi) || current != null)) {
                Object p = current;
                current = null;
                do {
                    if (p == null) {
                        p = tab[i++];
                    } else {
                        action.accept(HashMapSpliterator. getNodeValue(p));
                        p = getNextNode(p);
                    }
                } while (p != null || i < hi);
                if (mc != getModCount(m)) {
                    throw new ConcurrentModificationException();
                }
            }
        }

        @Override
        public boolean tryAdvance(Consumer action) {
            Objects.requireNonNull(action);
            int hi;
            Object[] tab = getTable(map);
            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
                while (current != null || index < hi) {
                    if (current == null) {
                        current = tab[index++];
                    } else {
                        V v = getNodeValue(current);
                        current = getNextNode(current);
                        action.accept(v);
                        if (expectedModCount != getModCount(map)) {
                            throw new ConcurrentModificationException();
                        }
                        return true;
                    }
                }
            }
            return false;
        }

        @Override
        public int characteristics() {
            return (fence < 0 || est == map.size() ? Spliterator.SIZED : 0);
        }

        @Override
        public Comparator getComparator() {
            return Spliterators.getComparator(null);
        }
    }

    private static final class EntrySpliterator extends
            HashMapSpliterator implements Spliterator> {

        EntrySpliterator(HashMap m, int origin, int fence,
                int est, int expectedModCount) {
            super(m, origin, fence, est, expectedModCount);
        }

        @Override
        public EntrySpliterator trySplit() {
            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
            return (lo >= mid || current != null) ? null
                    : new EntrySpliterator(map, lo, index = mid,
                            est >>>= 1, expectedModCount);
        }

        @Override
        public void forEachRemaining(Consumer> action) {
            Objects.requireNonNull(action);
            int i, hi, mc;
            HashMap m = map;
            Object[] tab = getTable(m);
            if ((hi = fence) < 0) {
                mc = expectedModCount = getModCount(m);
                hi = fence = (tab == null) ? 0 : tab.length;
            } else {
                mc = expectedModCount;
            }
            if (tab != null && tab.length >= hi && (i = index) >= 0
                    && (i < (index = hi) || current != null)) {
                Object p = current;
                current = null;
                do {
                    if (p == null) {
                        p = tab[i++];
                    } else {
                        action.accept((Map.Entry) p);
                        p = getNextNode(p);
                    }
                } while (p != null || i < hi);
                if (mc != getModCount(m)) {
                    throw new ConcurrentModificationException();
                }
            }
        }

        @Override
        public boolean tryAdvance(Consumer> action) {
            Objects.requireNonNull(action);
            int hi;
            Object[] tab = getTable(map);
            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
                while (current != null || index < hi) {
                    if (current == null) {
                        current = tab[index++];
                    } else {
                        Map.Entry e = (Map.Entry) current;
                        current = getNextNode(current);
                        action.accept(e);
                        if (expectedModCount != getModCount(map)) {
                            throw new ConcurrentModificationException();
                        }
                        return true;
                    }
                }
            }
            return false;
        }

        @Override
        public int characteristics() {
            return (fence < 0 || est == map.size() ? Spliterator.SIZED : 0)
                    | Spliterator.DISTINCT;
        }

        @Override
        public Comparator> getComparator() {
            return Spliterators.getComparator(null);
        }
    }

    private static abstract class HashMapSpliterator {
        final HashMap map;
        Object current; // current node
        int index; // current index, modified on advance/split
        int fence; // one past last index
        int est; // size estimate
        int expectedModCount; // for co-modification checks

        HashMapSpliterator(HashMap m, int origin, int fence, int est,
                int expectedModCount) {
            this.map = m;
            this.index = origin;
            this.fence = fence;
            this.est = est;
            this.expectedModCount = expectedModCount;
        }

        final int getFence() { // initialize fence and size on first use
            int hi;
            if ((hi = fence) < 0) {
                HashMap m = map;
                est = m.size();
                expectedModCount = getModCount(m);
                Object[] tab = getTable(m);
                hi = fence = (tab == null) ? 0 : tab.length;
            }
            return hi;
        }

        public abstract int characteristics();

        public final long getExactSizeIfKnown() {
            return Spliterators.getExactSizeIfKnown((Spliterator) this);
        }

        public final boolean hasCharacteristics(int characteristics) {
            return Spliterators.hasCharacteristics((Spliterator) this,
                    characteristics);
        }

        public final long estimateSize() {
            getFence(); // force init
            return (long) est;
        }

        static int getModCount(HashMap map) {
            return U.getInt(map, MODCOUNT_OFF);
        }

        static Object[] getTable(HashMap map) {
            return (Object[]) U.getObject(map, TABLE_OFF);
        }

        static  K getNodeKey(Object node) {
            return (K) U.getObject(node, NODE_KEY_OFF);
        }

        static  T getNodeValue(Object node) {
            return (T) U.getObject(node, NODE_VAL_OFF);
        }

        static Object getNextNode(Object node) {
            return U.getObject(node, NODE_NXT_OFF);
        }

        static Class nodeClass() throws ClassNotFoundException {
            String nodeName = new StringBuilder("java.util.HashMap$")
                    .append((Spliterators.IS_ANDROID || Spliterators.HAS_STREAMS) ? "Node"
                            : "Entry").toString();
            try {
                return Class.forName(nodeName);
            } catch (ClassNotFoundException e) {
                // we might be running on the first Nougat release
                // (or even on one of the Android N developer previews)
                if (Spliterators.IS_ANDROID) {
                    return Class.forName("java.util.HashMap$HashMapEntry");
                }
                throw e;
            }
        }

        // Unsafe mechanics
        private static final sun.misc.Unsafe U = UnsafeAccess.unsafe;
        private static final long TABLE_OFF;
        private static final long MODCOUNT_OFF;
        private static final long NODE_KEY_OFF;
        private static final long NODE_VAL_OFF;
        private static final long NODE_NXT_OFF;
        static {
            try {
                TABLE_OFF = U.objectFieldOffset(HashMap.class
                        .getDeclaredField("table"));
                MODCOUNT_OFF = U.objectFieldOffset(HashMap.class
                        .getDeclaredField("modCount"));
                Class nc = nodeClass();
                NODE_KEY_OFF = U.objectFieldOffset(nc
                        .getDeclaredField("key"));
                NODE_VAL_OFF = U.objectFieldOffset(nc
                        .getDeclaredField("value"));
                NODE_NXT_OFF = U.objectFieldOffset(nc
                        .getDeclaredField("next"));
            } catch (Exception e) {
                throw new Error(e);
            }
        }
    }

    private static  HashMap getHashMapFromKeySet(Set keySet) {
        return (HashMap) U.getObject(keySet, KEYSET_$0_OFF);
    }

    private static  HashMap getHashMapFromEntrySet(
            Set> entrySet) {
        return (HashMap) U.getObject(entrySet, ENTRYSET_$0_OFF);
    }

    private static  HashMap getHashMapFromValues(
            Collection values) {
        return (HashMap) U.getObject(values, VALUES_$0_OFF);
    }

    private static  HashMap getHashMapFromHashSet(HashSet hashSet) {
        return (HashMap) U.getObject(hashSet, HASHSET_MAP_OFF);
    }

    // Unsafe mechanics
    private static final sun.misc.Unsafe U = UnsafeAccess.unsafe;
    private static final long VALUES_$0_OFF;
    private static final long KEYSET_$0_OFF;
    private static final long ENTRYSET_$0_OFF;
    private static final long HASHSET_MAP_OFF;
    static {
        try {
            Class vc = Class.forName("java.util.HashMap$Values");
            Class ksc = Class.forName("java.util.HashMap$KeySet");
            Class esc = Class.forName("java.util.HashMap$EntrySet");
            VALUES_$0_OFF = U.objectFieldOffset(vc
                    .getDeclaredField("this$0"));
            KEYSET_$0_OFF = U.objectFieldOffset(ksc
                    .getDeclaredField("this$0"));
            ENTRYSET_$0_OFF = U.objectFieldOffset(esc
                    .getDeclaredField("this$0"));
            HASHSET_MAP_OFF = U.objectFieldOffset(HashSet.class
                    .getDeclaredField("map"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy