/*
* Copyright (c) 2014 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.yang.data.impl.schema.nodes;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
/**
* Internal equivalent of {@link Collections}' unmodifiable Map. It does not retain
* keySet/entrySet references, thus lowering the memory overhead.
*/
final class UnmodifiableChildrenMap implements CloneableMap<PathArgument, DataContainerChild<? extends PathArgument, ?>>, Serializable {
private static final long serialVersionUID = 1L;
/*
* Do not wrap maps which are smaller than this and instead copy them into
* an ImmutableMap.
*/
private static final int WRAP_THRESHOLD = 9;
private final Map<PathArgument, DataContainerChild<? extends PathArgument, ?>> delegate;
private transient Collection<DataContainerChild<? extends PathArgument, ?>> values;
private UnmodifiableChildrenMap(final Map<PathArgument, DataContainerChild<? extends PathArgument, ?>> delegate) {
this.delegate = Preconditions.checkNotNull(delegate);
}
/**
* Create an unmodifiable view of a particular map. Does not perform unnecessary
* encapsulation if the map is known to be already unmodifiable.
*
* @param map Backing map
* @return Unmodifiable view
*/
static Map<PathArgument, DataContainerChild<? extends PathArgument, ?>> create(final Map<PathArgument, DataContainerChild<? extends PathArgument, ?>> map) {
if (map instanceof UnmodifiableChildrenMap) {
return map;
}
if (map instanceof ImmutableMap) {
return map;
}
if (map.isEmpty()) {
return ImmutableMap.of();
}
if (map.size() < WRAP_THRESHOLD) {
return ImmutableMap.copyOf(map);
}
return new UnmodifiableChildrenMap(map);
}
@Override
public int size() {
return delegate.size();
}
@Override
public boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public boolean containsKey(final Object key) {
return delegate.containsKey(key);
}
@Override
public boolean containsValue(final Object value) {
return delegate.containsValue(value);
}
@Override
public DataContainerChild<? extends PathArgument, ?> get(final Object key) {
return delegate.get(key);
}
@Override
public DataContainerChild<? extends PathArgument, ?> put(final PathArgument key,
final DataContainerChild<? extends PathArgument, ?> value) {
throw new UnsupportedOperationException();
}
@Override
public DataContainerChild<? extends PathArgument, ?> remove(final Object key) {
throw new UnsupportedOperationException();
}
@Override
public void putAll(@Nonnull final Map<? extends PathArgument, ? extends DataContainerChild<? extends PathArgument, ?>> m) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public Set<PathArgument> keySet() {
return Collections.unmodifiableSet(delegate.keySet());
}
@Nonnull
@Override
public Collection<DataContainerChild<? extends PathArgument, ?>> values() {
if (values == null) {
values = Collections.unmodifiableCollection(delegate.values());
}
return values;
}
@Override
public Set<Entry<PathArgument, DataContainerChild<? extends PathArgument, ?>>> entrySet() {
/*
* Okay, this is not as efficient as it could be -- we could save ourselves the
* map instantiation. The cost of that would be re-implementation of a read-only
* Map.Entry to ensure our delegate is never modified.
*
* Let's skip that and use whatever the JRE gives us instead.
*/
return Collections.unmodifiableMap(delegate).entrySet();
}
@Override
public boolean equals(final Object o) {
return this == o || delegate.equals(o);
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public String toString() {
return delegate.toString();
}
@Override
@SuppressWarnings("unchecked")
public Map<PathArgument, DataContainerChild<? extends PathArgument, ?>> createMutableClone() {
if (delegate instanceof HashMap) {
return (Map<PathArgument, DataContainerChild<? extends PathArgument, ?>>) ((HashMap<?, ?>) delegate).clone();
}
return new HashMap<>(delegate);
}
}