001/*
002 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.compiler.common;
024
025import static com.oracle.graal.compiler.common.CollectionsFactory.Mode.*;
026
027import java.util.*;
028
029/**
030 * Factory for creating collection objects used during compilation.
031 */
032public class CollectionsFactory {
033
034    private static final ThreadLocal<Mode> tl = new ThreadLocal<>();
035
036    public static class ModeScope implements AutoCloseable {
037        private final Mode previousMode;
038
039        public ModeScope(Mode previousMode) {
040            this.previousMode = previousMode;
041        }
042
043        public void close() {
044            tl.set(previousMode);
045        }
046    }
047
048    /**
049     * Constants denoting what type of collections are {@link CollectionsFactory#getMode()
050     * currently} returned by the factory.
051     */
052    public enum Mode {
053        /**
054         * Denotes standard collections such as {@link HashSet} and {@link HashMap}.
055         */
056        STANDARD,
057
058        /**
059         * Denotes collections that have a deterministic iteration order over their keys/entries.
060         */
061        DETERMINISTIC_ITERATION_ORDER;
062    }
063
064    /**
065     * Gets the current mode determining the type of collection objects created by this factory.
066     */
067    public static Mode getMode() {
068        Mode mode = tl.get();
069        return mode == null ? Mode.STANDARD : mode;
070    }
071
072    /**
073     * Updates the mode for the current thread.
074     *
075     * @return an object which when {@linkplain ModeScope#close() closed} will revert the mode of
076     *         the current thread to the state before calling this method
077     */
078    public static ModeScope changeMode(Mode mode) {
079        Mode previousMode = tl.get();
080        tl.set(mode);
081        return new ModeScope(previousMode);
082    }
083
084    public static <K, V> HashMap<K, V> newMap() {
085        return getMode() == STANDARD ? new HashMap<>() : new LinkedHashMap<>();
086    }
087
088    public static <K, V> HashMap<K, V> newMap(Map<K, V> m) {
089        return getMode() == STANDARD ? new HashMap<>(m) : new LinkedHashMap<>(m);
090    }
091
092    public static <K, V> HashMap<K, V> newMap(int initialCapacity) {
093        return getMode() == STANDARD ? new HashMap<>(initialCapacity) : new LinkedHashMap<>(initialCapacity);
094    }
095
096    public static <K, V> Map<K, V> newIdentityMap() {
097        return getMode() == STANDARD ? new IdentityHashMap<>() : new LinkedIdentityHashMap<>();
098    }
099
100    public static <K, V> Map<K, V> newIdentityMap(int expectedMaxSize) {
101        return getMode() == STANDARD ? new IdentityHashMap<>(expectedMaxSize) : new LinkedIdentityHashMap<>();
102    }
103
104    public static <K, V> Map<K, V> newIdentityMap(Map<K, V> m) {
105        return getMode() == STANDARD ? new IdentityHashMap<>(m) : new LinkedIdentityHashMap<>(m);
106    }
107
108    /**
109     * Creates a set. If the current thread is {@linkplain CollectionsFactory#getMode() using}
110     * {@link Mode#DETERMINISTIC_ITERATION_ORDER} collections, the returned set will have an
111     * iteration order determined by the order in which elements are inserted in the set.
112     */
113    public static <E> Set<E> newSet() {
114        return CollectionsFactory.getMode() == Mode.STANDARD ? new HashSet<>() : new LinkedHashSet<>();
115    }
116
117    /**
118     * @see #newSet()
119     */
120    public static <E> Set<E> newSet(Collection<? extends E> c) {
121        return CollectionsFactory.getMode() == Mode.STANDARD ? new HashSet<>(c) : new LinkedHashSet<>(c);
122    }
123
124}