You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TopoNonIntermixSortGenerator.java 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /*
  2. * Copyright (C) 2020, Google LLC. and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.revwalk;
  11. import java.io.IOException;
  12. import org.eclipse.jgit.errors.IncorrectObjectTypeException;
  13. import org.eclipse.jgit.errors.MissingObjectException;
  14. /** Sorts commits in topological order without intermixing lines of history. */
  15. class TopoNonIntermixSortGenerator extends Generator {
  16. private static final int TOPO_QUEUED = RevWalk.TOPO_QUEUED;
  17. private final FIFORevQueue pending;
  18. private final int outputType;
  19. /**
  20. * Create a new sorter and completely spin the generator.
  21. * <p>
  22. * When the constructor completes the supplied generator will have no
  23. * commits remaining, as all of the commits will be held inside of this
  24. * generator's internal buffer.
  25. *
  26. * @param s
  27. * generator to pull all commits out of, and into this buffer.
  28. * @throws MissingObjectException
  29. * @throws IncorrectObjectTypeException
  30. * @throws IOException
  31. */
  32. TopoNonIntermixSortGenerator(Generator s) throws MissingObjectException,
  33. IncorrectObjectTypeException, IOException {
  34. super(s.firstParent);
  35. pending = new FIFORevQueue(firstParent);
  36. outputType = s.outputType() | SORT_TOPO;
  37. s.shareFreeList(pending);
  38. for (;;) {
  39. final RevCommit c = s.next();
  40. if (c == null) {
  41. break;
  42. }
  43. if ((c.flags & TOPO_QUEUED) == 0) {
  44. for (RevCommit p : c.parents) {
  45. p.inDegree++;
  46. if (firstParent) {
  47. break;
  48. }
  49. }
  50. }
  51. c.flags |= TOPO_QUEUED;
  52. pending.add(c);
  53. }
  54. }
  55. @Override
  56. int outputType() {
  57. return outputType;
  58. }
  59. @Override
  60. void shareFreeList(BlockRevQueue q) {
  61. q.shareFreeList(pending);
  62. }
  63. @Override
  64. RevCommit next() throws MissingObjectException,
  65. IncorrectObjectTypeException, IOException {
  66. for (;;) {
  67. final RevCommit c = pending.next();
  68. if (c == null) {
  69. return null;
  70. }
  71. if (c.inDegree > 0) {
  72. // At least one of our children is missing. We delay
  73. // production until all of our children are output.
  74. //
  75. continue;
  76. }
  77. if ((c.flags & TOPO_QUEUED) == 0) {
  78. // c is a parent that already produced or a parent that
  79. // was never in the priority queue and should never produce.
  80. //
  81. continue;
  82. }
  83. for (RevCommit p : c.parents) {
  84. if (--p.inDegree == 0 && (p.flags & TOPO_QUEUED) != 0) {
  85. // The parent has no unproduced interesting children. unpop
  86. // the parent so it goes right behind this child. This means
  87. // that this parent commit may appear in "pending" more than
  88. // once, but this is safe since upon the second and
  89. // subsequent iterations with this commit, it will no longer
  90. // have TOPO_QUEUED set, and thus will be skipped.
  91. //
  92. pending.unpop(p);
  93. }
  94. if (firstParent) {
  95. break;
  96. }
  97. }
  98. c.flags &= ~TOPO_QUEUED;
  99. return c;
  100. }
  101. }
  102. }