mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 00:45:18 +03:00
dag: add ToIdSet trait
Summary: The trait converts NameSet to IdSet. It'll be used by the revlog index. Reviewed By: sfilipco Differential Revision: D21795869 fbshipit-source-id: 55f7a238158442db9d8bdfe84e64438be504f618
This commit is contained in:
parent
45d6b00593
commit
234147239a
@ -31,7 +31,9 @@ use crate::ops::DagAddHeads;
|
|||||||
use crate::ops::DagAlgorithm;
|
use crate::ops::DagAlgorithm;
|
||||||
use crate::ops::DagPersistent;
|
use crate::ops::DagPersistent;
|
||||||
use crate::ops::IdConvert;
|
use crate::ops::IdConvert;
|
||||||
|
use crate::ops::IdMapEq;
|
||||||
use crate::ops::PrefixLookup;
|
use crate::ops::PrefixLookup;
|
||||||
|
use crate::ops::ToIdSet;
|
||||||
use crate::spanset::SpanSet;
|
use crate::spanset::SpanSet;
|
||||||
use anyhow::{anyhow, bail, ensure, Result};
|
use anyhow::{anyhow, bail, ensure, Result};
|
||||||
use indexedlog::multi;
|
use indexedlog::multi;
|
||||||
@ -356,7 +358,7 @@ impl<T: NameDagStorage> DagAlgorithm for T {
|
|||||||
|
|
||||||
/// Calculates all ancestors reachable from any name from the given set.
|
/// Calculates all ancestors reachable from any name from the given set.
|
||||||
fn ancestors(&self, set: NameSet) -> Result<NameSet> {
|
fn ancestors(&self, set: NameSet) -> Result<NameSet> {
|
||||||
let spans = self.dag().ancestors(self.to_span_set(&set)?)?;
|
let spans = self.dag().ancestors(self.to_id_set(&set)?)?;
|
||||||
Ok(NameSet::from_spans_idmap(spans, self.clone_map()))
|
Ok(NameSet::from_spans_idmap(spans, self.clone_map()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,7 +367,7 @@ impl<T: NameDagStorage> DagAlgorithm for T {
|
|||||||
/// Note: Parent order is not preserved. Use [`NameDag::parent_names`]
|
/// Note: Parent order is not preserved. Use [`NameDag::parent_names`]
|
||||||
/// to preserve order.
|
/// to preserve order.
|
||||||
fn parents(&self, set: NameSet) -> Result<NameSet> {
|
fn parents(&self, set: NameSet) -> Result<NameSet> {
|
||||||
let spans = self.dag().parents(self.to_span_set(&set)?)?;
|
let spans = self.dag().parents(self.to_id_set(&set)?)?;
|
||||||
let result = NameSet::from_spans_idmap(spans, self.clone_map());
|
let result = NameSet::from_spans_idmap(spans, self.clone_map());
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
{
|
{
|
||||||
@ -391,7 +393,7 @@ impl<T: NameDagStorage> DagAlgorithm for T {
|
|||||||
|
|
||||||
/// Calculates heads of the given set.
|
/// Calculates heads of the given set.
|
||||||
fn heads(&self, set: NameSet) -> Result<NameSet> {
|
fn heads(&self, set: NameSet) -> Result<NameSet> {
|
||||||
let spans = self.dag().heads(self.to_span_set(&set)?)?;
|
let spans = self.dag().heads(self.to_id_set(&set)?)?;
|
||||||
let result = NameSet::from_spans_idmap(spans, self.clone_map());
|
let result = NameSet::from_spans_idmap(spans, self.clone_map());
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
{
|
{
|
||||||
@ -402,13 +404,13 @@ impl<T: NameDagStorage> DagAlgorithm for T {
|
|||||||
|
|
||||||
/// Calculates children of the given set.
|
/// Calculates children of the given set.
|
||||||
fn children(&self, set: NameSet) -> Result<NameSet> {
|
fn children(&self, set: NameSet) -> Result<NameSet> {
|
||||||
let spans = self.dag().children(self.to_span_set(&set)?)?;
|
let spans = self.dag().children(self.to_id_set(&set)?)?;
|
||||||
Ok(NameSet::from_spans_idmap(spans, self.clone_map()))
|
Ok(NameSet::from_spans_idmap(spans, self.clone_map()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates roots of the given set.
|
/// Calculates roots of the given set.
|
||||||
fn roots(&self, set: NameSet) -> Result<NameSet> {
|
fn roots(&self, set: NameSet) -> Result<NameSet> {
|
||||||
let spans = self.dag().roots(self.to_span_set(&set)?)?;
|
let spans = self.dag().roots(self.to_id_set(&set)?)?;
|
||||||
let result = NameSet::from_spans_idmap(spans, self.clone_map());
|
let result = NameSet::from_spans_idmap(spans, self.clone_map());
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
{
|
{
|
||||||
@ -423,7 +425,7 @@ impl<T: NameDagStorage> DagAlgorithm for T {
|
|||||||
/// If there are multiple greatest common ancestors, pick one arbitrarily.
|
/// If there are multiple greatest common ancestors, pick one arbitrarily.
|
||||||
/// Use `gca_all` to get all of them.
|
/// Use `gca_all` to get all of them.
|
||||||
fn gca_one(&self, set: NameSet) -> Result<Option<VertexName>> {
|
fn gca_one(&self, set: NameSet) -> Result<Option<VertexName>> {
|
||||||
let result: Option<VertexName> = match self.dag().gca_one(self.to_span_set(&set)?)? {
|
let result: Option<VertexName> = match self.dag().gca_one(self.to_id_set(&set)?)? {
|
||||||
None => None,
|
None => None,
|
||||||
Some(id) => Some(self.map().vertex_name(id)?),
|
Some(id) => Some(self.map().vertex_name(id)?),
|
||||||
};
|
};
|
||||||
@ -437,7 +439,7 @@ impl<T: NameDagStorage> DagAlgorithm for T {
|
|||||||
/// Calculates all "greatest common ancestor"s of the given set.
|
/// Calculates all "greatest common ancestor"s of the given set.
|
||||||
/// `gca_one` is faster if an arbitrary answer is ok.
|
/// `gca_one` is faster if an arbitrary answer is ok.
|
||||||
fn gca_all(&self, set: NameSet) -> Result<NameSet> {
|
fn gca_all(&self, set: NameSet) -> Result<NameSet> {
|
||||||
let spans = self.dag().gca_all(self.to_span_set(&set)?)?;
|
let spans = self.dag().gca_all(self.to_id_set(&set)?)?;
|
||||||
let result = NameSet::from_spans_idmap(spans, self.clone_map());
|
let result = NameSet::from_spans_idmap(spans, self.clone_map());
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
{
|
{
|
||||||
@ -448,7 +450,7 @@ impl<T: NameDagStorage> DagAlgorithm for T {
|
|||||||
|
|
||||||
/// Calculates all common ancestors of the given set.
|
/// Calculates all common ancestors of the given set.
|
||||||
fn common_ancestors(&self, set: NameSet) -> Result<NameSet> {
|
fn common_ancestors(&self, set: NameSet) -> Result<NameSet> {
|
||||||
let spans = self.dag().common_ancestors(self.to_span_set(&set)?)?;
|
let spans = self.dag().common_ancestors(self.to_id_set(&set)?)?;
|
||||||
let result = NameSet::from_spans_idmap(spans, self.clone_map());
|
let result = NameSet::from_spans_idmap(spans, self.clone_map());
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
{
|
{
|
||||||
@ -481,7 +483,7 @@ impl<T: NameDagStorage> DagAlgorithm for T {
|
|||||||
/// an ancestor of X, but not the immediate ancestor, `heads` will include
|
/// an ancestor of X, but not the immediate ancestor, `heads` will include
|
||||||
/// Y while this function won't.
|
/// Y while this function won't.
|
||||||
fn heads_ancestors(&self, set: NameSet) -> Result<NameSet> {
|
fn heads_ancestors(&self, set: NameSet) -> Result<NameSet> {
|
||||||
let spans = self.dag().heads_ancestors(self.to_span_set(&set)?)?;
|
let spans = self.dag().heads_ancestors(self.to_id_set(&set)?)?;
|
||||||
let result = NameSet::from_spans_idmap(spans, self.clone_map());
|
let result = NameSet::from_spans_idmap(spans, self.clone_map());
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
{
|
{
|
||||||
@ -492,46 +494,19 @@ impl<T: NameDagStorage> DagAlgorithm for T {
|
|||||||
|
|
||||||
/// Calculates the "dag range" - vertexes reachable from both sides.
|
/// Calculates the "dag range" - vertexes reachable from both sides.
|
||||||
fn range(&self, roots: NameSet, heads: NameSet) -> Result<NameSet> {
|
fn range(&self, roots: NameSet, heads: NameSet) -> Result<NameSet> {
|
||||||
let roots = self.to_span_set(&roots)?;
|
let roots = self.to_id_set(&roots)?;
|
||||||
let heads = self.to_span_set(&heads)?;
|
let heads = self.to_id_set(&heads)?;
|
||||||
let spans = self.dag().range(roots, heads)?;
|
let spans = self.dag().range(roots, heads)?;
|
||||||
Ok(NameSet::from_spans_idmap(spans, self.clone_map()))
|
Ok(NameSet::from_spans_idmap(spans, self.clone_map()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the descendants of the given set.
|
/// Calculates the descendants of the given set.
|
||||||
fn descendants(&self, set: NameSet) -> Result<NameSet> {
|
fn descendants(&self, set: NameSet) -> Result<NameSet> {
|
||||||
let spans = self.dag().descendants(self.to_span_set(&set)?)?;
|
let spans = self.dag().descendants(self.to_id_set(&set)?)?;
|
||||||
Ok(NameSet::from_spans_idmap(spans, self.clone_map()))
|
Ok(NameSet::from_spans_idmap(spans, self.clone_map()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToSpanSet {
|
|
||||||
/// Converts [`NameSet`] to [`SpanSet`].
|
|
||||||
fn to_span_set(&self, set: &NameSet) -> Result<SpanSet>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: NameDagStorage> ToSpanSet for T {
|
|
||||||
/// Converts [`NameSet`] to [`SpanSet`].
|
|
||||||
fn to_span_set(&self, set: &NameSet) -> Result<SpanSet> {
|
|
||||||
// Fast path: extract SpanSet directly.
|
|
||||||
if let Some(set) = set.as_any().downcast_ref::<IdStaticSet>() {
|
|
||||||
if self.is_map_compatible(&set.map) {
|
|
||||||
return Ok(set.spans.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slow path: iterate through the set and convert it to a non-lazy
|
|
||||||
// SpanSet.
|
|
||||||
let mut spans = SpanSet::empty();
|
|
||||||
for name in set.iter()? {
|
|
||||||
let name = name?;
|
|
||||||
let id = self.map().vertex_id(name)?;
|
|
||||||
spans.push(id);
|
|
||||||
}
|
|
||||||
Ok(spans)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> PrefixLookup for T
|
impl<T> PrefixLookup for T
|
||||||
where
|
where
|
||||||
T: NameDagStorage,
|
T: NameDagStorage,
|
||||||
@ -693,7 +668,7 @@ fn is_ok_some<T>(value: Result<Option<T>>) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// IdMap + IdDag backend for DagAlgorithm.
|
/// IdMap + IdDag backend for DagAlgorithm.
|
||||||
pub trait NameDagStorage {
|
pub trait NameDagStorage: IdMapEq {
|
||||||
type IdDagStore: IdDagStore;
|
type IdDagStore: IdDagStore;
|
||||||
type IdMap: IdConvert;
|
type IdMap: IdConvert;
|
||||||
|
|
||||||
@ -705,9 +680,6 @@ pub trait NameDagStorage {
|
|||||||
|
|
||||||
/// (Cheaply) clone the map.
|
/// (Cheaply) clone the map.
|
||||||
fn clone_map(&self) -> Arc<dyn IdConvert + Send + Sync>;
|
fn clone_map(&self) -> Arc<dyn IdConvert + Send + Sync>;
|
||||||
|
|
||||||
/// (Cheaply) test if the map is compatible (same).
|
|
||||||
fn is_map_compatible(&self, other: &Arc<dyn IdConvert + Send + Sync>) -> bool;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NameDagStorage for NameDag {
|
impl NameDagStorage for NameDag {
|
||||||
@ -723,9 +695,6 @@ impl NameDagStorage for NameDag {
|
|||||||
fn clone_map(&self) -> Arc<dyn IdConvert + Send + Sync> {
|
fn clone_map(&self) -> Arc<dyn IdConvert + Send + Sync> {
|
||||||
self.snapshot_map.clone()
|
self.snapshot_map.clone()
|
||||||
}
|
}
|
||||||
fn is_map_compatible(&self, other: &Arc<dyn IdConvert + Send + Sync>) -> bool {
|
|
||||||
Arc::ptr_eq(other, &self.snapshot_map)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NameDagStorage for MemNameDag {
|
impl NameDagStorage for MemNameDag {
|
||||||
@ -741,6 +710,15 @@ impl NameDagStorage for MemNameDag {
|
|||||||
fn clone_map(&self) -> Arc<dyn IdConvert + Send + Sync> {
|
fn clone_map(&self) -> Arc<dyn IdConvert + Send + Sync> {
|
||||||
self.snapshot_map.clone()
|
self.snapshot_map.clone()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdMapEq for NameDag {
|
||||||
|
fn is_map_compatible(&self, other: &Arc<dyn IdConvert + Send + Sync>) -> bool {
|
||||||
|
Arc::ptr_eq(other, &self.snapshot_map)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdMapEq for MemNameDag {
|
||||||
fn is_map_compatible(&self, other: &Arc<dyn IdConvert + Send + Sync>) -> bool {
|
fn is_map_compatible(&self, other: &Arc<dyn IdConvert + Send + Sync>) -> bool {
|
||||||
Arc::ptr_eq(other, &self.snapshot_map)
|
Arc::ptr_eq(other, &self.snapshot_map)
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,13 @@ use crate::id::Group;
|
|||||||
use crate::id::Id;
|
use crate::id::Id;
|
||||||
use crate::id::VertexName;
|
use crate::id::VertexName;
|
||||||
use crate::namedag::MemNameDag;
|
use crate::namedag::MemNameDag;
|
||||||
|
use crate::nameset::id_lazy::IdLazySet;
|
||||||
|
use crate::nameset::id_static::IdStaticSet;
|
||||||
use crate::nameset::NameSet;
|
use crate::nameset::NameSet;
|
||||||
|
use crate::IdSet;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// DAG related read-only algorithms.
|
/// DAG related read-only algorithms.
|
||||||
pub trait DagAlgorithm {
|
pub trait DagAlgorithm {
|
||||||
@ -330,3 +334,43 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait ToIdSet {
|
||||||
|
/// Converts [`NameSet`] to [`SpanSet`].
|
||||||
|
fn to_id_set(&self, set: &NameSet) -> Result<IdSet>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IdMapEq {
|
||||||
|
/// (Cheaply) test if the map is compatible (same).
|
||||||
|
fn is_map_compatible(&self, other: &Arc<dyn IdConvert + Send + Sync>) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: IdConvert + IdMapEq> ToIdSet for T {
|
||||||
|
/// Converts [`NameSet`] to [`IdSet`].
|
||||||
|
fn to_id_set(&self, set: &NameSet) -> Result<IdSet> {
|
||||||
|
// Fast path: extract IdSet from IdStaticSet.
|
||||||
|
if let Some(set) = set.as_any().downcast_ref::<IdStaticSet>() {
|
||||||
|
if self.is_map_compatible(&set.map) {
|
||||||
|
return Ok(set.spans.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert IdLazySet to IdStaticSet. Bypass hash lookups.
|
||||||
|
if let Some(set) = set.as_any().downcast_ref::<IdLazySet>() {
|
||||||
|
if self.is_map_compatible(&set.map) {
|
||||||
|
let set: IdStaticSet = set.to_static()?;
|
||||||
|
return Ok(set.spans);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slow path: iterate through the set and convert it to a non-lazy
|
||||||
|
// IdSet. Does not bypass hash lookups.
|
||||||
|
let mut spans = IdSet::empty();
|
||||||
|
for name in set.iter()? {
|
||||||
|
let name = name?;
|
||||||
|
let id = self.vertex_id(name)?;
|
||||||
|
spans.push(id);
|
||||||
|
}
|
||||||
|
Ok(spans)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user