/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * 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,
*/
package org.opendaylight.yangtools.yang.data.api.schema.tree.spi;
-import com.google.common.base.Optional;
-import com.google.common.collect.Maps;
-import java.util.Collection;
-import java.util.HashMap;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.collect.Collections2;
import java.util.Map;
+import org.opendaylight.yangtools.util.MapAdaptor;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
-final class LazyContainerNode extends ContainerNode {
- protected LazyContainerNode(final NormalizedNode<?, ?> data, final Version version) {
- super(data, version, version);
+/**
+ * Lazily-materialized container node. Any new/modified children are tracked in a map. This map is consulted before
+ * instantiating a child node from data node. Resulting node is not cached.
+ */
+final class LazyContainerNode extends AbstractModifiedContainerNode {
+ LazyContainerNode(final NormalizedNode<?, ?> data, final Version version, final Version subtreeVersion) {
+ this(data, version, MapAdaptor.getDefaultInstance().initialSnapshot(1), subtreeVersion);
}
- @Override
- public Optional<TreeNode> getChild(final PathArgument key) {
- // We do not cache the instantiated node as it is dirt cheap
- final Optional<NormalizedNode<?, ?>> child = castData().getChild(key);
- if (child.isPresent()) {
- return Optional.of(TreeNodeFactory.createTreeNode(child.get(), getVersion()));
- }
-
- return Optional.absent();
- }
-
- // Assumes default load factor of 0.75 and capacity of 16.
- private static <K, V> Map<K, V> allocateMap(final int hint) {
- switch (hint) {
- case 0:
- case 1:
- // Zero does not matter, but will be kept small if it is touched in the future
- return new HashMap<>(1);
- case 2:
- // Two entries, may end up being grown to 4
- return new HashMap<>(2);
- case 3:
- // 4 * 0.75 = 3
- return new HashMap<>(4);
- case 4:
- case 5:
- case 6:
- // 8 * 0.75 = 6
- return new HashMap<>(8);
- default:
- // No savings, defer to Guava
- return Maps.newHashMapWithExpectedSize(hint);
- }
+ LazyContainerNode(final NormalizedNode<?, ?> data, final Version version,
+ final Map<PathArgument, TreeNode> children, final Version subtreeVersion) {
+ super(data, version, children, subtreeVersion);
}
@Override
public MutableTreeNode mutable() {
- /*
- * We are creating a mutable view of the data, which means that the version
- * is going to probably change -- and we need to make sure any unmodified
- * children retain it.
- *
- * The simplest thing to do is to just flush the amortized work and be done
- * with it.
- */
- final Collection<NormalizedNode<?, ?>> oldChildren = castData().getValue();
-
- // Use a proper sizing hint here, as the default size can suck for both extremely large and extremely small
- // collections. For the large ones we end up rehashing the table, for small ones we end up using more space
- // than necessary.
- final Map<PathArgument, TreeNode> children = allocateMap(oldChildren.size());
- for (NormalizedNode<?, ?> child : oldChildren) {
- PathArgument id = child.getIdentifier();
- children.put(id, TreeNodeFactory.createTreeNode(child, getVersion()));
+ final Map<PathArgument, TreeNode> snapshot = snapshotChildren();
+ if (snapshot.size() == castData().size()) {
+ return new MaterializedMutableContainerNode(this, snapshot);
}
+ return new LazyMutableContainerNode(this, snapshot);
+ }
- return new Mutable(this, children);
+ @Override
+ public TreeNode childByArg(final PathArgument arg) {
+ final TreeNode modified;
+ return (modified = getModifiedChild(arg)) == null ? getChildFromData(arg) : modified;
}
- @SuppressWarnings("unchecked")
- private NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> castData() {
- return (NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>>) getData();
+ @Override
+ protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+ // Modified children add added by superclass. Here we filter the other children.
+ return super.addToStringAttributes(helper).add("untouched", Collections2.filter(castData().getValue(),
+ input -> getModifiedChild(input.getIdentifier()) == null));
}
}