Package org.tmatesoft.hg.internal

Source Code of org.tmatesoft.hg.internal.RevisionSet

/*
* Copyright (c) 2013 TMate Software Ltd
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* For information on how to redistribute this software under
* the terms of a license other than GNU General Public License
* contact TMate Software at support@hg4j.com
*/
package org.tmatesoft.hg.internal;

import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.tmatesoft.hg.core.Nodeid;
import org.tmatesoft.hg.repo.HgChangelog;
import org.tmatesoft.hg.repo.HgParentChildMap;
import org.tmatesoft.hg.repo.HgRepository;

/**
* Unmodifiable collection of revisions with handy set operations
*
* @author Artem Tikhomirov
* @author TMate Software Ltd.
*/
public final class RevisionSet implements Iterable<Nodeid> {
 
  private final Set<Nodeid> elements;
 
  public RevisionSet(Nodeid... revisions) {
    this(revisions == null ? null : Arrays.asList(revisions));
  }
 
  public RevisionSet(Collection<Nodeid> revisions) {
    this(revisions == null ? new HashSet<Nodeid>() : new HashSet<Nodeid>(revisions));
  }
 
  private RevisionSet(HashSet<Nodeid> revisions) {
    if (revisions.isEmpty()) {
      elements = Collections.<Nodeid>emptySet();
    } else {
      elements = revisions;
    }
  }

  /**
   * elements of the set with no parents or parents not from the same set
   */
  public RevisionSet roots(HgParentChildMap<HgChangelog> ph) {
    HashSet<Nodeid> copy = new HashSet<Nodeid>(elements);
    for (Nodeid n : elements) {
      assert ph.knownNode(n);
      Nodeid p1 = ph.firstParent(n);
      if (p1 != null && elements.contains(p1)) {
        copy.remove(n);
        continue;
      }
      Nodeid p2 = ph.secondParent(n);
      if (p2 != null && elements.contains(p2)) {
        copy.remove(n);
        continue;
      }
    }
    return copy.size() == elements.size() ? this : new RevisionSet(copy);
  }
 
  /**
   * Same as {@link #roots(HgParentChildMap)}, but doesn't require a parent-child map
   */
  public RevisionSet roots(HgRepository repo) {
    // TODO introduce parent access interface, use it here, provide implementations
    // that delegate to HgParentChildMap or HgRepository
    HashSet<Nodeid> copy = new HashSet<Nodeid>(elements);
    final HgChangelog clog = repo.getChangelog();
    byte[] parent1 = new byte[Nodeid.SIZE], parent2 = new byte[Nodeid.SIZE];
    int[] parentRevs = new int[2];
    for (Nodeid n : elements) {
      assert clog.isKnown(n);
      clog.parents(clog.getRevisionIndex(n), parentRevs, parent1, parent2);
      if (parentRevs[0] != NO_REVISION && elements.contains(new Nodeid(parent1, false))) {
        copy.remove(n);
        continue;
      }
      if (parentRevs[1] != NO_REVISION && elements.contains(new Nodeid(parent2, false))) {
        copy.remove(n);
        continue;
      }
    }
    return copy.size() == elements.size() ? this : new RevisionSet(copy);
  }
 
  /**
   * elements of the set that has no children in this set
   */
  public RevisionSet heads(HgParentChildMap<HgChangelog> ph) {
    HashSet<Nodeid> copy = new HashSet<Nodeid>(elements);
    // can't do copy.removeAll(ph.childrenOf(asList())); as actual heads are indeed children of some other node
    for (Nodeid n : elements) {
      assert ph.knownNode(n);
      Nodeid p1 = ph.firstParent(n);
      Nodeid p2 = ph.secondParent(n);
      if (p1 != null && elements.contains(p1)) {
        copy.remove(p1);
      }
      if (p2 != null && elements.contains(p2)) {
        copy.remove(p2);
      }
    }
    return copy.size() == elements.size() ? this : new RevisionSet(copy);
  }

  /**
   * Any ancestor of an element from the supplied child set found in this one.
   * Elements of the supplied child set are not part of return value. 
   */
  public RevisionSet ancestors(RevisionSet children, HgParentChildMap<HgChangelog> parentHelper) {
    if (isEmpty()) {
      return this;
    }
    if (children.isEmpty()) {
      return children;
    }
    RevisionSet chRoots = children.roots(parentHelper);
    HashSet<Nodeid> ancestors = new HashSet<Nodeid>();
    Set<Nodeid> childrenToCheck = chRoots.elements;
    while (!childrenToCheck.isEmpty()) {
      HashSet<Nodeid> nextRound = new HashSet<Nodeid>();
      for (Nodeid n : childrenToCheck) {
        Nodeid p1 = parentHelper.firstParent(n);
        Nodeid p2 = parentHelper.secondParent(n);
        if (p1 != null && elements.contains(p1)) {
          nextRound.add(p1);
        }
        if (p2 != null && elements.contains(p2)) {
          nextRound.add(p2);
        }
      }
      ancestors.addAll(nextRound);
      childrenToCheck = nextRound;
    }
    return new RevisionSet(ancestors);
  }
 
  /**
   * Revisions that are both direct and indirect children of elements of this revision set
   * as known in supplied parent-child map
   */
  public RevisionSet children(HgParentChildMap<HgChangelog> parentHelper) {
    if (isEmpty()) {
      return this;
    }
    List<Nodeid> children = parentHelper.childrenOf(elements);
    return new RevisionSet(new HashSet<Nodeid>(children));
  }

  public RevisionSet intersect(RevisionSet other) {
    if (isEmpty()) {
      return this;
    }
    if (other.isEmpty()) {
      return other;
    }
    HashSet<Nodeid> copy = new HashSet<Nodeid>(elements);
    copy.retainAll(other.elements);
    return copy.size() == elements.size() ? this : new RevisionSet(copy);
  }
 
  public RevisionSet subtract(RevisionSet other) {
    if (isEmpty() || other.isEmpty()) {
      return this;
    }
    HashSet<Nodeid> copy = new HashSet<Nodeid>(elements);
    copy.removeAll(other.elements);
    return copy.size() == elements.size() ? this : new RevisionSet(copy);
  }

  public RevisionSet union(RevisionSet other) {
    if (isEmpty()) {
      return other;
    }
    if (other.isEmpty()) {
      return this;
    }
    HashSet<Nodeid> copy = new HashSet<Nodeid>(elements);
    copy.addAll(other.elements);
    return copy.size() == elements.size() ? this : new RevisionSet(copy);
  }

  /**
   * A ^ B := (A\B).union(B\A)
   * A ^ B := A.union(B) \ A.intersect(B)
   */
  public RevisionSet symmetricDifference(RevisionSet other) {
    if (isEmpty()) {
      return this;
    }
    if (other.isEmpty()) {
      return other;
    }
    HashSet<Nodeid> copyA = new HashSet<Nodeid>(elements);
    HashSet<Nodeid> copyB = new HashSet<Nodeid>(other.elements);
    copyA.removeAll(other.elements);
    copyB.removeAll(elements);
    copyA.addAll(copyB);
    return new RevisionSet(copyA);
  }

  public boolean isEmpty() {
    return elements.isEmpty();
  }

  public int size() {
    return elements.size();
  }

  public List<Nodeid> asList() {
    return new ArrayList<Nodeid>(elements);
  }
 
  public Iterator<Nodeid> iterator() {
    return elements.iterator();
  }
 
  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append('<');
    if (!isEmpty()) {
      sb.append(elements.size());
      sb.append(':');
    }
    for (Nodeid n : elements) {
      sb.append(n.shortNotation());
      sb.append(',');
    }
    if (sb.length() > 1) {
      sb.setCharAt(sb.length() - 1, '>');
    } else {
      sb.append('>');
    }
    return sb.toString();
  }
 
  @Override
  public boolean equals(Object obj) {
    if (false == obj instanceof RevisionSet) {
      return false;
    }
    return elements.equals(((RevisionSet) obj).elements);
  }
 
  @Override
  public int hashCode() {
    return elements.hashCode();
  }
}
TOP

Related Classes of org.tmatesoft.hg.internal.RevisionSet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.