summaryrefslogtreecommitdiffstats
path: root/vendor/gix-negotiate/src/consecutive.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-negotiate/src/consecutive.rs')
-rw-r--r--vendor/gix-negotiate/src/consecutive.rs167
1 files changed, 167 insertions, 0 deletions
diff --git a/vendor/gix-negotiate/src/consecutive.rs b/vendor/gix-negotiate/src/consecutive.rs
new file mode 100644
index 000000000..f213cd949
--- /dev/null
+++ b/vendor/gix-negotiate/src/consecutive.rs
@@ -0,0 +1,167 @@
+use gix_hash::ObjectId;
+use gix_revision::graph::CommitterTimestamp;
+
+use crate::{Error, Flags, Negotiator};
+
+pub(crate) struct Algorithm {
+ revs: gix_revision::PriorityQueue<CommitterTimestamp, ObjectId>,
+ non_common_revs: usize,
+}
+
+impl Default for Algorithm {
+ fn default() -> Self {
+ Self {
+ revs: gix_revision::PriorityQueue::new(),
+ non_common_revs: 0,
+ }
+ }
+}
+
+impl Algorithm {
+ /// Add `id` to our priority queue and *add* `flags` to it.
+ fn add_to_queue(&mut self, id: ObjectId, mark: Flags, graph: &mut crate::Graph<'_>) -> Result<(), Error> {
+ let mut is_common = false;
+ let mut has_mark = false;
+ if let Some(commit) = graph
+ .try_lookup_or_insert_commit(id, |data| {
+ has_mark = data.flags.intersects(mark);
+ data.flags |= mark;
+ is_common = data.flags.contains(Flags::COMMON);
+ })?
+ .filter(|_| !has_mark)
+ {
+ self.revs.insert(commit.commit_time, id);
+ if !is_common {
+ self.non_common_revs += 1;
+ }
+ }
+ Ok(())
+ }
+
+ fn mark_common(
+ &mut self,
+ id: ObjectId,
+ mode: Mark,
+ ancestors: Ancestors,
+ graph: &mut crate::Graph<'_>,
+ ) -> Result<(), Error> {
+ let mut is_common = false;
+ if let Some(commit) = graph
+ .try_lookup_or_insert_commit(id, |data| is_common = data.flags.contains(Flags::COMMON))?
+ .filter(|_| !is_common)
+ {
+ let mut queue = gix_revision::PriorityQueue::from_iter(Some((commit.commit_time, (id, 0_usize))));
+ if let Mark::ThisCommitAndAncestors = mode {
+ commit.data.flags |= Flags::COMMON;
+ if commit.data.flags.contains(Flags::SEEN) && !commit.data.flags.contains(Flags::POPPED) {
+ self.non_common_revs -= 1;
+ }
+ }
+ while let Some((id, generation)) = queue.pop_value() {
+ if graph
+ .get(&id)
+ .map_or(true, |commit| !commit.data.flags.contains(Flags::SEEN))
+ {
+ self.add_to_queue(id, Flags::SEEN, graph)?;
+ } else if matches!(ancestors, Ancestors::AllUnseen) || generation < 2 {
+ if let Some(commit) = graph.try_lookup_or_insert_commit(id, |_| {})? {
+ for parent_id in commit.parents.clone() {
+ let mut prev_flags = Flags::default();
+ if let Some(parent) = graph
+ .try_lookup_or_insert_commit(parent_id, |data| {
+ prev_flags = data.flags;
+ data.flags |= Flags::COMMON;
+ })?
+ .filter(|_| !prev_flags.contains(Flags::COMMON))
+ {
+ if prev_flags.contains(Flags::SEEN) && !prev_flags.contains(Flags::POPPED) {
+ self.non_common_revs -= 1;
+ }
+ queue.insert(parent.commit_time, (parent_id, generation + 1))
+ }
+ }
+ }
+ }
+ }
+ }
+ Ok(())
+ }
+}
+
+impl Negotiator for Algorithm {
+ fn known_common(&mut self, id: ObjectId, graph: &mut crate::Graph<'_>) -> Result<(), Error> {
+ if graph
+ .get(&id)
+ .map_or(true, |commit| !commit.data.flags.contains(Flags::SEEN))
+ {
+ self.add_to_queue(id, Flags::COMMON_REF | Flags::SEEN, graph)?;
+ self.mark_common(id, Mark::AncestorsOnly, Ancestors::DirectUnseen, graph)?;
+ }
+ Ok(())
+ }
+
+ fn add_tip(&mut self, id: ObjectId, graph: &mut crate::Graph<'_>) -> Result<(), Error> {
+ self.add_to_queue(id, Flags::SEEN, graph)
+ }
+
+ fn next_have(&mut self, graph: &mut crate::Graph<'_>) -> Option<Result<ObjectId, Error>> {
+ loop {
+ let id = self.revs.pop_value().filter(|_| self.non_common_revs != 0)?;
+ let commit = graph.get_mut(&id).expect("it was added to the graph by now");
+ let flags = &mut commit.data.flags;
+ *flags |= Flags::POPPED;
+
+ if !flags.contains(Flags::COMMON) {
+ self.non_common_revs -= 1;
+ }
+
+ let (res, mark) = if flags.contains(Flags::COMMON) {
+ (None, Flags::COMMON | Flags::SEEN)
+ } else if flags.contains(Flags::COMMON_REF) {
+ (Some(id), Flags::COMMON | Flags::SEEN)
+ } else {
+ (Some(id), Flags::SEEN)
+ };
+
+ for parent_id in commit.parents.clone() {
+ if graph
+ .get(&parent_id)
+ .map_or(true, |commit| !commit.data.flags.contains(Flags::SEEN))
+ {
+ if let Err(err) = self.add_to_queue(parent_id, mark, graph) {
+ return Some(Err(err));
+ }
+ }
+ if mark.contains(Flags::COMMON) {
+ if let Err(err) = self.mark_common(parent_id, Mark::AncestorsOnly, Ancestors::AllUnseen, graph) {
+ return Some(Err(err));
+ }
+ }
+ }
+
+ if let Some(id) = res {
+ return Some(Ok(id));
+ }
+ }
+ }
+
+ fn in_common_with_remote(&mut self, id: ObjectId, graph: &mut crate::Graph<'_>) -> Result<bool, Error> {
+ let known_to_be_common = graph
+ .get(&id)
+ .map_or(false, |commit| commit.data.flags.contains(Flags::COMMON));
+ self.mark_common(id, Mark::ThisCommitAndAncestors, Ancestors::DirectUnseen, graph)?;
+ Ok(known_to_be_common)
+ }
+}
+
+enum Mark {
+ AncestorsOnly,
+ ThisCommitAndAncestors,
+}
+
+enum Ancestors {
+ /// Traverse only the parents of a commit.
+ DirectUnseen,
+ /// Traverse all ancestors that weren't yet seen.
+ AllUnseen,
+}