/* Copyright (c) 2012-2014 Boundless and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Distribution License v1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/edl-v10.html * * Contributors: * Gabriel Roldan (Boundless) - initial implementation */ package org.locationtech.geogig.api; import java.util.Collection; import java.util.Iterator; import java.util.Map; import org.locationtech.geogig.storage.NodeStorageOrder; import org.locationtech.geogig.storage.ObjectDatabase; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.Iterators; /** * */ public abstract class RevTreeImpl extends AbstractRevObject implements RevTree { private static final class LeafTree extends RevTreeImpl { private final Optional<ImmutableList<Node>> features; private final Optional<ImmutableList<Node>> trees; public LeafTree(final ObjectId id, final long size, final Optional<ImmutableList<Node>> features, Optional<ImmutableList<Node>> trees) { super(id, size); this.features = features; this.trees = trees; } @Override public Optional<ImmutableList<Node>> features() { return features; } @Override public Optional<ImmutableList<Node>> trees() { return trees; } @Override public int numTrees() { return trees.isPresent() ? trees.get().size() : 0; } @Override public final boolean isEmpty() { return features.isPresent() ? features.get().isEmpty() : (trees.isPresent() ? trees .get().isEmpty() : true); } } private static final class NodeTree extends RevTreeImpl { private final Optional<ImmutableSortedMap<Integer, Bucket>> buckets; private final int childTreeCount; public NodeTree(final ObjectId id, final long size, final int childTreeCount, final ImmutableSortedMap<Integer, Bucket> innerTrees) { super(id, size); this.childTreeCount = childTreeCount; if (innerTrees.isEmpty()) { this.buckets = Optional.absent(); } else { this.buckets = Optional.of(innerTrees); } } @Override public Optional<ImmutableSortedMap<Integer, Bucket>> buckets() { return buckets; } @Override public final boolean isEmpty() { return buckets().isPresent() ? buckets().get().isEmpty() : true; } @Override public int numTrees() { return childTreeCount; } } private final long size; private RevTreeImpl(ObjectId id, long size) { super(id); this.size = size; } @Override public final long size() { return size; } @Override public Optional<ImmutableList<Node>> features() { return Optional.absent(); } @Override public Optional<ImmutableList<Node>> trees() { return Optional.absent(); } @Override public Optional<ImmutableSortedMap<Integer, Bucket>> buckets() { return Optional.absent(); } public static RevTreeImpl createLeafTree(ObjectId id, long size, ImmutableList<Node> features, ImmutableList<Node> trees) { Preconditions.checkNotNull(id); Preconditions.checkNotNull(features); Preconditions.checkNotNull(trees); Optional<ImmutableList<Node>> f = Optional.absent(); Optional<ImmutableList<Node>> t = Optional.absent(); if (!features.isEmpty()) { f = Optional.of(features); } if (!trees.isEmpty()) { t = Optional.of(trees); } return new LeafTree(id, size, f, t); } private static final NodeStorageOrder ordering = new NodeStorageOrder(); public static RevTreeImpl createLeafTree(ObjectId id, long size, Collection<Node> features, Collection<Node> trees) { Preconditions.checkNotNull(id); Preconditions.checkNotNull(features); ImmutableList<Node> featuresList = ImmutableList.of(); ImmutableList<Node> treesList = ImmutableList.of(); if (!features.isEmpty()) { featuresList = ordering.immutableSortedCopy(features); } if (!trees.isEmpty()) { treesList = ordering.immutableSortedCopy(trees); } return createLeafTree(id, size, featuresList, treesList); } public static RevTreeImpl createNodeTree(final ObjectId id, final long size, final int childTreeCount, final Map<Integer, Bucket> bucketTrees) { Preconditions.checkNotNull(id); Preconditions.checkNotNull(bucketTrees); Preconditions.checkArgument(bucketTrees.size() <= RevTree.MAX_BUCKETS); ImmutableSortedMap<Integer, Bucket> innerTrees = ImmutableSortedMap.copyOf(bucketTrees); return new NodeTree(id, size, childTreeCount, innerTrees); } public static RevTreeImpl create(ObjectId id, long size, RevTree unidentified) { if (unidentified.buckets().isPresent()) { return new NodeTree(id, size, unidentified.numTrees(), unidentified.buckets().get()); } final Optional<ImmutableList<Node>> features; if (unidentified.features().isPresent()) { features = Optional.of(unidentified.features().get()); } else { features = Optional.absent(); } final Optional<ImmutableList<Node>> trees; if (unidentified.trees().isPresent()) { trees = Optional.of(unidentified.trees().get()); } else { trees = Optional.absent(); } return new LeafTree(id, size, features, trees); } @Override public TYPE getType() { return TYPE.TREE; } @Override public RevTreeBuilder builder(ObjectDatabase target) { return new RevTreeBuilder(target, this); } @Override public Iterator<Node> children() { Preconditions.checkState(!buckets().isPresent()); ImmutableList<Node> trees = trees().or(ImmutableList.<Node> of()); ImmutableList<Node> features = features().or(ImmutableList.<Node> of()); if (trees.isEmpty()) { return features.iterator(); } if (features.isEmpty()) { return trees.iterator(); } return Iterators.mergeSorted(ImmutableList.of(trees.iterator(), features.iterator()), ordering); } @Override public String toString() { final int nSubtrees; if (trees().isPresent()) { nSubtrees = trees().get().size(); } else { nSubtrees = 0; } final int nBuckets; if (buckets().isPresent()) { nBuckets = buckets().get().size(); } else { nBuckets = 0; } final int nFeatures; if (features().isPresent()) { nFeatures = features().get().size(); } else { nFeatures = 0; } StringBuilder builder = new StringBuilder(); builder.append("Tree["); builder.append(getId().toString()); builder.append("; size="); builder.append(size); builder.append("; subtrees="); builder.append(nSubtrees); builder.append(", buckets="); builder.append(nBuckets); builder.append(", features="); builder.append(nFeatures); builder.append(']'); return builder.toString(); } }