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

org.opendaylight.yangtools.util.SharedSingletonMap Maven / Gradle / Ivy

There is a newer version: 14.0.4
Show newest version
/*
 * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.yangtools.util;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;

import com.google.common.annotations.Beta;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import java.io.Serializable;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNull;

/**
 * Implementation of the {@link Map} interface which stores a single mapping. The key set is shared among all instances
 * which contain the same key. This implementation does not support null keys or values.
 *
 * 

* In case the set of keys is statically known, you can use {@link SharedSingletonMapTemplate} to efficiently create * {@link SharedSingletonMap} instances. * * @param the type of keys maintained by this map * @param the type of mapped values */ @Beta public abstract class SharedSingletonMap implements Serializable, UnmodifiableMapPhase { static final class Ordered extends SharedSingletonMap { private static final long serialVersionUID = 1L; Ordered(final K key, final V value) { super(key, value); } Ordered(final SingletonSet keySet, final V value) { super(keySet, value); } @Override public @NonNull ModifiableMapPhase toModifiableMap() { return MutableOffsetMap.orderedCopyOf(this); } } static final class Unordered extends SharedSingletonMap { private static final long serialVersionUID = 1L; Unordered(final K key, final V value) { super(key, value); } Unordered(final SingletonSet keySet, final V value) { super(keySet, value); } @Override public @NonNull ModifiableMapPhase toModifiableMap() { return MutableOffsetMap.unorderedCopyOf(this); } } private static final long serialVersionUID = 1L; private static final LoadingCache> CACHE = CacheBuilder.newBuilder().weakValues() .build(new CacheLoader>() { @Override public SingletonSet load(final Object key) { return SingletonSet.of(key); } }); private final @NonNull SingletonSet keySet; private final @NonNull V value; private int hashCode; SharedSingletonMap(final SingletonSet keySet, final V value) { this.keySet = requireNonNull(keySet); this.value = requireNonNull(value); } SharedSingletonMap(final K key, final V value) { this(cachedSet(key), value); } /** * Create a {@link SharedSingletonMap} of specified {@code key} and {@code value}, which retains insertion order * when transformed via {@link #toModifiableMap()}. * * @param key key * @param value value * @return A SharedSingletonMap * @throws NullPointerException if any of the arguments is null */ public static @NonNull SharedSingletonMap orderedOf(final K key, final V value) { return new Ordered<>(key, value); } /** * Create a {@link SharedSingletonMap} of specified {@code key} and {@code value}, which does not retain insertion * order when transformed via {@link #toModifiableMap()}. * * @param key key * @param value value * @return A SharedSingletonMap * @throws NullPointerException if any of the arguments is null */ public static @NonNull SharedSingletonMap unorderedOf(final K key, final V value) { return new Unordered<>(key, value); } /** * Create a {@link SharedSingletonMap} of specified {@code key} and {@code value}, which retains insertion order * when transformed via {@link #toModifiableMap()}. * * @param map input map * @return A SharedSingletonMap * @throws NullPointerException if {@code map} is null * @throws IllegalArgumentException if {@code map} does not have exactly one entry */ public static @NonNull SharedSingletonMap orderedCopyOf(final Map map) { final Entry e = singleEntry(map); return new Ordered<>(e.getKey(), e.getValue()); } /** * Create a {@link SharedSingletonMap} from specified single-element map, which does not retain insertion order when * transformed via {@link #toModifiableMap()}. * * @param map input map * @return A SharedSingletonMap * @throws NullPointerException if {@code map} is null * @throws IllegalArgumentException if {@code map} does not have exactly one entry */ public static @NonNull SharedSingletonMap unorderedCopyOf(final Map map) { final Entry e = singleEntry(map); return new Unordered<>(e.getKey(), e.getValue()); } public final Entry getEntry() { return new SimpleImmutableEntry<>(keySet.getElement(), value); } @Override public final @NonNull SingletonSet> entrySet() { return SingletonSet.of(getEntry()); } @Override public final @NonNull SingletonSet keySet() { return keySet; } @Override public final @NonNull SingletonSet values() { return SingletonSet.of(value); } @Override public final boolean containsKey(final Object key) { return keySet.contains(key); } @Override @SuppressWarnings("checkstyle:hiddenField") public final boolean containsValue(final Object value) { return this.value.equals(value); } @Override public final V get(final Object key) { return keySet.contains(key) ? value : null; } @Override public final int size() { return 1; } @Override public final boolean isEmpty() { return false; } @Override @SuppressWarnings("checkstyle:hiddenField") public final V put(final K key, final V value) { throw new UnsupportedOperationException(); } @Override public final V remove(final Object key) { throw new UnsupportedOperationException(); } @Override @SuppressWarnings("checkstyle:parameterName") public final void putAll(final Map m) { throw new UnsupportedOperationException(); } @Override public final void clear() { throw new UnsupportedOperationException(); } @Override public final int hashCode() { if (hashCode == 0) { hashCode = keySet.getElement().hashCode() ^ value.hashCode(); } return hashCode; } @Override public final boolean equals(final Object obj) { if (this == obj) { return true; } if (!(obj instanceof Map)) { return false; } final Map m = (Map)obj; return m.size() == 1 && value.equals(m.get(keySet.getElement())); } @Override public final String toString() { return "{" + keySet.getElement() + '=' + value + '}'; } @SuppressWarnings("unchecked") static @NonNull SingletonSet cachedSet(final K key) { return (SingletonSet) CACHE.getUnchecked(key); } private static Entry singleEntry(final Map map) { final Iterator> it = map.entrySet().iterator(); checkArgument(it.hasNext(), "Input map is empty"); final Entry ret = it.next(); checkArgument(!it.hasNext(), "Input map has more than one entry"); return ret; } }