001/**
002 * The MIT License (MIT)
003 *
004 * Copyright (c) 2019 nobark (tools4j), Marco Terzer, Anton Anufriev
005 *
006 * Permission is hereby granted, free of charge, to any person obtaining a copy
007 * of this software and associated documentation files (the "Software"), to deal
008 * in the Software without restriction, including without limitation the rights
009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
010 * copies of the Software, and to permit persons to whom the Software is
011 * furnished to do so, subject to the following conditions:
012 *
013 * The above copyright notice and this permission notice shall be included in all
014 * copies or substantial portions of the Software.
015 *
016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
022 * SOFTWARE.
023 */
024package org.tools4j.nobark.queue;
025
026import java.util.*;
027import java.util.concurrent.atomic.AtomicReference;
028import java.util.function.Supplier;
029
030/**
031 * Package local immutable wrapper object used by the queue implementations;  holds conflation key and a value.
032 *
033 * @param <K> the conflation key type
034 * @param <V> the value type
035 */
036final class Entry<K,V> {
037    final K key;
038    final AtomicReference<V> value;
039
040    /**
041     * Constructor with conflation key and value
042     *
043     * @param key   the conflation key
044     * @param value the value
045     */
046    Entry(final K key, final V value) {
047        this.key = Objects.requireNonNull(key);
048        this.value = new AtomicReference<>(value);//nulls allowed for value
049    }
050
051    /**
052     * Eagerly initializes a hash map using all provided keys and creating values with the given value factory.
053     *
054     * @param allKeys       a list with all conflation keys
055     * @param valueFactory  the value factory
056     * @param <K> the conflation key type
057     * @param <V> the value type
058     * @return the map initialized with new values for all keys
059     */
060    static <K,V> Map<K,Entry<K,V>> eagerlyInitialiseEntryMap(final List<? extends K> allKeys,
061                                                             final Supplier<V> valueFactory) {
062        final Map<K,Entry<K,V>> entryMap = new HashMap<>((int)Math.ceil(allKeys.size() / 0.75));
063        //NOTE: we intentionally use index here to avoid iterator garbage
064        for (int i = 0; i < allKeys.size(); i++) {
065            final K key = allKeys.get(i);
066            entryMap.put(key, new Entry<>(key, valueFactory.get()));
067        }
068        return entryMap;
069    }
070
071    /**
072     * Eagerly initializes an enum map using all enum constants as keys and creating values with the given value factory.
073     *
074     * @param keyClass      the enum key class
075     * @param valueFactory  the value factory
076     * @param <K> the conflation key type
077     * @param <V> the value type
078     * @return the enum map initialized with new values for all key constants
079     */
080    static <K extends Enum<K>,V> Map<K,Entry<K,V>> eagerlyInitialiseEntryEnumMap(final Class<K> keyClass,
081                                                                                 final Supplier<V> valueFactory) {
082        final EnumMap<K, Entry<K,V>> entryMap = new EnumMap<>(keyClass);
083        //NOTE: we create garbage when getting enum constants, but escape analysis most likely eliminates this
084        for (final K key : keyClass.getEnumConstants()) {
085            entryMap.put(key, new Entry<>(key, valueFactory.get()));
086        }
087        return entryMap;
088    }
089}