View Javadoc
1   /*
2    * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> 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  
11  package org.eclipse.jgit.revwalk;
12  
13  import java.io.IOException;
14  
15  import org.eclipse.jgit.errors.IncorrectObjectTypeException;
16  import org.eclipse.jgit.errors.MissingObjectException;
17  
18  abstract class BlockRevQueue extends AbstractRevQueue {
19  	protected BlockFreeList free;
20  
21  	/**
22  	 * Create an empty revision queue.
23  	 *
24  	 * @param firstParent
25  	 *            whether only first-parent links should be followed when
26  	 *            walking
27  	 */
28  	protected BlockRevQueue(boolean firstParent) {
29  		super(firstParent);
30  		free = new BlockFreeList();
31  	}
32  
33  	BlockRevQueue(Generator s) throws MissingObjectException,
34  			IncorrectObjectTypeException, IOException {
35  		super(s.firstParent);
36  		free = new BlockFreeList();
37  		outputType = s.outputType();
38  		s.shareFreeList(this);
39  		for (;;) {
40  			final RevCommit c = s.next();
41  			if (c == null)
42  				break;
43  			add(c);
44  		}
45  	}
46  
47  	/**
48  	 * {@inheritDoc}
49  	 * <p>
50  	 * Reconfigure this queue to share the same free list as another.
51  	 * <p>
52  	 * Multiple revision queues can be connected to the same free list, making
53  	 * it less expensive for applications to shuttle commits between them. This
54  	 * method arranges for the receiver to take from / return to the same free
55  	 * list as the supplied queue.
56  	 * <p>
57  	 * Free lists are not thread-safe. Applications must ensure that all queues
58  	 * sharing the same free list are doing so from only a single thread.
59  	 */
60  	@Override
61  	public void shareFreeList(BlockRevQueue q) {
62  		free = q.free;
63  	}
64  
65  	static final class BlockFreeList {
66  		private Block next;
67  
68  		Block newBlock() {
69  			Block b = next;
70  			if (b == null)
71  				return new Block();
72  			next = b.next;
73  			b.clear();
74  			return b;
75  		}
76  
77  		void freeBlock(Block b) {
78  			b.next = next;
79  			next = b;
80  		}
81  
82  		void clear() {
83  			next = null;
84  		}
85  	}
86  
87  	static final class Block {
88  		static final int BLOCK_SIZE = 256;
89  
90  		/** Next block in our chain of blocks; null if we are the last. */
91  		Block next;
92  
93  		/** Our table of queued commits. */
94  		final RevCommit.html#RevCommit">RevCommit[] commits = new RevCommit[BLOCK_SIZE];
95  
96  		/** Next valid entry in {@link #commits}. */
97  		int headIndex;
98  
99  		/** Next free entry in {@link #commits} for addition at. */
100 		int tailIndex;
101 
102 		boolean isFull() {
103 			return tailIndex == BLOCK_SIZE;
104 		}
105 
106 		boolean isEmpty() {
107 			return headIndex == tailIndex;
108 		}
109 
110 		boolean canUnpop() {
111 			return headIndex > 0;
112 		}
113 
114 		void add(RevCommit c) {
115 			commits[tailIndex++] = c;
116 		}
117 
118 		void unpop(RevCommit c) {
119 			commits[--headIndex] = c;
120 		}
121 
122 		RevCommit pop() {
123 			return commits[headIndex++];
124 		}
125 
126 		RevCommit peek() {
127 			return commits[headIndex];
128 		}
129 
130 		void clear() {
131 			next = null;
132 			headIndex = 0;
133 			tailIndex = 0;
134 		}
135 
136 		void resetToMiddle() {
137 			headIndex = tailIndex = BLOCK_SIZE / 2;
138 		}
139 
140 		void resetToEnd() {
141 			headIndex = tailIndex = BLOCK_SIZE;
142 		}
143 	}
144 }