HEX
Server: Apache
System: Linux infong-uk86 4.4.400-icpu-106 #2 SMP Mon Sep 15 08:23:40 UTC 2025 x86_64
User: u44115835 (4976590)
PHP: 8.4.17
Disabled: NONE
Upload Files
File: //kunden/lib/python3/dist-packages/breezy/__pycache__/graph.cpython-39.pyc
a

�*�^R�
@s>ddlmZddlZddlmZmZmZmZmZddl	m
Z
mZdZGdd�de
�ZGd	d
�d
e
�ZGdd�de
�ZGd
d�de
�ZGdd�de
�ZGdd�de
�ZGdd�de
�ZGdd�de
�Zdd�Zdd�ZGdd�de
�Zgd�ZzddlmZWn<e�y8Zz"e�e�ddlmZWYdZ[n
dZ[00dS)�)�absolute_importN�)�debug�errors�osutils�revision�trace)�	viewitems�
viewvalues�c@s(eZdZdZdd�Zdd�Zdd�ZdS)	�DictParentsProviderz%A parents provider for Graph objects.cCs
||_dS�N��ancestry)�selfr�r�./usr/lib/python3/dist-packages/breezy/graph.py�__init__=szDictParentsProvider.__init__cCs
d|jS)NzDictParentsProvider(%r)r�rrrr�__repr__@szDictParentsProvider.__repr__cs|j�t�fdd�|D��S)z)See StackedParentsProvider.get_parent_mapcs g|]}|�vr|�|f�qSrr)�.0�krrr�
<listcomp>K�z6DictParentsProvider.get_parent_map.<locals>.<listcomp>)r�dict�r�keysrrr�get_parent_mapHsz"DictParentsProvider.get_parent_mapN��__name__�
__module__�__qualname__�__doc__rrrrrrrr:src@s(eZdZdZdd�Zdd�Zdd�ZdS)	�StackedParentsProviderz�A parents provider which stacks (or unions) multiple providers.

    The providers are queries in the order of the provided parent_providers.
    cCs
||_dSr
)�_parent_providers)rZparent_providersrrrrTszStackedParentsProvider.__init__cCsd|jj|jfS�Nz%s(%r))�	__class__rr$rrrrrWszStackedParentsProvider.__repr__c	Cs�i}t|�}|jD]>}t|dd�}|dur,q||�}|�|�|�|�|sqRq|sZ|S|jD]H}z|�|�}Wntjy�Yq`Yn0|�|�|�|�|s`q�q`|S)a�Get a mapping of keys => parents

        A dictionary is returned with an entry for each key present in this
        source. If this source doesn't have information about a key, it should
        not include an entry.

        [NULL_REVISION] is used as the parent of the first user-committed
        revision.  Its parent list is empty.

        :param keys: An iterable returning keys to check (eg revision_ids)
        :return: A dictionary mapping each key to its parents
        �get_cached_parent_mapN)�setr$�getattr�update�difference_updaterr�UnsupportedOperation)rr�foundZ	remaining�parents_providerZ
get_cachedZ	new_foundrrrrZs2

�





z%StackedParentsProvider.get_parent_mapNrrrrrr#Nsr#c@sTeZdZdZddd�Zdd�Zddd	�Zd
d�Zdd
�Zdd�Z	dd�Z
dd�ZdS)�CachingParentsProvidera�A parents provider which will cache the revision => parents as a dict.

    This is useful for providers which have an expensive look up.

    Either a ParentsProvider or a get_parent_map-like callback may be
    supplied.  If it provides extra un-asked-for parents, they will be cached,
    but filtered out of get_parent_map.

    The cache is enabled by default, but may be disabled and re-enabled.
    NcCs4||_|dur|jj|_n||_d|_|�d�dS)z�Constructor.

        :param parent_provider: The ParentProvider to use.  It or
            get_parent_map must be supplied.
        :param get_parent_map: The get_parent_map callback to use.  It or
            parent_provider must be supplied.
        NT)�_real_providerr�_get_parent_map�_cache�enable_cache)rZparent_providerrrrrr�szCachingParentsProvider.__init__cCsd|jj|jfSr%)r&rr0rrrrr�szCachingParentsProvider.__repr__TcCs*|jdurtd��i|_||_t�|_dS)z
Enable cache.Nz#Cache enabled when already enabled.)r2�AssertionError�
_cache_missesr(�missing_keys)rZcache_missesrrrr3�s

z#CachingParentsProvider.enable_cachecCsd|_d|_t�|_dS)zDisable and clear the cache.N)r2r5r(r6rrrr�
disable_cache�sz$CachingParentsProvider.disable_cachecCs|jdurdSt|j�S)z(Return any cached get_parent_map values.N�r2rrrrr�get_cached_map�s
z%CachingParentsProvider.get_cached_mapcs(|j��duriSt�fdd�|D��S)z�Return items from the cache.

        This returns the same info as get_parent_map, but explicitly does not
        invoke the supplied ParentsProvider to search for uncached values.
        Ncs g|]}|�vr|�|f�qSrr�r�key��cacherrr�rz@CachingParentsProvider.get_cached_parent_map.<locals>.<listcomp>r8rrr<rr'�sz,CachingParentsProvider.get_cached_parent_mapcs�|j��dur|�|��n\t�fdd�|D��}|�|j�|rv|�|�}��|�|jrv|D]}||vr^|�|�q^i}|D]}��|�}|dur~|||<q~|S)z*See StackedParentsProvider.get_parent_map.Nc3s|]}|�vr|VqdSr
rr:r<rr�	<genexpr>�rz8CachingParentsProvider.get_parent_map.<locals>.<genexpr>)	r2r1r(r+r6r*r5�note_missing_key�get)rrZneeded_revisions�
parent_mapr;�result�valuerr<rr�s$



z%CachingParentsProvider.get_parent_mapcCs|jr|j�|�dS)zNote that key is a missing key.N)r5r6�add)rr;rrrr?�sz'CachingParentsProvider.note_missing_key)NN)T)rr r!r"rrr3r7r9r'rr?rrrrr/�s

r/c@s(eZdZdZdd�Zdd�Zdd�ZdS)	� CallableToParentsProviderAdapterz�A parents provider that adapts any callable to the parents provider API.

    i.e. it accepts calls to self.get_parent_map and relays them to the
    callable it was constructed with.
    cCs
||_dSr
��callable)rZ
a_callablerrrr�sz)CallableToParentsProviderAdapter.__init__cCsd|jj|jfSr%)r&rrGrrrrr�sz)CallableToParentsProviderAdapter.__repr__cCs
|�|�Sr
rFrrrrr�sz/CallableToParentsProviderAdapter.get_parent_mapNrrrrrrE�srEc@seZdZdZdd�Zdd�Zdd�Zdd	�Zd
d�Zdd
�Z	dd�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�Zdd�Zdd�Zd d!�Zd"d#�Zd$d%�Zd&d'�Zd(d)�Zd*d+�Zd,d-�Zd@d/d0�Zd1d2�ZdAd4d5�Zd6d7�Zd8d9�Zd:d;�Zd<d=�Z d>d?�Z!d3S)B�Graphz�Provide incremental access to revision graphs.

    This is the generic implementation; it is intended to be subclassed to
    specialize it for other repository types.
    cCs:t|dd�dur|j|_t|dd�dur0|j|_||_dS)a�Construct a Graph that uses several graphs as its input

        This should not normally be invoked directly, because there may be
        specialized implementations for particular repository types.  See
        Repository.get_graph().

        :param parents_provider: An object providing a get_parent_map call
            conforming to the behavior of
            StackedParentsProvider.get_parent_map.
        �get_parentsNr)r)rIr�_parents_provider)rr.rrrr�s
zGraph.__init__cCs
d|jS)Nz	Graph(%r))rJrrrrr	szGraph.__repr__cGs|�|�\}}}|�|�S)a�Determine the lowest common ancestors of the provided revisions

        A lowest common ancestor is a common ancestor none of whose
        descendants are common ancestors.  In graphs, unlike trees, there may
        be multiple lowest common ancestors.

        This algorithm has two phases.  Phase 1 identifies border ancestors,
        and phase 2 filters border ancestors to determine lowest common
        ancestors.

        In phase 1, border ancestors are identified, using a breadth-first
        search starting at the bottom of the graph.  Searches are stopped
        whenever a node or one of its descendants is determined to be common

        In phase 2, the border ancestors are filtered to find the least
        common ancestors.  This is done by searching the ancestries of each
        border ancestor.

        Phase 2 is perfomed on the principle that a border ancestor that is
        not an ancestor of any other border ancestor is a least common
        ancestor.

        Searches are stopped when they find a node that is determined to be a
        common ancestor of all border ancestors, because this shows that it
        cannot be a descendant of any border ancestor.

        The scaling of this operation should be proportional to:

        1. The number of uncommon ancestors
        2. The number of border ancestors
        3. The length of the shortest path between a border ancestor and an
           ancestor of all border ancestors.
        )�_find_border_ancestors�heads)r�	revisionsZ
border_common�commonZsidesrrr�find_lcas"zGraph.find_lcacCsH|�||g�\}}}|�||�|dj}|dj}|�|�|�|�fS)z4Determine the graph difference between two revisionsrr)rK�_search_for_extra_common�seen�
difference)r�
left_revision�right_revisionZborderrN�	searchers�left�rightrrr�find_difference4s�


zGraph.find_differencecCs8|�|�||��}tt|��}|�|g�}t|�|jS)z:Find descendants of old_key that are ancestors of new_key.)�
get_child_map�_find_descendant_ancestorsrHr�_make_breadth_first_searcher�listrQ)r�old_key�new_key�	child_map�graph�searcherrrr�find_descendants=s�zGraph.find_descendantscCs^|�|g�}|�|g�}|D]2}|j�|�}|�|�|�|���}|�|�q|j�|j�S)z=Find ancestors of new_key that may be descendants of old_key.)r[rQ�intersection�stop_searching_any�find_seen_ancestors�steprR)rr]r^�stop�descendantsrMZold_stopZ	seen_stoprrrrZFs
z Graph._find_descendant_ancestorscCsF|j�|�}i}tt|��D]$\}}|D]}|�|g��|�q(q|S)z�Get a mapping from parents to children of the specified keys.

        This is simply the inversion of get_parent_map.  Only supplied keys
        will be discovered as children.
        :return: a dict of key:child_list for keys.
        )rJr�sortedr	�
setdefault�append)rrrAZparent_child�child�parents�parentrrrrYQszGraph.get_child_mapcCs�t|�}|}d}tj}d||<t|�}i}||vr�|||<|d7}|h}	|	�|�|�|	�}
|
�|d�}|sxt�||��|d}g}|D]^}
|
�|
d�}|s�q�|d}||
d}||vr�|||S||vr�q�|||<|�	|�q�|}q*|||S)a�Find the left-hand distance to the NULL_REVISION.

        (This can also be considered the revno of a branch at
        target_revision_id.)

        :param target_revision_id: A revision_id which we would like to know
            the revno for.
        :param known_revision_ids: [(revision_id, revno)] A list of known
            revno, revision_id tuples. We'll use this to seed the search.
        rrN)
rr�
NULL_REVISIONr\r*rr@r�GhostRevisionsHaveNoRevnork)rZtarget_revision_idZknown_revision_ids�known_revnosZcur_tipZ	num_stepsroZsearching_known_tipsZunknown_searchedZ	to_searchrArmZnext_known_tips�revision_id�nextZ
next_revnorrr�find_distance_to_null_sD

�zGraph.find_distance_to_nullc	Cslg}g}|D]>}z|�||�||�f�WqtjyH|�|�Yq0q|D]}|�|df�qPt|�S)z�Find the distance to null for all the keys in keys.

        :param keys: keys to lookup.
        :return: A dict key->distance for all of keys.
        ���)rkrtrrpr)rrrq�ghostsr;rrr�find_lefthand_distances�s�zGraph.find_lefthand_distancesc	Cs�||vrt�S|�|g|�\}}|j�|j�}|s6|S|�|||�\}}|�||||�|�|j�}dtjvr�t�	dt
|�t
|��|S)arFind the unique ancestors for a revision versus others.

        This returns the ancestry of unique_revision, excluding all revisions
        in the ancestry of common_revisions. If unique_revision is in the
        ancestry, then the empty set will be returned.

        :param unique_revision: The revision_id whose ancestry we are
            interested in.
            (XXX: Would this API be better if we allowed multiple revisions on
            to be searched here?)
        :param common_revisions: Revision_ids of ancestries to exclude.
        :return: A set of revisions in the ancestry of unique_revision
        r`z%Found %d truly unique nodes out of %d)r(�_find_initial_unique_nodesrQrR�_make_unique_searchers�_refine_unique_nodesr�debug_flagsr�mutter�len)	rZunique_revision�common_revisions�unique_searcher�common_searcher�unique_nodes�all_unique_searcher�unique_tip_searchersZtrue_unique_nodesrrr�find_unique_ancestors�s,����
�zGraph.find_unique_ancestorsc	Cs�|�|�}t|�|�|�}|jr�t|���}t|���}|�|j�}|�|�|j��|r|�|�}|�|�|��|�	|�|�
|�q||fS)z�Steps 1-3 of find_unique_ancestors.

        Find the maximal set of unique nodes. Some of these might actually
        still be common, but we are sure that there are no other unique nodes.

        :return: (unique_searcher, common_searcher)
        )r[rs�_next_queryr(rfrcrQr*rerd�start_searching)	rZunique_revisionsr~rr�Znext_unique_nodesZnext_common_nodesZunique_are_common_nodes�	ancestorsrrrrx�s,	

�
���
z Graph._find_initial_unique_nodesc
	Cs,|�||�|��}t|�dkr.g}|�|�}nzg}|D]B}|�|g�}|�|�|��|�|�}	||	_|	��|�|	�q6d}|D]$}	|dur�t	|	j
�}q�|�|	j
�}q�|�|�}
|r�|
��|�|�|��}d}|D]}	|t|	�|	�|���7}q�dt
jv�r$t�dt|�t|�|t|�t|��|
|fS)aCreate a searcher for all the unique search tips (step 4).

        As a side effect, the common_searcher will stop searching any nodes
        that are ancestors of the unique searcher tips.

        :return: (all_unique_searcher, unique_tip_searchers)
        rNrr`zuFor %d unique nodes, created %d + 1 unique searchers (%d stopped search tips, %d common ancestors (%d stopped common))�_remove_simple_descendantsrr}rer*r[�_labelrfrkr(rQrcrdrr{rr|)
rr�rr�Zunique_tipsr��ancestor_all_uniqueZtip�revs_to_searchrar�Zstopped_commonZ
total_stoppedrrrrysZ	
���
����
�zGraph._make_unique_searchersc	Cs�t|���}t�}|D]h}t|���}|�|�|��|�|�|��|D]}||urXqJ|�|�|��qJ|�|�|�|�q||fS)zStep all the searchers)r(rfr*rer�)	rr�r�r�newly_seen_common�newly_seen_uniquerarsZalt_searcherrrr�!_step_unique_and_common_searchersDs
z'Graph._step_unique_and_common_searchersc
Cs�|��}|D]}|�|j�q|�|j�|r|t��}|��}|�|�dtjvr|t��|}	t	�
d|	t|�t|j�|j�|S)z�Find nodes that are common to all unique_tip_searchers.

        If it is time, step the all_unique_searcher, and add its nodes to the
        result.
        r`zKall_unique_searcher step() took %.3fsfor %d nodes (%d total), iteration: %s)
�copy�intersection_updaterQr�perf_counterrfr*rr{rr|r}�_iterations)
rr�r�r�Zstep_all_unique�common_to_all_unique_nodesraZtstart�nodesZtdeltarrr� _find_nodes_common_to_all_uniqueVs"�

�z&Graph._find_nodes_common_to_all_uniquec
Cs�i}|D]b}|�|�}t|j�}|sHdtjvrjt�d|j|jt	|��q||vr\|g||<q||�
|�qg}t|�D]|}t	|�dkr�|�
|d�qx|d}	|dd�D]}|	j�
|j�q�dtjvr�t�dt	|�t	|	j�t	|	j��|�
|	�qx|S)aWCombine searchers that are searching the same tips.

        When two searchers are searching the same tips, we can stop one of the
        searchers. We also know that the maximal set of common ancestors is the
        intersection of the two original searchers.

        :return: A list of searchers that are searching unique nodes.
        r`z@Unique searcher %s was stopped. (%s iterations) %d nodes stoppedrrNzQCombining %d searchers into a single searcher searching %d nodes with %d ancestry)rd�	frozensetr�rr{rr|r�r�r}rkr
rQr�)
rr�r�Zunique_search_tipsra�stopped�will_search_set�next_unique_searchersrUZ
next_searcherrrr�_collapse_unique_searchersrs:


�
�z Graph._collapse_unique_searchersc
Cs�d}|jr�|�|||�\}}|�||||dk�}|dt}|rR|�|j�|��|rz|�|�|��|�	|�|�|�|�
||�}	t|�t|	�kr�dtj
vr�t�dt|�t|	�|j�|	}qdS)z�Steps 5-8 of find_unique_ancestors.

        This function returns when common_searcher has stopped searching for
        more nodes.
        rrr`z4Collapsed %d unique searchers => %d at %s iterationsN)r�r�r��STEP_UNIQUE_SEARCHER_EVERYrdrQrcr*rer�r�r}rr{rr|r�)
rrr�r�r�Zstep_all_unique_counterr�r�r�r�rrrrz�sJ	����
���


�
�zGraph._refine_unique_nodescCs,i}|�|�D]\}}|dur|||<q|S)z�Get a map of key:parent_list for revisions.

        This implementation delegates to get_parents, for old parent_providers
        that do not supply get_parent_map.
        N)rI)rrMrB�revrmrrrr�s

zGraph.get_parent_mapcCs
t||�Sr
)�_BreadthFirstSearcher)rrMrrrr[�sz"Graph._make_breadth_first_searchercsTd|vrt�d���t�}�fdd�|D�}t�}t�}|D]}|��}|r<|�|�q<t�}|D]D}	|	|vrz|�|	�qb|D]}|	|jvr~qbq~|�|	�|�|	�qb|r�|D]}|�|�|��q�|D]}|�|�q�|�|�t�}
|D] }t	|j
�}||
vr�|
�|�q�t|
�dkr2|
��}|�
|�}
|
�rJtd||
f���qJq2|||fS)aWFind common ancestors with at least one uncommon descendant.

        Border ancestors are identified using a breadth-first
        search starting at the bottom of the graph.  Searches are stopped
        whenever a node or one of its descendants is determined to be common.

        This will scale with the number of uncommon ancestors.

        As well as the border ancestors, a set of seen common ancestors and a
        list of sets of seen ancestors for each input revision is returned.
        This allows calculation of graph difference from the results of this
        operation.
        Ncsg|]}��|g��qSr�r[�r�rrrrr�s�z0Graph._find_border_ancestors.<locals>.<listcomp>rzmSomehow we ended up converging without actually marking them as in common.
Start_nodes: %s
uncommon_nodes: %s)rZInvalidRevisionIdr(rfr*rDrQrer�r�r�r}�poprRr4)rrMZcommon_ancestorsrUZborder_ancestorsZ
newly_seenraZ
new_ancestors�
new_commonr�unique_search_setsr�r�Zuncommon_nodesrrrrK�sT
�





�zGraph._find_border_ancestorsc
	s�t|�}tj|vr*|�tj�|s*tjhSt|�dkr:|St�fdd�|D��}t|�}t|�D]}t|�q`��g�}t|�dk�r�t�}zt|�Wnt	y�Yn0t
|�D]Z}z||}Wnty�Yq�Yn0z|�t|��Wq�t	�y||=Yq�Yq�0q�t�}	|D]�}
|
|v�rH|�|
�||
=|
|v�rH||
=|
|j
v�rv|
h}t|�D]}|�|��qbnRt|�D]}|
|j
v�r~�q�q~|	�|
�t|�D]}|�|
g�}|�|��q��q|�|	�qx|S)aaReturn the heads from amongst keys.

        This is done by searching the ancestries of each key.  Any key that is
        reachable from another key is not returned; all the others are.

        This operation scales with the relative depth between any two keys. If
        any two keys are completely disconnected all ancestry of both sides
        will be retrieved.

        :param keys: An iterable of keys.
        :return: A set of the heads. Note that as a set there is no ordering
            information. Callers will need to filter their input to create
            order if they need it.
        �c3s|]}|��|g�fVqdSr
r�)r�crrrr>Js�zGraph.heads.<locals>.<genexpr>r)r(rro�remover}rr
rsr[�
StopIterationr\�KeyErrorr*rQrdrDrer�)
rrZcandidate_headsrUZactive_searchersraZ
common_walkerr��	candidater�ZancestorZancestor_set�seen_ancestorsrrrrL3sf
�








�zGraph.headsc
Cs�t|�dkrt|�St|�}|g}g}t�}|r�|r�|��}|�|�||vr�|�|�|�|�t|�dkr,|�|���q�q,|�|g��|d�}|s�q,t	|�D] }	|	|vr�|�|	�|�|	�q�q,|S)z�Find the order that each revision was merged into tip.

        This basically just walks backwards with a stack, and walks left-first
        until it finds a node to stop.
        rN)
r}r\r(r�rDrkr�rr@�reversed)
rZtip_revision_idZlca_revision_idsZlooking_for�stackr-rgrs�
parent_ids�	parent_idrrr�find_merge_order�s0	



zGraph.find_merge_ordercCs<|�||�}|�|�}d}|D]}||vr2|S|}qdS)aFind the first lefthand ancestor of tip_key that merged merged_key.

        We do this by first finding the descendants of merged_key, then
        walking through the lefthand ancestry of tip_key until we find a key
        that doesn't descend from merged_key.  Its child is the key that
        merged merged_key.

        :return: The first lefthand ancestor of tip_key to merge merged_key.
            merged_key if it is a lefthand ancestor of tip_key.
            None if no ancestor of tip_key merged merged_key.
        N)rb�iter_lefthand_ancestry)rZ
merged_keyZtip_keyrhZcandidate_iteratorZlast_candidater�rrr�find_lefthand_merger�s
zGraph.find_lefthand_mergerFcCsd||g}d}|d7}|j|�}t|�dkrB|��}|r>||fS|St|�dkrZt�||��|}qdS)a�Find a unique LCA.

        Find lowest common ancestors.  If there is no unique  common
        ancestor, find the lowest common ancestors of those ancestors.

        Iteration stops when a unique lowest common ancestor is found.
        The graph origin is necessarily a unique lowest common ancestor.

        Note that None is not an acceptable substitute for NULL_REVISION.
        in the input for this method.

        :param count_steps: If True, the return value will be a tuple of
            (unique_lca, steps) where steps is the number of times that
            find_lca was run.  If False, only unique_lca is returned.
        rrN)rOr}r�rZNoCommonAncestor)rrSrTZcount_stepsrMZstepsZlcarBrrr�find_unique_lca�s
zGraph.find_unique_lcac#s�t|�}t��|r���|�|�|�}t�}t|�D]&}|V|��fdd�|dD��q4|�|�}|D]}|dfVqj|}qdS)a�Iterate the ancestry of this revision.

        :param revision_ids: Nodes to start the search
        :return: Yield tuples mapping a revision_id to its parents for the
            ancestry of revision_id.
            Ghosts will be returned with None as their parents, and nodes
            with no parents will have NULL_REVISION as their only parent. (As
            defined by get_parent_map.)
            There will also be a node for (NULL_REVISION, ())
        c3s|]}|�vr|VqdSr
r�r�p�Z	processedrrr>rz&Graph.iter_ancestry.<locals>.<genexpr>rN)r(r*rr	rR)rZrevision_ids�pendingZnext_map�next_pending�itemrvZghostrr�r�
iter_ancestry�s


zGraph.iter_ancestryNc#sV|durd}|���fdd�}�|vr*dS|��}�Vt|�dkrHdS|d�qdS)Nrcs8z�j�|g�|WSty2t�����Yn0dSr
)rJrr�rZRevisionNotPresent)r;�Znext_keyrrrrI
sz1Graph.iter_lefthand_ancestry.<locals>.get_parentsr)r})rZ	start_keyZ	stop_keysrIrmrr�rr�szGraph.iter_lefthand_ancestrycCs$ddlm}|�|�|��}|��S)aIterate through the input revisions in topological order.

        This sorting only ensures that parents come before their children.
        An ancestor may sort after a descendant if the relationship is not
        visible in the supplied list of revisions.
        r)�tsort)Zbreezyr�Z
TopoSorterr�iter_topo_order)rrMr�Zsorterrrrr�szGraph.iter_topo_ordercCs|h|�||g�kS)z�Determine whether a revision is an ancestor of another.

        We answer this using heads() as heads() has the logic to perform the
        smallest number of parent lookups to determine the ancestral
        relationship between N revisions.
        )rL)rZcandidate_ancestorZcandidate_descendantrrr�is_ancestor's�zGraph.is_ancestorcCs(|dus|�||�o&|dup&|�||�S)z�Determine whether a revision is between two others.

        returns true if and only if:
        lower_bound_revid <= revid <= upper_bound_revid
        N)r�)rZrevidZlower_bound_revidZupper_bound_revidrrr�
is_between1s
�
�zGraph.is_betweencCs�t|�dkrtd��|}|d}|d}|j�|j�}|s>dSt|�}|�||�|��}t|�}g}	|D]J}
|
|jvr||}n|}|�|
g�}|s�|
g}|�|�}
|
��|	�	|
�qhd}|	D]$}
|dur�t
|
j�}q�|�|
j�}q�t�
d||�t
�}|D]}
|�|
���q�t
�}|	D]}
|�|
����qt
�}|D].}|	D]}
||
jv�r@�q8�q@|�|��q8|�r�|D]}
|�|
�|���qr|D]}
|
�|��q�|�|�}|�r�|D]}
|
�|��q�|�r||	D]}
|�|
�|���q�|D]}
|�|
�|���q�|	D]}
|
�|��q|D]}
|
�|��q|�|�g}t
�}|	D].}
t|
j�}||v�rH|�|�|�	|
��qH|}	|D]}
|
j�r�q�q�dSq�dS)abMake sure that unique nodes are genuinely unique.

        After _find_border_ancestors, all nodes marked "common" are indeed
        common. Some of the nodes considered unique are not, due to history
        shortcuts stopping the searches early.

        We know that we have searched enough when all common search tips are
        descended from all unique (uncommon) nodes because we know that a node
        cannot be an ancestor of its own ancestor.

        :param common: A set of common nodes
        :param searchers: The searchers returned from _find_border_ancestors
        :return: None
        r�z/Algorithm not yet implemented for > 2 searchersrrNz3Started %d unique searchers for %d unique revisions)r}�NotImplementedErrorrQ�symmetric_differencer�rrer[rfrkr(rcrr|r*rDr�rdr�r�)rrNrUZcommon_searchersZ
left_searcherZright_searcher�uniqueZtotal_uniqueZ
simple_uniqueZunique_searchersrrZparent_searcherr�rar�r�r�Znew_common_uniquerZstop_searching_commonr�r�r�rrrrP<s���

��
����



zGraph._search_for_extra_commoncCsH|��}t|�D]2\}}|dur"q|D]}||vr&|�|�qq&q|S)aMremove revisions which are children of other ones in the set

        This doesn't do any graph searching, it just checks the immediate
        parent_map to find if there are any children which can be removed.

        :param revisions: A set of revision_ids
        :return: A set of revision_ids with the children removed
        N)r�r	�discard)rrMrAZsimple_ancestorsrr�r�rrrr��s	
z Graph._remove_simple_descendants)F)N)"rr r!r"rrrOrXrbrZrYrtrwr�rxryr�r�r�rzrr[rKrLr�r�r�r�r�r�r�r�rPr�rrrrrH�sB(		57(=54IY/�
 

rHc@s eZdZdZdd�Zdd�ZdS)�
HeadsCachez)A cache of results for graph heads calls.cCs||_i|_dSr
�r`�_heads�rr`rrrr�szHeadsCache.__init__cCsNt|�}zt|j|�WStyH|j�|�}||j|<t|�YS0dS)a�Return the heads of keys.

        This matches the API of Graph.heads(), specifically the return value is
        a set which can be mutated, and ordering of the input is not preserved
        in the output.

        :see also: Graph.heads.
        :param keys: The keys to calculate heads for.
        :return: A set containing the heads, which may be mutated without
            affecting future lookups.
        N)r�r(r�r�r`rL�rrrLrrrrLs
zHeadsCache.headsN)rr r!r"rrLrrrrr��sr�c@s(eZdZdZdd�Zdd�Zdd�ZdS)	�FrozenHeadsCachez;Cache heads() calls, assuming the caller won't modify them.cCs||_i|_dSr
r�r�rrrrszFrozenHeadsCache.__init__cCsJt|�}z|j|WStyDt|j�|��}||j|<|YS0dS)a-Return the heads of keys.

        Similar to Graph.heads(). The main difference is that the return value
        is a frozen set which cannot be mutated.

        :see also: Graph.heads.
        :param keys: The keys to calculate heads for.
        :return: A frozenset containing the heads.
        N)r�r�r�r`rLr�rrrrLs

zFrozenHeadsCache.headscCst|�|jt|�<dS)zStore a known value.N)r�r�r�rrrr=/szFrozenHeadsCache.cacheN)rr r!r"rrLr=rrrrr�sr�c@steZdZdZdd�Zdd�Zdd�Zdd	�Zd
d�ZeZ	dd
�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�ZdS)r�z�Parallel search breadth-first the ancestry of revisions.

    This class implements the iterator protocol, but additionally
    1. provides a set of seen ancestors, and
    2. allows some ancestries to be unsearched, via stop_searching_any
    cCsRd|_t|�|_t�|_t|j�|_t�|_||_d|_t�|_t�|_	i|_
dS)Nr�next_with_ghosts)r�r(r�rQ�
_started_keys�
_stopped_keysrJ�
_returning�_current_present�_current_ghosts�_current_parents)rrMr.rrrr<s
z_BreadthFirstSearcher.__init__cCs8|jrd}nd}d|t|j�f}d|j|t|j�fS)NZ	searchingZstartingz%s=%rz1_BreadthFirstSearcher(iterations=%d, %s, seen=%r))r�r\r�rQ)r�prefix�searchrrrrHs�z_BreadthFirstSearcher.__repr__cCs`|jdkr6|�|j�\}}}}|j�|�|�|�}n|j}|j�|�}|j�|�}|j||fS)zvGet the current state of this searcher.

        :return: Tuple with started keys, excludes and included keys
        rs)	r��	_do_queryr�rQr+�unionr�rRr�)rr-rvrsrmZ
next_queryZexcludesZ
included_keysrrr�	get_stateQs
z_BreadthFirstSearcher.get_statecCs$z
t|�WStyYdS0dS)Nr)rsr�rrrrrfgs
z_BreadthFirstSearcher.stepcCsP|jdkr d|_|jd7_n|��t|j�dkr<t��|j�|j�|jS)aJReturn the next ancestors of this revision.

        Ancestors are returned in the order they are seen in a breadth-first
        traversal.  No ancestor will be returned more than once. Ancestors are
        returned before their parentage is queried, so ghosts and missing
        revisions (including the start revisions) are included in the result.
        This can save a round trip in LCA style calculation by allowing
        convergence to be detected without reading the data for the revision
        the convergence occurs on.

        :return: A set of revision_ids.
        rsrr)r�r��_advancer}r�r�rQr*rrrr�__next__ms
z_BreadthFirstSearcher.__next__cCs@|jdkrd|_|��t|j�dkr,t��|��|j|jfS)a�Return the next found ancestors, with ghosts split out.

        Ancestors are returned in the order they are seen in a breadth-first
        traversal.  No ancestor will be returned more than once. Ancestors are
        returned only after asking for their parents, which allows us to detect
        which revisions are ghosts and which are not.

        :return: A tuple with (present ancestors, ghost ancestors) sets.
        r�r)r�r�r}r�r�r�r�rrrrr��s

z&_BreadthFirstSearcher.next_with_ghostscCsJ|jd7_|�|j�\}}}}||_||_||_||_|j�|�dS)z�Advance the search.

        Updates self.seen, self._next_query, self._current_present,
        self._current_ghosts, self._current_parents and self._iterations.
        rN)r�r�r�r�r�r�r�r*)rr-rvrsrmrrrr��sz_BreadthFirstSearcher._advancec	s�t�}t�}|j���|�|j�|�}|�|�t|�D]2\}}|durLq:�fdd�|D�}|r:|�|�q:||}||||fS)aQuery for revisions.

        Adds revisions to the seen set.

        :param revisions: Revisions to query.
        :return: A tuple: (set(found_revisions), set(ghost_revisions),
           set(parents_of_found_revisions), dict(found_revisions:parents)).
        Ncsg|]}|�vr|�qSrrr��rQrrr�rz3_BreadthFirstSearcher._do_query.<locals>.<listcomp>)r(rQr*rJrr	)	rrMZfound_revisionsZparents_of_foundrA�rev_idrmZnew_found_parentsZghost_revisionsrr�rr��s	

z_BreadthFirstSearcher._do_querycCs|Sr
rrrrr�__iter__�sz_BreadthFirstSearcher.__iter__cCs�|j}t|��|�}t|�}|jdkr.|j}nd}|�|�|jj}|r�||�}g}t|�D]}	|�	|	�q\|�|��
|�}
|�|
�|
�|�|
}qD|S)aFind ancestors of these revisions that have already been seen.

        This function generally makes the assumption that querying for the
        parents of a node that has already been queried is reasonably cheap.
        (eg, not a round trip to a remote host).
        rsr)rQr(rcr�r�r+rJrr
�extendrRr*)rrMZall_seenr�r�Znot_searched_yetrrAZall_parentsr�r�rrrre�s,

��

z)_BreadthFirstSearcher.find_seen_ancestorsc
Cs6t|�}|jdkr.|j�|�}|j�|�|_n�|j�|�}|�|j�|��}|j�|�|j�|�i}|D]4}|j	|D]$}||vr�d||<||d7<qzqlt
|j	�D]6}|D],}z||d8<Wq�ty�Yq�0q�q�t�}t
|�D]\}	}
|
dkr�|�|	�q�|j�|�|j�|�|j�|�|S)a1
        Remove any of the specified revisions from the search list.

        None of the specified revisions are required to be present in the
        search list.

        It is okay to call stop_searching_any() for revisions which were seen
        in previous iterations. It is the callers responsibility to call
        find_seen_ancestors() to make sure that current search tips that are
        ancestors of those revisions are also stopped.  All explicitly stopped
        revisions will be excluded from the search result's get_keys(), though.
        rsrr)r�r�r�rcrRr�r�r�r+r�r
r�r(r	rDr�r*)rrMr�Zstopped_presentZstop_rev_referencesr�r�rmZstop_parentsr�Zrefsrrrrd�s<

�
z(_BreadthFirstSearcher.stop_searching_anycCs�t|�}|j�|�|�|j�}|jdkrD|j�|�|j�|�nV|�|�\}}}}|j�|�|j	�|�|j
�|�|j�|�|j�|�||fSdS)aWAdd revisions to the search.

        The parents of revisions will be returned from the next call to next()
        or next_with_ghosts(). If next_with_ghosts was the most recently used
        next* call then the return value is the result of looking up the
        ghost/not ghost status of revisions. (A tuple (present, ghosted)).
        rsN)r�r�r*rRrQr�r�r�r�r�r�r�)rrMZ
new_revisionsZrevsrvZqueryrmrrrr�%s
z%_BreadthFirstSearcher.start_searchingN)rr r!r"rrr�rfr�rsr�r�r�r�rerdr�rrrrr�4s	'3r�cCsJi}t|�D]8\}}|D]*}||vr0|f||<q|||f||<qq|S)zCGiven a map from child => parents, create a map of parent=>children)r	)rAr_rlrmr�rrr�invert_parent_map>sr�cCs�i}t|�D]0\}}|�|g�|D]}|�|g��|�q$qt�}t|�}|D]�}||}t|�dkrP||d}t|�dkr�qP||}	t|	�dkr�qP|�|	dd�}
t|
�dkr�qP|||	d<|	||d<||=||=|�|�qP|S)a!Collapse regions of the graph that are 'linear'.

    For example::

      A:[B], B:[C]

    can be collapsed by removing B and getting::

      A:[C]

    :param parent_map: A dictionary mapping children to their parents
    :return: Another dictionary with 'linear' chains collapsed
    rrN)r	rjrkr(rr}r@rD)rAZchildrenrlrmr�ZremovedrB�nodeZparent_childrenZ
node_childrenZ
child_parentsrrr�collapse_linear_regionsMs2'r�c@s8eZdZdZdd�Zdd�Zdd�Zdd	�Zd
d�ZdS)
�GraphThunkIdsToKeysz7Forwards calls about 'ids' to be about keys internally.cCs
||_dSr
)�_graphr�rrrr�szGraphThunkIdsToKeys.__init__cCsdd�|j��D�S)NcSsg|]
\}|�qSrrr�rrrr�rz1GraphThunkIdsToKeys.topo_sort.<locals>.<listcomp>)r��	topo_sortrrrrr��szGraphThunkIdsToKeys.topo_sortcCs(dd�|D�}|j�|�}dd�|D�S)zSee Graph.heads()cSsg|]
}|f�qSrr)r�irrrr�rz-GraphThunkIdsToKeys.heads.<locals>.<listcomp>cSsh|]}|d�qS)rr)r�hrrr�	<setcomp>�rz,GraphThunkIdsToKeys.heads.<locals>.<setcomp>)r�rL)rZidsZas_keysZ	head_keysrrrrL�szGraphThunkIdsToKeys.headscCs(|j�|f�}|D]}|jd|_q|S)Nr)r��
merge_sortr;)rZtip_revisionr�r�rrrr��szGraphThunkIdsToKeys.merge_sortcCs|j�|fdd�|D��dS)NcSsg|]
}|f�qSrrr�rrrr�rz0GraphThunkIdsToKeys.add_node.<locals>.<listcomp>)r��add_node)rrrmrrrr��szGraphThunkIdsToKeys.add_nodeN)	rr r!r"rr�rLr�r�rrrrr��sr�)rrrrrrr)�
KnownGraph) Z
__future__r�time�rrrrrZsixishr	r
r��objectrr#r/rErHr�r�r�r�r�r�Z	_countersZ_known_graph_pyxr��ImportError�eZfailed_to_load_extensionZ_known_graph_pyrrrr�<module>s>7[H