Rev 4529: Move the core loops into module-level helpers. in http://bazaar.launchpad.net/~jameinel/bzr/1.17-rework-annotate
John Arbash Meinel
john at arbash-meinel.com
Wed Jul 8 16:41:22 BST 2009
At http://bazaar.launchpad.net/~jameinel/bzr/1.17-rework-annotate
------------------------------------------------------------
revno: 4529
revision-id: john at arbash-meinel.com-20090708154118-q0k3jyyhhnmoezr7
parent: john at arbash-meinel.com-20090708152805-nbgmogmzfbfbuu28
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 1.17-rework-annotate
timestamp: Wed 2009-07-08 10:41:18 -0500
message:
Move the core loops into module-level helpers.
Not sure if it really matters, but it does make it a bit simpler, and it
means the code matches _update_from_first_parent.
-------------- next part --------------
=== modified file 'bzrlib/_annotator_py.py'
--- a/bzrlib/_annotator_py.py 2009-07-08 15:28:05 +0000
+++ b/bzrlib/_annotator_py.py 2009-07-08 15:41:18 +0000
@@ -143,8 +143,9 @@
def _update_from_first_parent(self, key, annotations, lines, parent_key):
"""Reannotate this text relative to its first parent."""
- parent_annotations, matching_blocks = self._get_parent_annotations_and_matches(
- key, lines, parent_key)
+ (parent_annotations,
+ matching_blocks) = self._get_parent_annotations_and_matches(
+ key, lines, parent_key)
for parent_idx, lines_idx, match_len in matching_blocks:
# For all matching regions we copy across the parent annotations
@@ -154,8 +155,9 @@
def _update_from_other_parents(self, key, annotations, lines,
this_annotation, parent_key):
"""Reannotate this text relative to a second (or more) parent."""
- parent_annotations, matching_blocks = self._get_parent_annotations_and_matches(
- key, lines, parent_key)
+ (parent_annotations,
+ matching_blocks) = self._get_parent_annotations_and_matches(
+ key, lines, parent_key)
last_ann = None
last_parent = None
@@ -239,7 +241,14 @@
self._heads_provider = None
def annotate(self, key):
- """Return annotated fulltext for the given key."""
+ """Return annotated fulltext for the given key.
+
+ :param key: A tuple defining the text to annotate
+ :return: ([annotations], [lines])
+ annotations is a list of tuples of keys, one for each line in lines
+ each key is a possible source for the given line.
+ lines the text of "key" as a list of lines
+ """
pb = ui.ui_factory.nested_progress_bar()
try:
for text_key, text, num_lines in self._get_needed_texts(key, pb=pb):
@@ -261,6 +270,8 @@
"""Determine the single-best-revision to source for each line.
This is meant as a compatibility thunk to how annotate() used to work.
+ :return: [(ann_key, line)]
+ A list of tuples with a single annotation key for each line.
"""
annotations, lines = self.annotate(key)
assert len(annotations) == len(lines)
=== modified file 'bzrlib/_annotator_pyx.pyx'
--- a/bzrlib/_annotator_pyx.pyx 2009-07-08 15:28:05 +0000
+++ b/bzrlib/_annotator_pyx.pyx 2009-07-08 15:41:18 +0000
@@ -56,7 +56,6 @@
from bzrlib import _annotator_py
-from bzrlib import errors, graph as _mod_graph, osutils, patiencediff, ui
cdef int _check_annotations_are_lists(annotations,
@@ -155,8 +154,8 @@
return new_ann
-cdef _apply_parent_annotations(annotations, parent_annotations,
- matching_blocks):
+cdef int _apply_parent_annotations(annotations, parent_annotations,
+ matching_blocks) except -1:
"""Apply the annotations from parent_annotations into annotations.
matching_blocks defines the ranges that match.
@@ -181,6 +180,57 @@
Py_INCREF_ptr(par_temp[idx])
Py_DECREF_ptr(ann_temp[idx])
ann_temp[idx] = par_temp[idx]
+ return 0
+
+
+cdef int _merge_annotations(this_annotation, annotations, parent_annotations,
+ matching_blocks, ann_cache) except -1:
+ cdef Py_ssize_t parent_idx, ann_idx, lines_idx, match_len, idx
+ cdef Py_ssize_t pos
+ cdef PyObject *ann_temp, *par_temp
+
+ _check_annotations_are_lists(annotations, parent_annotations)
+ last_ann = None
+ last_parent = None
+ last_res = None
+ for parent_idx, lines_idx, match_len in matching_blocks:
+ _check_match_ranges(parent_annotations, annotations,
+ parent_idx, lines_idx, match_len)
+ # For lines which match this parent, we will now resolve whether
+ # this parent wins over the current annotation
+ for idx from 0 <= idx < match_len:
+ ann_idx = lines_idx + idx
+ ann_temp = PyList_GET_ITEM(annotations, ann_idx)
+ par_temp = PyList_GET_ITEM(parent_annotations, parent_idx + idx)
+ if (ann_temp == par_temp):
+ # This is parent, do nothing
+ # Pointer comparison is fine here. Value comparison would
+ # be ok, but it will be handled in the final if clause by
+ # merging the two tuples into the same tuple
+ # Avoiding the Py_INCREF and function call to
+ # PyObject_RichCompareBool using pointer comparison drops
+ # timing from 215ms => 125ms
+ continue
+ par_ann = <object>par_temp
+ ann = <object>ann_temp
+ if (ann is this_annotation):
+ # Originally claimed 'this', but it was really in this
+ # parent
+ Py_INCREF(par_ann)
+ PyList_SetItem(annotations, ann_idx, par_ann)
+ continue
+ # Resolve the fact that both sides have a different value for
+ # last modified
+ if (ann is last_ann and par_ann is last_parent):
+ Py_INCREF(last_res)
+ PyList_SetItem(annotations, ann_idx, last_res)
+ else:
+ new_ann = _combine_annotations(ann, par_ann, ann_cache)
+ Py_INCREF(new_ann)
+ PyList_SetItem(annotations, ann_idx, new_ann)
+ last_ann = ann
+ last_parent = par_ann
+ last_res = new_ann
class Annotator(_annotator_py.Annotator):
@@ -188,8 +238,9 @@
def _update_from_first_parent(self, key, annotations, lines, parent_key):
"""Reannotate this text relative to its first parent."""
- parent_annotations, matching_blocks = self._get_parent_annotations_and_matches(
- key, lines, parent_key)
+ (parent_annotations,
+ matching_blocks) = self._get_parent_annotations_and_matches(
+ key, lines, parent_key)
_apply_parent_annotations(annotations, parent_annotations,
matching_blocks)
@@ -197,53 +248,11 @@
def _update_from_other_parents(self, key, annotations, lines,
this_annotation, parent_key):
"""Reannotate this text relative to a second (or more) parent."""
- cdef Py_ssize_t parent_idx, ann_idx, lines_idx, match_len, idx
- cdef Py_ssize_t pos
- cdef PyObject *ann_temp, *par_temp
- parent_annotations, matching_blocks = self._get_parent_annotations_and_matches(
- key, lines, parent_key)
- _check_annotations_are_lists(annotations, parent_annotations)
- last_ann = None
- last_parent = None
- last_res = None
- cache = self._ann_tuple_cache
- for parent_idx, lines_idx, match_len in matching_blocks:
- _check_match_ranges(parent_annotations, annotations,
- parent_idx, lines_idx, match_len)
- # For lines which match this parent, we will now resolve whether
- # this parent wins over the current annotation
- for idx from 0 <= idx < match_len:
- ann_idx = lines_idx + idx
- ann_temp = PyList_GET_ITEM(annotations, ann_idx)
- par_temp = PyList_GET_ITEM(parent_annotations, parent_idx + idx)
- if (ann_temp == par_temp):
- # This is parent, do nothing
- # Pointer comparison is fine here. Value comparison would
- # be ok, but it will be handled in the final if clause by
- # merging the two tuples into the same tuple
- # Avoiding the Py_INCREF by using pointer comparison drops
- # timing from 215ms => 125ms
- continue
- par_ann = <object>par_temp
- ann = <object>ann_temp
- if (ann is this_annotation):
- # Originally claimed 'this', but it was really in this
- # parent
- Py_INCREF(par_ann)
- PyList_SetItem(annotations, ann_idx, par_ann)
- continue
- # Resolve the fact that both sides have a different value for
- # last modified
- if (ann is last_ann and par_ann is last_parent):
- Py_INCREF(last_res)
- PyList_SetItem(annotations, ann_idx, last_res)
- else:
- new_ann = _combine_annotations(ann, par_ann, cache)
- Py_INCREF(new_ann)
- PyList_SetItem(annotations, ann_idx, new_ann)
- last_ann = ann
- last_parent = par_ann
- last_res = new_ann
+ (parent_annotations,
+ matching_blocks) = self._get_parent_annotations_and_matches(
+ key, lines, parent_key)
+ _merge_annotations(this_annotation, annotations, parent_annotations,
+ matching_blocks, self._ann_tuple_cache)
def annotate_flat(self, key):
"""Determine the single-best-revision to source for each line.
More information about the bazaar-commits
mailing list