@@ -383,7 +383,7 @@
self._containsiter = None
return False
-class rustlazyancestors(lazyancestors):
+class rustlazyancestors(object):
def __init__(self, index, revs, stoprev=0, inclusive=False):
self._index = index
@@ -395,12 +395,26 @@
# constructor (from C code) doesn't understand anything else yet
self._initrevs = initrevs = list(revs)
- self._containsseen = set()
self._containsiter = parsers.rustlazyancestors(
index, initrevs, stoprev, inclusive)
+ def __nonzero__(self):
+ """False if the set is empty, True otherwise.
+
+ It's better to duplicate this essentially trivial method than
+ to subclass lazyancestors
+ """
+ try:
+ next(iter(self))
+ return True
+ except StopIteration:
+ return False
+
def __iter__(self):
return parsers.rustlazyancestors(self._index,
self._initrevs,
self._stoprev,
self._inclusive)
+
+ def __contains__(self, target):
+ return target in self._containsiter
@@ -2316,6 +2316,7 @@
int inclusive);
void rustlazyancestors_drop(rustlazyancestorsObject *self);
int rustlazyancestors_next(rustlazyancestorsObject *self);
+int rustlazyancestors_contains(rustlazyancestorsObject *self, long rev);
/* CPython instance methods */
static int rustla_init(rustlazyancestorsObject *self,
@@ -2395,6 +2396,24 @@
return PyInt_FromLong(res);
}
+static int rustla_contains(rustlazyancestorsObject *self, PyObject *rev) {
+ if (!(PyInt_Check(rev))) {
+ return 0;
+ }
+ return rustlazyancestors_contains(self->iter, PyInt_AS_LONG(rev));
+}
+
+static PySequenceMethods rustla_sequence_methods = {
+ 0, /* sq_length */
+ 0, /* sq_concat */
+ 0, /* sq_repeat */
+ 0, /* sq_item */
+ 0, /* sq_slice */
+ 0, /* sq_ass_item */
+ 0, /* sq_ass_slice */
+ (objobjproc)rustla_contains, /* sq_contains */
+};
+
static PyTypeObject rustlazyancestorsType = {
PyVarObject_HEAD_INIT(NULL, 0) /* header */
"parsers.rustlazyancestors", /* tp_name */
@@ -2407,7 +2426,7 @@
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
- 0, /* tp_as_sequence */
+ &rustla_sequence_methods, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
@@ -80,6 +80,26 @@
self.conditionally_push_rev(parents.1);
Ok(())
}
+
+ /// Consumes partially the iterator to tell if the given target
+ /// revision
+ /// is in the ancestors it emits.
+ /// This is meant for iterators actually dedicated to that kind of
+ /// purpose
+ pub fn contains(&mut self, target: Revision) -> bool {
+ if self.seen.contains(&target) && target != NULL_REVISION {
+ return true;
+ }
+ for rev in self {
+ if rev == target {
+ return true;
+ }
+ if rev < target {
+ return false;
+ }
+ }
+ false
+ }
}
/// Main implementation.
@@ -203,6 +223,18 @@
assert_eq!(iter.next(), None)
}
+ #[test]
+ fn test_contains() {
+ let mut lazy =
+ AncestorsIterator::new(Stub, vec![10, 1], 0, true).unwrap();
+ assert!(lazy.contains(1));
+ assert!(!lazy.contains(3));
+
+ let mut lazy =
+ AncestorsIterator::new(Stub, vec![0], 0, false).unwrap();
+ assert!(!lazy.contains(NULL_REVISION));
+ }
+
/// A corrupted Graph, supporting error handling tests
struct Corrupted;
@@ -139,6 +139,27 @@
as_ref.next().unwrap_or(NULL_REVISION) as c_long
}
+#[no_mangle]
+pub extern "C" fn rustlazyancestors_contains(
+ raw: *mut AncestorsIterator<Index>,
+ target: c_long,
+) -> c_int {
+ raw_contains(raw, target)
+}
+
+/// Testable (for any Graph) version of rustlazayancestors_next
+#[inline]
+fn raw_contains<G: Graph>(
+ raw: *mut AncestorsIterator<G>,
+ target: c_long,
+) -> c_int {
+ let as_ref = unsafe { &mut *raw };
+ if as_ref.contains(target as Revision) {
+ return 1;
+ }
+ 0
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -226,4 +247,18 @@
fn test_init_err_out_of_range() {
assert!(stub_raw_init_from_vec(vec![25], 0, 0).is_null());
}
+
+ #[test]
+ fn test_contains() {
+ let raw = stub_raw_init_from_vec(vec![5, 6], 0, 1);
+ assert_eq!(raw_contains(raw, 5), 1);
+ assert_eq!(raw_contains(raw, 2), 1);
+ }
+
+ #[test]
+ fn test_contains_exclusive() {
+ let raw = stub_raw_init_from_vec(vec![5, 6], 0, 0);
+ assert_eq!(raw_contains(raw, 5), 0);
+ assert_eq!(raw_contains(raw, 2), 1);
+ }
}
@@ -13,4 +13,7 @@
extern crate libc;
mod ancestors;
-pub use ancestors::{rustlazyancestors_drop, rustlazyancestors_init, rustlazyancestors_next};
+pub use ancestors::{
+ rustlazyancestors_contains, rustlazyancestors_drop,
+ rustlazyancestors_init, rustlazyancestors_next,
+};