@@ -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,
@@ -2394,6 +2395,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 */
@@ -2406,7 +2425,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 */
@@ -81,6 +81,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.
@@ -204,6 +224,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;
@@ -0,0 +1,3 @@
+max_width = 79
+wrap_comments = true
+error_on_line_overflow = true
@@ -16,9 +16,12 @@
use std::slice;
type IndexPtr = *mut c_void;
-type IndexParentsFn =
- unsafe extern "C" fn(index: IndexPtr, rev: ssize_t, ps: *mut [c_int; 2], max_rev: c_int)
- -> c_int;
+type IndexParentsFn = unsafe extern "C" fn(
+ index: IndexPtr,
+ rev: ssize_t,
+ ps: *mut [c_int; 2],
+ max_rev: c_int,
+) -> c_int;
/// A Graph backed up by objects and functions from revlog.c
///
@@ -41,10 +44,19 @@
impl Graph for Index {
/// wrap a call to the C extern parents function
- fn parents(&self, rev: Revision) -> Result<(Revision, Revision), GraphError> {
+ fn parents(
+ &self,
+ rev: Revision,
+ ) -> Result<(Revision, Revision), GraphError> {
let mut res: [c_int; 2] = [0; 2];
- let code =
- unsafe { (self.parents)(self.index, rev as ssize_t, &mut res as *mut [c_int; 2], rev) };
+ let code = unsafe {
+ (self.parents)(
+ self.index,
+ rev as ssize_t,
+ &mut res as *mut [c_int; 2],
+ rev,
+ )
+ };
match code {
0 => Ok((res[0], res[1])),
_ => Err(GraphError::ParentOutOfRange(rev)),
@@ -110,7 +122,9 @@
/// Deallocator to be called from C code
#[no_mangle]
-pub extern "C" fn rustlazyancestors_drop(raw_iter: *mut AncestorsIterator<Index>) {
+pub extern "C" fn rustlazyancestors_drop(
+ raw_iter: *mut AncestorsIterator<Index>,
+) {
raw_drop(raw_iter);
}
@@ -128,7 +142,9 @@
/// it will be up to the C wrapper to convert that back into a Python end of
/// iteration
#[no_mangle]
-pub extern "C" fn rustlazyancestors_next(raw: *mut AncestorsIterator<Index>) -> c_long {
+pub extern "C" fn rustlazyancestors_next(
+ raw: *mut AncestorsIterator<Index>,
+) -> c_long {
raw_next(raw)
}
@@ -139,6 +155,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_long {
+ 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_long {
+ let as_ref = unsafe { &mut *raw };
+ if as_ref.contains(target as Revision) {
+ return 1;
+ }
+ 0
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -148,7 +185,10 @@
struct Stub;
impl Graph for Stub {
- fn parents(&self, r: Revision) -> Result<(Revision, Revision), GraphError> {
+ fn parents(
+ &self,
+ r: Revision,
+ ) -> Result<(Revision, Revision), GraphError> {
match r {
25 => Err(GraphError::ParentOutOfRange(25)),
_ => Ok((1, 2)),
@@ -199,7 +239,9 @@
let mut initrevs: Vec<c_long> = vec![11, 13];
let initrevs_len = initrevs.len();
let initrevs_ptr = initrevs.as_mut_ptr() as usize;
- let handler = thread::spawn(move || stub_raw_init(initrevs_len, initrevs_ptr, 0, 1));
+ let handler = thread::spawn(move || {
+ stub_raw_init(initrevs_len, initrevs_ptr, 0, 1)
+ });
let raw = handler.join().unwrap() as *mut AncestorsIterator<Stub>;
assert_eq!(raw_next(raw), 13);
@@ -226,4 +268,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,
+};